英文:
move by scrolling 3 elements with 1 event handler
问题
我试图通过相同事件一次将3个<div class="container">
中的3个滚动条移到一个类名来处理。这是我的方法:
首先,我从脚本中共享事件处理程序
function handleScroll(event: any) {
let position: number = event._vts
let scrollOptions = {
left: position,
top: 0,
behavior: undefined
}
if (event._vts) {
if (graficas.length !== 0) {
console.log('muevo el array')
console.log('asi tengo el array -> ' + graficas)
const el0 = document.getElementsByClassName('container').item(0)
el0?.scroll(scrollOptions)
const el1 = document.getElementsByClassName('container').item(1)
el1?.scroll(scrollOptions)
const el2 = document.getElementsByClassName('container').item(2)
el2?.scroll(scrollOptions)
} else {
console.log('lleno el array')
for (let index = 0; index < document.getElementsByClassName('container').length; index++) {
graficas.push(document.getElementsByClassName('container')[index])
document.getElementsByClassName('container')[index].scrollBy(event._vts, 0)
console.log(document.getElementsByClassName('container')[index])
}
graficas.shift()
console.log('asi queda el array -> ' + graficas)
}
}
}
然后,我分享要显示带有滚动条的图表的模板部分:
<h2>CPU</h2>
<div class="container" @scroll="handleScroll">
<div class="containerBody">
<Bar :data="cpu" :options="options" />
</div>
</div>
<h2>IO</h2>
<div class="container" @scroll="handleScroll">
<div class="containerBody">
<Bar :data="io" :options="options" />
</div>
</div>
<h2>SEC</h2>
<div class="container" @scroll="handleScroll">
<div class="containerBody">
<Bar :data="sec" :options="options" />
</div>
</div>
有没有办法实现这个目标的想法?
英文:
I'm trying to move the 3 scrollbar from 3 <div class="container">
by the class name with the same event at one time. This is my approach:
In first place I share the event handler from the script
function handleScroll(event: any) {
let position: number = event._vts
let scrollOptions = {
left: position,
top: 0,
behavior: undefined
}
if (event._vts) {
if (graficas.length !== 0) {
console.log('muevo el array')
console.log('asi tengo el array -> ' + graficas)
const el0 = document.getElementsByClassName('container').item(0)
el0?.scroll(scrollOptions)
const el1 = document.getElementsByClassName('container').item(1)
el1?.scroll(scrollOptions)
const el2 = document.getElementsByClassName('container').item(2)
el2?.scroll(scrollOptions)
} else {
console.log('lleno el array')
for (let index = 0; index < document.getElementsByClassName('container').length; index++) {
graficas.push(document.getElementsByClassName('container')[index])
document.getElementsByClassName('container')[index].scrollBy(event._vts, 0)
console.log(document.getElementsByClassName('container')[index])
}
graficas.shift()
console.log('asi queda el array -> ' + graficas)
}
}
}
then I share the portion of template that display the chart with the scrollbars I want to move:
<h2>CPU</h2>
<div class="container" @scroll="handleScroll">
<div class="containerBody">
<Bar :data="cpu" :options="options" />
</div>
</div>
<h2>IO</h2>
<div class="container" @scroll="handleScroll">
<div class="containerBody">
<Bar :data="io" :options="options" />
</div>
</div>
<h2>SEC</h2>
<div class="container" @scroll="handleScroll">
<div class="containerBody">
<Bar :data="sec" :options="options" />
</div>
</div>
Any idea how can I approach to achieve this?
答案1
得分: 1
Approach 1: 不是滚动事件,而是监听滚轮事件。
大多数用户通过手势或鼠标滚轮进行滚动。使用这种方法,您可以轻松避免无限循环(一个滚动触发另一个,反之亦然)。当用户通过拖动滚动手柄进行滚动时,这种方法不起作用。
Approach 2: 监听鼠标悬停以了解光标正下方的元素,并仅使用该元素的滚动事件来同步滚动。
英文:
Approach 1: Instead of scroll events, listen for wheel event.
Mostly users scroll by gestures or mouse wheel. With this you can easily avoid infinite loop (one scroll triggering other and vise-versa). This will not work when the user scrolls by dragging the scroll handle.
Approach 2: Listen for mouseover to know which element is directly under cursor and only use scroll event of that element to sync scrolls.
答案2
得分: 0
以下是您要翻译的代码部分:
let uuid = 0;
Vue.component('scroll-sync', {
name: 'ScrollSync',
template: document.querySelector("#scroll-sync-template").innerHTML,
data() {
return {
topNode: null
}
},
beforeCreate() {
this.uuid = uuid.toString();
uuid += 1;
},
mounted() {
let parent = this.$parent
while (parent) {
this.topNode = parent
parent = this.topNode.$parent
}
const vue = this;
this.topNode.$on('scroll-sync', function(data) {
if (data.emitter === vue.uuid) {
return
}
const {
scrollTop,
scrollHeight,
clientHeight,
barHeight
} = data
const scrollTopOffset = scrollHeight - clientHeight
vue.$el.onscroll = null
if (scrollTopOffset > barHeight) {
vue.$el.scrollTop = scrollTop;
}
window.requestAnimationFrame(() => {
vue.$el.onscroll = vue.handleScroll
})
})
this.$el.onscroll = this.handleScroll
},
methods: {
handleScroll: function(e) {
const vue = this
window.requestAnimationFrame(() => {
const {
scrollTop,
scrollHeight,
clientHeight,
offsetHeight
} = e.target
this.topNode.$emit('scroll-sync', {
scrollTop,
scrollHeight,
clientHeight,
barHeight: offsetHeight - clientHeight,
emitter: vue.uuid
})
})
}
}
});
Vue.config.productionTip = false;
new Vue({
el: '#app'
});
.scroll-sync-container {
height: 100%;
width: 100%;
position: relative;
overflow: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div style="display:flex;">
<scroll-sync vertical style="height:500px;width:100px;margin-right:50px;">
<div style="width:100px;height:1000px;background:linear-gradient(red, green, blue);"></div>
</scroll-sync>
<scroll-sync vertical style="height:500px;width:100px;">
<div style="width:100px;height:2000px;background:linear-gradient(red, green, blue);"></div>
</scroll-sync>
</div>
</div>
<div id="scroll-sync-template">
<div class="scroll-sync-container">
<slot></slot>
</div>
</div>
英文:
The following snippet is a modified/simplified version of the source code for Vue Scroll Sync. Depending on the complexity of your needs (and your ability to use third-party dependencies in your codebase), you may want to pull that library directly, rather than hard-coding the component.
A few callouts:
- Note the use of a
uuid
to identify the different regions whose scroll position should be synced. This prevents a given scroll event being "double-counted" when the other regions' scroll positions are updated. - In all cases, the
onScroll
handler is temporarily removed from the divs when the scroll position is being modified. Again, this prevents the "double-counting" behaviors that might impact smooth scrolling. - The divs are styled and colored for ease of demoing, but of course, you can copy your own markup and content into the
scroll-sync
component to achieve the same effect. Deep nesting of DOM elements should still work, because thetopNode
of the component is computed on mount, and events are emitted/captured on that node.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
let uuid = 0;
Vue.component('scroll-sync', {
name: 'ScrollSync',
template: document.querySelector("#scroll-sync-template").innerHTML,
data() {
return {
topNode: null
}
},
beforeCreate() {
this.uuid = uuid.toString();
uuid += 1;
},
mounted() {
let parent = this.$parent
while (parent) {
this.topNode = parent
parent = this.topNode.$parent
}
const vue = this;
this.topNode.$on('scroll-sync', function(data) {
if (data.emitter === vue.uuid) {
return
}
const {
scrollTop,
scrollHeight,
clientHeight,
barHeight
} = data
const scrollTopOffset = scrollHeight - clientHeight
vue.$el.onscroll = null
if (scrollTopOffset > barHeight) {
vue.$el.scrollTop = scrollTop;
}
window.requestAnimationFrame(() => {
vue.$el.onscroll = vue.handleScroll
})
})
this.$el.onscroll = this.handleScroll
},
methods: {
handleScroll: function(e) {
const vue = this
window.requestAnimationFrame(() => {
const {
scrollTop,
scrollHeight,
clientHeight,
offsetHeight
} = e.target
this.topNode.$emit('scroll-sync', {
scrollTop,
scrollHeight,
clientHeight,
barHeight: offsetHeight - clientHeight,
emitter: vue.uuid
})
})
}
}
});
Vue.config.productionTip = false;
new Vue({
el: '#app'
});
<!-- language: lang-css -->
.scroll-sync-container {
height: 100%;
width: 100%;
position: relative;
overflow: auto;
}
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div style="display:flex;">
<scroll-sync vertical style="height:500px;width:100px;margin-right:50px;">
<div style="width:100px;height:1000px;background:linear-gradient(red, green, blue);"></div>
</scroll-sync>
<scroll-sync vertical style="height:500px;width:100px;">
<div style="width:100px;height:2000px;background:linear-gradient(red, green, blue);"></div>
</scroll-sync>
</div>
</div>
<div id="scroll-sync-template">
<div class="scroll-sync-container">
<slot></slot>
</div>
</div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论