前言
在移动开发中, 会遇到这样的情况, 比如说有一个输入框在最底部的时候, 我们弹起输入框, 输入框不会在输入键盘上.
说明白简单点就是, 输入框被键盘挡住了. 而且在原生中, 输入框应该正好在输入键盘上, 但是 h5 没有这种体验, 那么我们需要自己实现.
再次用图说明情况.
情况一:
键盘挡住了, 输入框.
情况二:
红色代表有滚动条, 输入框, 没有正好卡在下面, 用户体验不好, 同样输入的时候不能滑动体验也不好.
开工
正确情况:
要做的其实就是两步:
第一步, 动态改变可滑动的高度, 就是在输入的时候可以通过滑动看到下面蓝色的部分:
第二部, 需要修改滚动距离:
也就是需要滚动多少, 输入框才刚好在键盘下. 那这个怎么移动呢? 我们该如何滚动才能完成呢?
计算滚动的距离, 其实就是计算输入框移动的距离.
这个问题就简单了, 分两种情况, 其实就一种哈.
假如输入框在上面:
就是我们滑动块的底部到顶部的距离 - 输入框底部到顶部的距离
加入输入框在键盘下面:
就不画了, 也是我们滑动块的底部到顶部的距离 - 输入框底部到顶部的距离, 只不过我们得到的是负数, 正好我们对应了我们滑动的方向.
好的, 现在我们要做的就是实现这两步.
如何修改键盘弹起的高度?
我们只要知道键盘的高度和屏幕的高度即可.
屏幕高度, 我们不需要去知道, 因为需要修改样式, 直接 100vh - 键盘高度即可.
键盘的高度如下:
Windows.addEventListener("keyboardWillShow", this.keyboardShowCallback);
在 keyboardShowCallback 有个参数是 e:
- public keyboardShowCallback = (e) => {
- e.keyboardHeight;// 取得键盘的高度
- })
在这里, 因为我的滑动块是全屏的, 那么我可以这样:
- public keyboardShowCallback = (e) => {
- //page 是我当前页面的滑动块, 100vh 就是屏幕高度
- page.setAttribute('style', 'height:calc(100vh -' + e.keyboardHeight + 'px) !important;z-index:150;');
- })
那么如何获取当前正在输入的输入框, 只要获取当前焦点的位置 document.activeElement:
var rect = document.activeElement.getBoundingClientRect();
通过 getBoundingClientRect 获取到输入框各个位置到屏幕的距离:
我们需要的是输入框的底部, 那么就是: rect.bottom;
那么我们计算滑动距离就是:
- scrolldiv// 表示可滑动的元素
- var scrolldivrect = scrolldiv.getBoundingClientRect();
- var addScrollTop = rect.bottom - scrolldivrect.bottom;
- scrolldiv.scrollTop = scrolldiv.scrollTop + addScrollTop;
接下来就是键盘收起来的时候恢复:
- // 监听键盘隐藏
- Windows.addEventListener("keyboardWillHide", this.keyboardHideCallback);
- // 恢复事件
- page.setAttribute('style', 'height: 100vh !important;z-index:120;');
在这里, 其实就已经实现效果了, 那么这时候会在一些平台上遇到一些问题.
遇到的问题
iOS 光标乱飘
造成原因, 是因为我们设置滑动了, 在低版本如 iPad mini3 上会出现光标和输入框不对应.
那么这个时候, 我继续输入, 或者我点一下其他地方光标又正常了.
这时候给了我线索, 我需要重绘这个 input 就行. 那么如何重新绘制呢? 我们无法操作啊. 但是我们知道如果改变某些样式是会触发重绘过程, 具体查看标准.
code 如下:
- var activeElement = document.activeElement; // 取得 focus 的 dom 元素
- setTimeout(function () {
- if (activeElement) {
- if (activeElement.nodeName == "TEXTAREA" || activeElement.nodeName == 'INPUT') { // 如果是 input 或 textarea
- if ((Object)(activeElement).style.textShadow === '') {
- (Object)(activeElement).style.textShadow = 'rgba(0,0,0,0) 0 0 0'; // 改变某个不可见样式, 触发 dom 重绘
- } else {
- (Object)(activeElement).style.textShadow = '';
- }
- }
- }
- }, 0);
收起键盘出现白屏, 在低版本上连续弹起键盘白屏无消失
这个问题得回到设计的根源上.
在我们收起键盘的时候, 我们就会让红色部分为 100%;
键盘收齐向下, 然后红色向下, 如果键盘收起速度, 大于红色向下增大的速度, 就会出现一点白, 然后消失.
怎么解决呢?
红色部分是我们滚动的部分, 蓝色是 content, 这时候让 content 设置为 100%vh, 这时候马上可视区域就会马上重绘.
在 keyboardHideCallback 中
- var num = Math.random() * 99;
- ionContent.setAttribute('style', 'height: 100vh !important;z-index:' + num + '');
当然, 然后要在 keyboardShowCallback 中设置为 100%, 如何不设置回去, 键盘弹起就会挡住输入框:
- var num = Math.random() * 99;
- ionContent.setAttribute('style', 'height: 100% !important;z-index:' + num + '');
总结
如果要兼容一些低版本, 需要主动触发去让一些区域刷新, 这些可以解决大部分白屏问题, 或者其他疑难杂症 (如光标漂移).
来源: https://www.cnblogs.com/aoximin/p/12192930.html