移动,通过滚动 3 个元素,使用 1 个事件处理程序。

huangapple go评论67阅读模式
英文:

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 &lt;div class=&quot;container&quot;&gt; 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(&#39;muevo el array&#39;)
      console.log(&#39;asi tengo el array -&gt; &#39; + graficas)
      const el0 = document.getElementsByClassName(&#39;container&#39;).item(0)
      el0?.scroll(scrollOptions)
      const el1 = document.getElementsByClassName(&#39;container&#39;).item(1)
      el1?.scroll(scrollOptions)
      const el2 = document.getElementsByClassName(&#39;container&#39;).item(2)
      el2?.scroll(scrollOptions)
    } else {
      console.log(&#39;lleno el array&#39;)
      for (let index = 0; index &lt; document.getElementsByClassName(&#39;container&#39;).length; index++) {
        graficas.push(document.getElementsByClassName(&#39;container&#39;)[index])
        document.getElementsByClassName(&#39;container&#39;)[index].scrollBy(event._vts, 0)
        console.log(document.getElementsByClassName(&#39;container&#39;)[index])
      }
      graficas.shift()
      console.log(&#39;asi queda el array -&gt; &#39; + graficas)
    }
  }
}  

then I share the portion of template that display the chart with the scrollbars I want to move:

  &lt;h2&gt;CPU&lt;/h2&gt;
    &lt;div class=&quot;container&quot; @scroll=&quot;handleScroll&quot;&gt;
      &lt;div class=&quot;containerBody&quot;&gt;
        &lt;Bar :data=&quot;cpu&quot; :options=&quot;options&quot; /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;h2&gt;IO&lt;/h2&gt;
    &lt;div class=&quot;container&quot; @scroll=&quot;handleScroll&quot;&gt;
      &lt;div class=&quot;containerBody&quot;&gt;
        &lt;Bar :data=&quot;io&quot; :options=&quot;options&quot; /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;h2&gt;SEC&lt;/h2&gt;
    &lt;div class=&quot;container&quot; @scroll=&quot;handleScroll&quot;&gt;
      &lt;div class=&quot;containerBody&quot;&gt;
        &lt;Bar :data=&quot;sec&quot; :options=&quot;options&quot; /&gt;
      &lt;/div&gt;
    &lt;/div&gt;

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 the topNode 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(&#39;scroll-sync&#39;, {
name: &#39;ScrollSync&#39;,
template: document.querySelector(&quot;#scroll-sync-template&quot;).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(&#39;scroll-sync&#39;, function(data) {
if (data.emitter === vue.uuid) {
return
}
const {
scrollTop,
scrollHeight,
clientHeight,
barHeight
} = data
const scrollTopOffset = scrollHeight - clientHeight
vue.$el.onscroll = null
if (scrollTopOffset &gt; barHeight) {
vue.$el.scrollTop = scrollTop;
}
window.requestAnimationFrame(() =&gt; {
vue.$el.onscroll = vue.handleScroll
})
})
this.$el.onscroll = this.handleScroll
},
methods: {
handleScroll: function(e) {
const vue = this
window.requestAnimationFrame(() =&gt; {
const {
scrollTop,
scrollHeight,
clientHeight,
offsetHeight
} = e.target
this.topNode.$emit(&#39;scroll-sync&#39;, {
scrollTop,
scrollHeight,
clientHeight,
barHeight: offsetHeight - clientHeight,
emitter: vue.uuid
})
})
}
}
});
Vue.config.productionTip = false;
new Vue({
el: &#39;#app&#39;
});

<!-- language: lang-css -->

.scroll-sync-container {
height: 100%;
width: 100%;
position: relative;
overflow: auto;
}

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js&quot;&gt;&lt;/script&gt;
&lt;div id=&quot;app&quot;&gt;
&lt;div style=&quot;display:flex;&quot;&gt;
&lt;scroll-sync vertical style=&quot;height:500px;width:100px;margin-right:50px;&quot;&gt;
&lt;div style=&quot;width:100px;height:1000px;background:linear-gradient(red, green, blue);&quot;&gt;&lt;/div&gt;
&lt;/scroll-sync&gt;
&lt;scroll-sync vertical style=&quot;height:500px;width:100px;&quot;&gt;
&lt;div style=&quot;width:100px;height:2000px;background:linear-gradient(red, green, blue);&quot;&gt;&lt;/div&gt;
&lt;/scroll-sync&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;scroll-sync-template&quot;&gt;
&lt;div class=&quot;scroll-sync-container&quot;&gt;
&lt;slot&gt;&lt;/slot&gt;
&lt;/div&gt;
&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年4月13日 23:42:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76007367.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定