![v2-9a94b0fc4e938b418f6065576ea90b71_1440w.jpg?source=172ae18b](http://img-01.proxy.5ce.com/view/image?&type=2&guid=cc8fa2f9-242e-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-9a94b0fc4e938b418f6065576ea90b71_1440w.jpg?source=172ae18b)
vue不能老实的 @scroll真的是一大心病,今天就来去了这颗心病
先看MDN上关于scroll事件冒泡的描述:element的scroll事件不冒泡, 但是document的defaultView的scroll事件冒泡,
意思大概是监听的目标元素(element)是一个div的话,scroll事件不会冒泡到上一级,而document.defaultView(在浏览器上就是window)会冒泡(这里window已经是最顶级了,冒泡并没有卵用)
举个例子:
文档结构例如:
html > body > wrapper > box
在上面四个连加window,一共五个都绑定 scroll事件,同时触发捕获和冒泡阶段,测试结果事件触发顺序为 :
![v2-d8592cc893e0cd076b6805c36198f3b7_b.jpg](http://img-02.proxy.5ce.com/view/image?&type=2&guid=cc8fa2f9-242e-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-d8592cc893e0cd076b6805c36198f3b7_b.jpg)
示例地址
可见:在box之后就不再冒泡了,wrapper的scroll并未执行。
ps: box 只有在overflow:scroll / auto且确定了高度时 才会被window捕获到。
所以解决scroll绑定失败的方法有三个:
- scroll直接绑定在window的捕获阶段
- 使用开发者工具 performance 录制滚动动作,event log 里查看scroll事件的目标元素,然后亲手给这个元素绑定scroll(别忘了它不会冒泡的),如果目标元素是 #document ,只能在 created 里 addEventListener
- 如果必须使用@scroll事件,检查以下:
- 是否确定了高度(写一行height:100vh,不要随意100%,因为不能保证上一级或者上上一级一定就高度确定),
- 是否为overflow:scroll / auto
- 然后 performance录制触发scroll检查是不是你想要的元素
关于第一种方法的代码示例
1.
关于自定义组件: 组件根组件监听事件
<my-component @scroll.native="handleScroll">
关于移动端的滚动:
1. 监听 @scroll.passive (.passive 使得滚动行为立即触发)
2. 监听 @touchmove
所以:问题不是 vue 不能使用@scroll,而是即使是普通的页面不满足scroll的要求也一样不能执行回调,人家只是默默不说话,看着你没头没脑自个滚的开心。。
关于获取滚动距离的问题:
获取滚动距离 document.body.scrollTop 在 chrome 存在兼容性问题,可用以下三个代替:
- window.pageYOffset
- window.scrollY
- document.documentElement.scrollTop
Appendix:
mdn中的scroll
segmentfault 提出相关解决方法