METADATA
title: 【91kanmm开发笔记】移动端事件穿透问题的解决&瀑布流布局的实现 date: 2018-05-13 23:30 tags: [前端,91kanmm开发笔记] categories: 技术
本文主要介绍了在豆瓣美女模块开发过程中遇到的一些布局方面的问题,比如移动端滚动事件穿透,瀑布流布局的实现等。
移动端滚动事件穿透
这个问题在开发移动端页面的时候几乎是必踩的坑了,主要有点击穿透和滚动穿透这两个坑。点击穿透在开发过程中没有遇到(也有可能是没有受到点击穿透的影响),就暂时不去深究它;滚动穿透是遇到并且对用户体验造成切实影响的。因此本节主要说明在91kanmm中是如何解决滚动穿透的问题的。
在豆瓣美女模块中对于一条条的图片Card的交互设定是点击
Card
组件中的图片跳出弹窗显示该用户的更多图片和内容描述。之所以不做页面跳转是考虑到详情中不会有大量不同类型信息或特别的交互,使用弹窗能更快速地让用户得到信息并继续之前的浏览动作。 移动端的弹窗是滚动穿透的重灾区,当在弹窗上触发滚动的时候会发现下面一层的页面也跟随着滚动了。解决办法在网上也有很多讨论,在 移动端滚动穿透问题 中也有比较准确的答案。在91kanmm中我使用的解决方案和实现是这样的:
- 对于高度为屏幕高度的元素,是不会出现滚动条也不会触发滚动事件的;那让一个元素无法滚动最粗暴的实现方式就是设置如下的样式了:
position: fixed; width: 100%; height: 100%;
- 在触发弹窗之后我们就希望下层元素不触发滚动事件。基于以上的想法,只需要在触发的弹窗的时候给下层元素(body)加上相应的class(当然也可以修改样式,不过出于性能考虑修改class可以更少地触发reflow),这样即使弹窗的滚动事件穿透了也不会引起下层元素的滚动。
- 实际操作中会发现当给元素加上
position: fixed;
的样式之后页面会滚动到顶部,即失去了之前的滚动位置。这种情况可以使用js解决,即在打开弹窗之前记录下当前滚动位置,并在弹窗打开或关闭、给body设置/去除相应的class之后再将body滚动到记录下的位置。这里获取页面滚动高度的方式使用的是pageYOffset
,因为应用主要针对移动端开发,不用考虑兼容(低版本)IE,而在MDN中有特别提到:
为了跨浏览器兼容,请使用 window.pageYOffset 代替 window.scrollY。
瀑布流布局的实现
考虑过两种实现瀑布流的方式:绝对定位及多栏布局
绝对定位的实现可以参见Pinterest,多栏布局的参见小红书。
最开始选择的是自己实现一套绝对定位的瀑布流,通过js计算每个card所处的列数和处于同一列的上方元素的高度来计算出X和Y方向的偏移量。自己实现的坑就是往往考虑得不周全,而且当有些图片没有在计算代码触发之前加载完的话会导致计算出来的位置错误。
之后看到有个实现绝对定位瀑布流的插件,叫Masonry,通过该插件可以傻瓜式地实现瀑布流,并且它定位各个元素的方式并不是用top、left等属性,而是使用transform中的translate属性进行位置的改变,这样在性能上还更好一点。*top、left的改变会触发重排(reflow),而translate只会触发重绘(repaint),不过我们现在使用的前提是每个改变位置的元素position属性都是absolute,所以即使是left、top也不会触发重排;然而translate3d还能触发硬件加速,所以某种意义上来说对于移动端使用translate进行位移操作是更好的选择。这个插件还使用了imagesloaded插件,通过它可以判断容器内的图片是否加载完,而且在排列元素的时候还带了一丢丢特效,简直就是实现瀑布流利器。
虽然说Masonry已经做得很棒了,但毕竟是大量依赖于js的计算。在PC上浏览自然是没多大问题,然而移动端的开发会特别考虑性能问题。因此决定采用多栏布局的方式实现瀑布流。相比于绝对定位的方式,多栏布局在计算量上少了很多,无非就是计算出当前页面的栏数,将请求到的数据转为相应的几组数据在页面中渲染即可。91kanmm这种图片浏览的网站对每条item的顺序没有特别的要求,因此选择这个方式是个非常棒的选择。