问题出现
上图便是模块中发布帖子的页面,看上去没有什么坑可以踩,写完页面在电脑端和我自己的安卓手机上也都没什么问题,最后拿来苹果的测试机,打开页面便出现了如下问题
从两张图中可以看出,和安卓手机不同,唤起软键盘时底部的操作栏没有和软键盘一起被顶上来,仍处于页面最底端,需要向下滑动页面才可以看到,这和设计的初衷完全相悖。
问题原因
fiexd定位在ios唤起软键盘时失效
ios中唤起软键盘后会根据相应情况发生如下情况:
- 当前内容高度小于屏幕高度时:上下滑动页面时候,发现之前fixed定位在顶部的元素会跟随页面滚动,变成了absolute定位的效果。
- 当前内容高度大于屏幕高度时:之前fixed定位的元素不在原先的位置,下滑往上翻页面后,才会发现该元素出现在视图中。
ios在唤起软键盘时并不压缩webview高度
安卓手机中唤起软键盘时页面会压缩webview的高度,窗口会执行resize事件,但ios并不会。
解决思路
由于ios不压缩webview视图,我定位的元素仍在webview的底部,但与安卓不同的是此时webview的底部并不是软键盘上方。
所以如果我们可以获取到软键盘的高度,将元素重新定位便可以解决这个bug。
解决过程
项目是用uniapp开发的。
我的思路是通过innerHeight
的变化来判断软键盘高度,但ios不压缩webview,所以这直接阻绝了我。就在我逐渐烦躁,几乎放弃,准备另寻思路的时候,偶然看见Element.scrollIntoView方法,执行此方法会滚动元素的父元素,直到该元素可视。
果断试一试,唤起软键盘时取消定位,ios效果如下:
可以看到 键盘弹出的时候,底部操作栏被推上来了,但问题也很明显,整个视图被上移了操作栏虽然出现在了软键盘上,但输入框却被挤到视图外,不过问题不大,我们的目的已经达到了,此时我们可以通过视图偏移量,来得到软键盘的高度。
通过Element.getBoundingClientRect方法,我们可以拿到视图的偏移量,该方法返回一个DOMRect
对象,该对象提供有关元素大小及其相对于视图位置的信息。
获取到偏移量后为操作栏重新添加定位,但要注意重新定位底部操作栏后,上方编辑区域的高度也需要重新设置,不然会出现下面的情况,定位元素遮盖输入框。
在聚焦事件里根据视图偏移量为输入框设置高度,失去焦点时再还原,就解决元素错乱的问题。
最后附上结果:
贴上代码
<template>
<view ref="posting" class="posting">
<scroll-view
:style="{'height': scrollHeight}"
class="scroll-view"
:scroll-y="true">
<view class="main">
<u-input :height="200" :maxlength="500" v-model="value" @focus="focusIpt" @blur="blurIpt" placeholder="写下您的见解" type="textarea" />
</view>
</scroll-view>
<view class="bottom" ref="bottom" :style="{'bottom': bottomVal + 'px', 'position': isFiexd ? 'absolute' : 'relative'}">
<view class="edit-row">
底部操作栏
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
bottomVal: 0,
scrollHeight: 'calc(100vh - 196rpx)',
isFiexd: true
};
},
onLoad(e) {
},
methods: {
blurIpt() {
this.bottomVal = 0
this.scrollHeight = 'calc(100vh - 196rpx)'
},
focusIpt() {
//获取系统信息
let info = uni.getSystemInfoSync()
if(info.platform === 'ios') {
this.isFiexd = false
setTimeout(() => {
this.$refs.bottom.$el.scrollIntoView()
let viewInfo = this.$refs.posting.$el.getBoundingClientRect()
//获取视图偏移量,重新定位操作栏
this.bottomVal = Math.abs(parseFloat(viewInfo.top))
//重置编辑区高度
this.scrollHeight = `calc(100vh - ${98 + this.bottomVal}px )`
//还原偏移量
scrollTo(0,0)
this.isFiexd = true
},500)
}
},
}
};
</script>