ios和安卓软键盘问题

前景介绍

最近在开发移动端项目,然后QA突然和我说能不能优化点东西,说输入框在最底下,但是手机点击输入框以后,键盘就会挡住输入框,看不到写的东西了,用户体验很不好。

我一顿翻找,发现还真有问题,而且只在ios真机上有问题,这让我突然想到前几天fixed的问题:移动端使用fixed以后,用户填写输入框时,在安卓机上会出现fixed的元素出现在了键盘上面,但是并不能触发自身的点击事件。

这两个问题是不是很像!!!

先来分析下原因吧~

产生原因

ios和安卓机不太一样的点在于,ios键盘弹出时,不会自动调整页面布局和滚动位置,即不会立即更新视图位置。

所以 问题1 ios端点击输入框以后,页面布局不会调整,页面并不会上移,键盘自然会挡住最底下的输入框;

同理, 问题2 安卓移动端浏览器在键盘弹出时会改变视口高度,导致 fixed 定位的基准发生变化,键盘弹出时,浏览器可能会重新计算布局,导致点击区域错位。

解决措施(问题1 ios 点击底部输入框键盘弹出以后会遮挡输入框)

js 复制代码
// 针对ios系统,键盘弹出会遮挡输入框问题
adjustInputPosition() {
    // 获取浏览器的用户代理字符串
    let u = navigator.userAgent;
    // 检测是否为iOS设备,使用正则表达式匹配iOS特有的用户代理字符串
    let isIos = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
    
    // 如果是ios系统,则进入下一步
    if (isIos) {
        // 定义处理获得焦点事件的函数
        // 定义具名函数以便后续移除
        const handleFocusIn = (e) => {
            // 检查获得焦点的元素是否是input或textarea
            if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
                // 使用setTimeout确保键盘已弹出
                setTimeout(() => {
                    // 获取触发事件的元素
                    const input = e.target;
                    // 获取元素相对于视口的位置和尺寸信息
                    const inputRect = input.getBoundingClientRect();
                    // 获取元素底部相对于视口顶部的距离
                    const inputBottom = inputRect.bottom;
                    // 计算键盘高度,取两个值中的较大者
                    const keyboardHeight = Math.max(
                        Math.abs(window.innerHeight - document.documentElement.clientHeight)// 通过视口高度差异估算键盘高度,但不知道为什么ios一般计算不准
                        , 302 // 保底值);
                    // 计算键盘弹出后可视区域的高度
                    const visibleArea = window.innerHeight - keyboardHeight;
                    // 如果输入框底部在可视区之外
                    if (inputBottom > visibleArea) {
                        // 计算需要滚动的距离,额外加50像素作为缓冲
                        const scrollAmount = inputBottom - visibleArea + 50;
                        // 执行滚动
                        window.scrollTo({
                            // 计算新的滚动位置
                            top: window.pageYOffset + scrollAmount,
                            // 平滑滚动
                            behavior: 'smooth'
                        });
                    }
                }, 100);
            }
        };
        // 定义处理失去焦点事件的函数
        const handleFocusOut = () => {
            setTimeout(() => {
                window.scrollTo({top: 0, behavior: 'smooth'});
            }, 100);
        };

        // 添加监听器
        // 监听获得焦点事件
        document.body.addEventListener('focusin', handleFocusIn);
        // 监听失去焦点事件
        document.body.addEventListener('focusout', handleFocusOut);
        // 返回一个清理函数
        return () => {
            // 移除获得焦点事件
            document.body.removeEventListener('focusin', handleFocusIn);
            // 移除失去焦点事件
            document.body.removeEventListener('focusout', handleFocusOut);
        };
    }
    // 若不是ios设备,返回一个空函数
    return () => {};
}

同时,需要在页面mounted和beforeDestroyed内增加和移除操作

js 复制代码
mounted(){
        this.removeListeners = this.adjustInputPosition()
},
beforeDestroyed() {
        this.removeListeners()
},

以上,就是ios键盘会遮挡van-field输入框问题的解决

解决措施(问题2 安卓端针对fixed元素的问题)

再梳理一下问题:安卓端查看页面时,fixed元素会被键盘顶起来,但是此时,无法触发该元素的点击事件。

比较暴力的解决办法,就是在软键盘弹起时,通过isShow直接让元素消失

html 复制代码
<div class="submit" v-if="isShow">
    <button>提交</button>
</div>

在元素渲染以后,就添加监听器,监听页面布局的变化,从而改变isShow的值

js 复制代码
data(){
    return {
        isShow: true, // 默认可展示
        height: document.body.clientHeight, //初始化赋值默认的视图高度
    }
},
mounted() {
    window.addEventListener("resize", () => {
        if(document.body.clientHeight < this.height){
            // Android 键盘弹出后操作
            this.isShow = false
        }else{
            // Android 键盘收起后操作
            this.isShow = true
        }
    })
}
相关推荐
寒水馨4 分钟前
macOS下载、安装 Tailwind CSS-v4.3.3(附安装包tailwindcss-macos-arm64)
前端·css·macos·tailwind css·utility-first·css 框架·实用优先
shawxlee19 分钟前
vue3+axios挑战最简洁实用的配置封装+接口调用:请求拦截器、响应拦截器、通用请求方法(单个请求/并发请求/下载文件)、统一接口管理
前端·经验分享·vue·接口·axios·api
yuhaiqiang1 小时前
上线一个人静态网站需要多少钱,难不难?
前端·后端·程序员
宸津-代码粉碎机1 小时前
Jar热部署进阶实战|修复原生方案OOM与类冲突问题,生产级无BUG优化方案
java·大数据·服务器·开发语言·前端·人工智能·python
To_OC9 小时前
写了三遍 Todo List,我终于搞懂了 React 父子组件到底怎么通信
前端·javascript·react.js
勇往直前plus10 小时前
Vue3(篇一) 核心概念——响应式模板语法与组件基础
前端·javascript·vue.js
咩咩啃树皮10 小时前
第43篇:Vue3计算属性(computed)完全精讲——缓存机制、依赖计算、业务最优解
前端·vue.js·缓存
徐小夕12 小时前
花了一周,3亿tokens,我开源了一款 Word 文档智能审查平台,文稿自动质检+可视化分析,告别低效人工审核
前端·算法·github
kyriewen13 小时前
别再乱用useEffect了——你写的10个里有8个不该存在
前端·javascript·react.js
Ivanqhz13 小时前
Rust &‘static str浅析
java·前端·javascript·rust