better

您所在的位置:网站首页 vue滚动事件为什么没有触发 better

better

2023-11-15 12:42| 来源: 网络整理| 查看: 265

better-scroll是什么

BetterScroll 是一款重点解决移动端(已支持 PC)各种滚动场景需求的插件。它的核心是借鉴的 iscroll 的实现,它的 API 设计基本兼容 iscroll,在 iscroll 的基础上又扩展了一些 feature 以及做了一些性能优化。

vue中better-scroll的简单使用 ... ... ...

使用better-scroll,首先一定要有三层的html元素,最外层是wrapper,要有固定的高度,而且要设置 overflow: hidden样式。 为什么需要中间的一层content,而不直接用wrapper包含所有标签呢? 因为better-scroll默认处理第一个子元素的滚动,而忽略其他子元素,因此我们需要content这一层来包裹真正滚动的元素。 使用之前,我们要先通过npm install一下better-scroll,然后再import进来:

import Bscroll from 'better-scroll' export default { mounted () { this.scroll = new Bscroll(this.$refs.wrapper, { click: true }) } }

通过this.$ref取到wrapper这个dom进行初始化,构造函数的第二个是参数是配置项。由于我们使用better-scroll滚动元素默认是不可点击的,因此可以通过设置click为true派发点击事件。 另外,better-scroll也提供一个方法scrollToElement,通过这个方法,可以将页面滚动到指定的子元素:

this.scrollToElement(this.$ref.child) 踩坑总结 初始化Bscroll之后页面无法滚动

首先,我们要知道better-scroll的滚动原理,如下图,只有当content的高度大于wrapper的高度,页面才能够滚动。 但在项目开发过程中,我发现,我的content的高度确实大于wrapper的高度时,页面依然无法滚动,这是为什么?其实原因很有可能是new scroll的时机不对,导致初始化时,wrapper的高度大于content。而我们看到的content高度大于wrapper,其实是在bscroll初始化结束后的因为获取到数据或其他方式改变的。因此,我们初始化Bscroll的时机很重要。 在很多实际应用中,我们列表的数据往往是动态获取的。而由数据改变到触发页面重新渲染又是一个异步的过程,我们要在获取到数据,并且页面已经重新渲染过后,再进行Bscroll的初始化。

官方文档描述: Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。 因此,我们可以在数据变化后立即使用nextTick函数,在下一个事件循环中,即dom更新后,再new Bsroll。

created () { requestData().then((res) => { this.data = res.data this.$nextTick(() => { this.scroll = new Bscroll(this.$refs.wrapper) }) }) } scroll.refresh()

由于数据是可能不断变化的,我们不可能每次数据变更都初始化一个Bscroll,这时,我们可以使用better-scroll提供的另一个方法refresh(),触发重新计算wrapper和content的高度,比如在updated钩子函数或监听某个数据的函数中使用。

//父组件部分代码 ... ... export default { name: 'City', data () { return { cities: {} } } }, methods: { getCityInfo () { axios.get('/api/city.json').then(this.getCityInfoSucc) }, getCityInfoSucc (res) { res = res.data if (res.ret && res.data) { const data = res.data this.cities = data.cities this.hotCities = data.hotCities } }, }, created () { this.getCityInfo() } } //子组件部分代码 ... {{key}} {{innerItem.name}} export default { name: 'CityList', props: { cities: Object }, methods: { mounted () { this.scroll = new Bscroll(this.$refs.wrapper, { click: true }) }, updated () { this.scroll.refresh() } }

上面是我开发项目中的部分代码,其中,父组件在created后通过axios请求数据,以props的形式传值给子组件,子组件要根据这个值渲染列表,也就是说,子组件里用到了Bscroll,但数据和dom结构依赖于父组件传过来的值而动态更新。 在这里,我没法在数据获取成功的回调函数中使用nextTick,因此我想到一个办法,在updated钩子函数中,使用refresh函数,当父组件获取数据成功后,props中的值也会相应update,此时让scroll重新计算dom元素的高度,列表便能正常滚动了。 当然,如果担心数据频繁变化,导致refresh刷新频繁,影响性能的话,可以利用timer进行防抖操作。

//data里定义一个timer updated () { const refresh=this.debounce(500) refresh() }, methods: { debounce(delay){ let timer1 = null return () => { if (timer1) clearTimeout(timer1) timer1 = setTimeout(() => { this.scroll.refresh() }, delay) } } better-scroll和scrollBehavior

在项目中,我想让每次进入这个页面时,列表都回到顶端,因此我利用vue-router的scrollBehavior:

scrollBehavior (to, from, savedPosition) { if (savedPosition) { return savedPosition } else { return { x: 0, y: 0 } } }

然而这在better-scroll列表页中并没有没有生效,但是重新进入其他页面都能回到顶端,这又是为什么呢? 我们要搞清楚这两个scroll的原理。当使用vue-router时,scrollBehavior记录的是整个页面的滚动,也就是说,页面是由于内容太多,自动撑高的,这个高度不固定。而使用better-scroll(再次引用上面那张图),外层wrapper的高度是固定下来的,滚动的是wrapper内的元素,因此,整个页面其实是没有滚动的,这样就造成了列表里面的元素还停留在原来的位置,但页面其实已经回到顶端的现象。 那要怎么让better-scroll内滚动的元素回到最顶端呢? 可以利用scrollToElement(this.$refs.wrapper)方法,或者scrollTo(0, 0)方法。

以上是我自己在使用better-scroll时的一些体验与心得,如有不当,欢迎指出。

参考: 当 better-scroll 遇见 Vue



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3