移动端onTouchMove事件 以及Fixed定位的坑

4,406 阅读3分钟

就为了一个小特效搞了一天时间!话不多说

需求是这样的:在页面上做一个浮动的小图标,可以拖拽移动它。

效果是这样的:

代码是这样的:


大家都知道,移动端拖拽事件主要就是利用touchmove。为了防止拖拽它的时候,禁止浏览器的上下滚动,我的方法是在onTouchStart中将html和body的样式设为 height: 100%; overflow: hidden,然后在onTouchEnd中将样式清空。最后在onTouchStart,onTouchMove中添加了e.preventDefault()方法来阻止浏览器默认行为。

但是!PC端调试的时候好好的,然后到手机访问的时候就失效!浏览器也跟着一起滚犊子!体验贼差!最神奇的是,同样都是苹果自带的Safari浏览器,我的手机不行,测试的手机就正常!

研究了好久都没解决,然后发现PC端虽然正常,但是报了个警告:


什么玩意?翻译一波



百度后发现:Chorme某个版本更新后,为了让页面滑动流畅的飞起来,在window、document 和 body 上注册的 touchstart 和 touchmove 事件处理函数,默认 passive为 true。浏览器会忽略默认事件的preventDefault(), 你要是强行阻止会弹出一个警告, 也就是上面那个黄黄的!

这时候又纳闷了,这个passive又是啥?

Passive Event Listeners是Chrome提出的一个新的浏览器特性:Web开发者通过一个新的属性passive来告诉浏览器,当前页面内注册的事件监听器内部是否会调用preventDefault函数来阻止事件的默认行为,以便浏览器根据这个信息更好地做出决策来优化页面性能。当属性passive的值为true的时候,代表该监听器内部不会调用preventDefault函数来阻止默认滑动行为,Chrome浏览器称这类型的监听器为被动(passive)监听器。目前Chrome主要利用该特性来优化页面的滑动性能,所以Passive Event Listeners特性当前仅支持mousewheel/touch相关事件。

这时我感觉找到了眉目,然后就换了一种方式!不在DOM上直接绑定方法了,而是在componentDidMount钩子里添加监听!


然后发现,成了~~啊哈哈哈

最后要提一嘴,对于那个警告网上很多帖子都说加上全局样式*{touch-action: none}就好了。我在这里告诫大家,可千万不能乱加,加了这个有些浏览器所有页面都不能滚动了!而且也只是为了清除那个警告,并没有达到想要的效果。有兴趣的可以去了解一下touch-action属性。


。。。   。。。


糟糕的一天还没结束,我又发现了个新问题……就是这个浮动的小图标是fixed定位的,但是怎么不随着浏览器滚动而固定在屏幕上呢??

最后发现body的跟标签,也就是id为root的div上有transform属性!(这项目不是我写的)

规范中规定:如果元素的transform值不为none,则该元素会生成包含块和层叠上下文

什么是包含块?包含块(Containing Block)是视觉格式化模型的一个重要概念,它与框模型类似,也可以理解为一个矩形,而这个矩形的作用是为它里面包含的元素提供一个参考,元素的尺寸和位置的计算往往是由该元素所在的包含块决定的。

说重点!包含块重新定位了坐标参考系!!所以transform会影响子元素的绝对定位(fixed定位也是绝对定位的一种)!

知道咋回事了,那就来看看前辈为什么加这个transform?代码是left: 50%; transform: translate(-50%);

就是为了大屏幕下的居中定位。。而大屏幕会重定向到PC端官网,所以删掉!!

搞定!下班!