工作总结(9) - 关于移动端底部评论框效果的实现

之前在工作总结(六)中就整理了自己实现的移动端底部评论框的方案。这个方案整体效果可以,但是还是有些细节不够好。最近项目中再次遇到同样的需求,重新做了分析,用另一种不那么复杂的方案又实现了一次。这里就来总结一下这次实现方案。

需求

这次的需求跟上次的一样,只是因为考虑到可能有多个地方复用,所以打算做成一个底部评论框组件。需求是底部有一个假的评论栏,点击之后会弹出真的评论栏,并附着在底部和软键盘。

这个需求之前实现的思路是切换评论栏的布局,然后短时间内监听距离视窗顶部的高度来调整。这个方案能实现效果,但是在软键盘升起的时候会出现抖动现象。所以这次改变思路,直接使用绝对定位布局处理。

之前其实也考虑过这个思路,但是因为只考虑了评论框做绝对定位,所以那种处理的方案需要一直计算位置。这次思路的实现,是把整个页面的布局做调整:body元素直接限定高度为视窗高度,内容分块也全部使用绝对定位,内容的滚动是在内容块内处理。这样,评论框是相对于body做绝对定位,位置一定在视窗的底部。

这次还是用vue来实现。

页面处理

页面有几个需要处理的地方。因为每个页面都是一个vue组件,所以只要组件最外层限定为视窗的高度,body的高度就跟视窗高度一致,同时设置为相对定位:

1
2
3
4
5
6
7
8
body {
min-height: 100vh;
}

.wrapper {
position: relative;
height: 100vh;
}

然后.wrapper内的所有子节点都要使用绝对定位。内容块如果高度超过视窗高度,一般可以使用overflow:auto来处理,不过在移动端的效果有个不太好的情况的滑动不流畅,这个问题可以使用下面的写法处理:

1
2
3
4
5
6
7
height: 100vh;
overflow: auto;
-webkit-overflow-scrolling : touch;

&::-webkit-scrollbar { /* WebKit的浏览器隐藏滚动条 */
display: none;
}

遮罩层的设计

一般评论框弹起是需要用户避免操作其他功能,所以这里在评论组件上增加一个全屏的遮罩层。而且增加一个点击隐藏的功能。这个功能必须要点击遮罩层才能触发,所以用vue开发就是使用`@click.self`来设计点击事件。

评论框的设计

因为这个页面的效果先是视窗底部有一个假的评论框,点击之后这个假的评论框会隐藏,真的评论框会弹出来,所以实际上是需要做两个,但是这个假的评论框并不影响这些评论框的设计,所以只要保证它的布局时绝对定位就可以了。

首先,这个评论框的布局一样是绝对定位,定位在组件最外层元素的底部,也即在视窗的底部,这样当软键盘弹起的时候,整个页面被顶起,评论框依然能固定在页面的底部,贴着软键盘的顶部,而且不需要做任何计算高度的处理。

这里需要注意的是,评论框的绝对定位必须使用bottom属性来定位,而不能用top属性,因为使用top属性的情况下,因为软键盘弹起,视窗高度被压缩,会导致评论框还是按top属性的设置隐藏到软键盘后面,而用bottom属性可以使评论框一直定位在视窗的底部,所以不会被隐藏。

还有一个会影响效果的,是需要设计评论框的高度。因为在iOS上,当H5的input标签获得聚焦,弹出软键盘时,iOS会先把页面所有fixed定位改成绝对定位,然后判断输入框的位置,根据判断滚动页面。一方面软键盘的弹出会导致视窗高度变小,这会影响使用vh布局的样式,另一方面是滚动页面也会让从fixed定位改绝对定位的容器上移,而且高度不确定。所以最后会导致本身输入框会上移,然后视窗缩小也是顶起,最后效果就会变成输入框偏移更多,显示不全或各种难堪的页面显示。因此可以先设定一个高度,然后在输入框获得聚焦时把高度改高一些,这样在经历视窗缩小跟滚动之后,评论框的显示效果也不会差。这里就不上代码了,思路已经整理了。

实际开发出来的效果还是可以的。这里说的效果是安卓跟iOS13版本之前。安卓效果最好,而且其实在输入框获得聚焦的时候也不需要调整评论框高度的。但因为自iOS13出来之后,这个方案实现的效果跟实际效果又有了新的偏差:软键盘弹起后,当输入框失焦时,软键盘虽然隐藏了,但是视窗竟然没有恢复,导致页面下方原来软键盘的部分空白。这个原因目前不明,当然我只在我们公司的app上测试出来,并没有在其他地方测试过,可能跟webview有关。