微信小程序解决ios页面上推问题

相信大家写原生小程序都遇到过一个问题,当输入框聚焦键盘弹起时,页面会自动上推,使得输入框刚好位于键盘之上,在安卓中推动的只是内容,但在ios中,推动的是整个页面,导致导航栏被推出屏幕外,如下:

在这里插入图片描述
针对这个问题,目前的解决方案是将自动上推改成手动上推,让我们自己来控制页面内容的滚动。

一、方案一

1.取消自动上推

微信小程序中的input和textarea都有一个属性adjust-position,将其改为false
在这里插入图片描述

2.添加类名或者id

我们给每个输入框或者需要定位到键盘之上的元素添加唯一类名或者id,另外,我们还要给input或textarea添加自定义属性,值也为同一个类名或者id。
在这里插入图片描述
如上图,我期望键盘弹起能刚好将整个输入栏顶在键盘之上,所以我选择给这一栏加上唯一类名,里面的input自定义属性值为该输入栏的唯一类名,这样做事为了当我触发键盘事件时,能拿到当前输入栏的类名,获取该元素的坐标信息。

3、绑定键盘事件

input和textarea,微信小程序官方提供了键盘弹起的事件
在这里插入图片描述
这个方法里面的逻辑是本次的重点,主要是计算手动推动距离,先看代码:


 data:{
  isIos:wx.getSystemInfoSync().platform === 'ios',
 },

// 监听页面软键盘弹起手动推动页面
bindkeyboardheightchange(e) {
	// 只对ios 处理
	if(!this.data.isIos === 'ios'){
		return
	}

  // 键盘高度
  const height = e.detail.height;
  const className = e.target.dataset.class;
  if (height === 0) {
    this.scrollToInput(0);
    return;
  }
  try {
    this.createSelectorQuery()
      .select(`.${className}`)
      .boundingClientRect((res) => {
       // 可使用窗口高度
        const windowHeight = wx.getSystemInfoSync().windowHeight;
        // 除去键盘的剩余高度
        let restHeight = windowHeight - height;
        // 元素左下角坐标
        let bottom = res.bottom;
        // 只有当元素被软键盘覆盖的时候才上推页面
        if (bottom <= restHeight) return;
        // 现阶段需要滚动的大小
        let scrollTop = bottom - restHeight;
        this.scrollToInput(height, scrollTop);
      })
      .exec();
  } catch (error) {}
}

// 获取页面滚动条位置
getScrollOffset() {
  return new Promise((resolve) => {
    try {
      wx.createSelectorQuery()
        .selectViewport()
        .scrollOffset((res) => {
          resolve(res.scrollTop);
        })
        .exec();
    } catch (error) {
      resolve(0);
    }
  });
}

// 监听页面软键盘弹起手动推动页面
scrollToInput(keyboardHeight, scrollTop) {
  this.setData({
    keyboardHeight,
  });
  if (scrollTop) {
    try {
      this.getScrollOffset().then((lastScrollTop) => {
        wx.pageScrollTo({
          // 如果已经存在滚动,在此基础上继续滚
          scrollTop: lastScrollTop ? lastScrollTop + scrollTop : scrollTop,
          duration: 300,
        });
      });
    } catch (error) {}
  }
}

这里涉及到几个值,参见下图:
在这里插入图片描述

注意:这里的页面使用的是原生导航栏,若使用的是自定义导航栏,那么B/D/E/H都会再加上G区域,E/H在官方文档有说到,是元素基于显示区域的坐标位置。
1、键盘弹起后,获取到键盘的高度C,用显示区域B减去键盘区域C就是我们可使用的区域D 2、获取输入栏底部距离显示区域的坐标,如E/H
3、若输入栏底部坐标小于可使用区域D,如H,则说明当键盘弹起时,该输入栏不会被键盘遮挡,不需要推动
4、反之,若大于D,如E,则说明键盘弹起时,输入栏会被键盘遮挡,这个时候就需要页面上推至输入栏完全展示出来
5、针对4,将E减去D,得到一个差值F,这就是当前元素距离完全展示还需要滚动的距离
6、页面实际滚动距离应该为F加上页面之前已经有的滚动距离,所以在滚动之前,需要再获取一次当前页面的滚动距离
7、这里可能会存在一个问题,页面的高度不够,无法滚动这么长的距离,因此,当键盘弹起时,这里需要给页面增加高度,这里直接是增加的键盘高度

重点:包含Input的view 加入class=“form-input-1" 或者直接给input加入 input标签则需加入adjust-position="{{isIos?false:true}}" bindkeyboardheightchange="bindkeyboardheightchange" data-class="form-input-1"

// 这里的view 指的是最外层的view 这里的180rpx 是我对ios 安全区的高度
<view style="height:calc(100% + {{keyboardHeight? (keyboardHeight + 'px'):'100%'}});padding-bottom:calc(180rpx +  {{keyboardHeight?  120 + 'px':0}}) "">

	<view></view>
	............
 	<input bindfocus="stationNameFocus" type="text" placeholder="请输入" placeholder-style="color:#C9C9C9" value="		{{params.formData.WIDGET_1689834780127}}" bindblur="changeParam" data-num="11" style="width: 100%;" bind:input="hxInput" 	adjust-position="{{isIos?false:true}}" bindkeyboardheightchange="changeKeyHeight" data-class="form-input-7" />

</view>

到这里,我们就已经实现了页面自动上推的功能了。另外,这里可以根据实际情况来做个判断,一般情况下
最终实现效果如下:,安卓我们可以直接使用原生的推动,即adjust-position为true,ios使用手动上推。
在这里插入图片描述

二、方案二

有些手机或者版本过低,监听不到键盘事件,可以使用聚焦事件和失焦事件代替,事件对象中也返回了键盘的高度。
在这里插入图片描述

// 监听页面软键盘弹起手动推动页面
bindfocus(e) {
  const height = e.detail.height;
  const className = e.target.dataset.class;
  if (height === 0) {
    this.scrollToInput(0);
    return;
  }
  try {
    this.createSelectorQuery()
      .select(`.${className}`)
      .boundingClientRect((res) => {
        ......
        this.scrollToInput(height, scrollTop);
      })
      .exec();
  } catch (error) {}
}

bindblur(e) {
    this.scrollToInput(0);
  }

对比两种方案
1.,方案一的推动是及时的,方案二有一点点延迟

三、疑难杂症

1、问题:在方案一中,如果textarea展示了原生完成,在点击完成时,或者失焦键盘落下事件未监听到
解决:配合bindblur或者bindconfirm,将keyboardHeight设为0

// 监听页面软键盘弹起手动推动页面
scrollToInput(keyboardHeight, scrollTop) {
  this.setData({
    keyboardHeight,
  });
  if (scrollTop) {
    ......
  }
}

  bindblur(e) {

    this.scrollToInput(0);

  }

  bindconfirm() {

    this.scrollToInput(0);

  }

2、问题:获取元素的坐标时,会默认保留全部小数,我们都知道,js在计算的时候会存在精度问题,有可能会滚动错误

解决:获取到元素坐标后,最好只保留两位小数,计算时注意处理精度

3、问题:当页面同时有input和textarea时,若只给textarea绑定键盘事件,input会触发该textarea的键盘事件
4、问题:bindkeyboardheightchange会触发多次,某些特殊情况中,每次的高度获取不一致,导致滚动多次

解决1:使用方案二

解决2:打印每次获取的高度,看哪一次是对的,使用节流或者防抖获取正确的数据

5、问题:当页面同时有input和textarea,并且textarea添加了原生的完成那栏,先点击textarea触发键盘事件,再点击input触发键盘事件,input获取到的键盘高度是有完成那栏的,导致页面上推距离不准

解决:不要使用原生的完成,自定义一个完成,键盘弹起时将他使用动画移动到键盘之上,这个时候记得在计算D区域的时候,要减去自定义完成栏的高度

如果非要用原生的完成,可以参考一下这个方法:使用方案一,bindkeyboardheightchange事件添加防抖,获取到真实的键盘高度,页面中添加两个变量,一个是input的高度,一个是textarea的高度,当输入框聚焦获取到键盘高度时,判断当前类型的高度是否有值,没有就赋值,有就用之前的值

const height = e.detail.height;
const type = e.target.dataset.type;
this.data[type] = this.data[type] || height;
### 使用 UniApp 将 H5 页面封装成 Android 应用 #### 准备工作 为了使用 UniApp 把现有的 H5 网页转换并打包成为适用于 Android 设备的应用程序,开发者需先安装 Node.js 及 NPM 工具环境。接着,在本地计算机上通过命令行工具全局安装 `@vue/cli` 和 `uni-app-cli` 插件[^1]。 ```bash npm install -g @vue/cli npm install -g @dcloudio/uni-cli ``` #### 创建项目结构 利用官方提供的模板快速创建一个新的 UniApp 项目: ```bash vue create my-project-name --preset dcloudio/uni-preset-vue cd my-project-name ``` 这一步骤会初始化一个基础的工程目录树,并自动配置好必要的依赖项和编译设置。 #### 配置平台特定参数 编辑项目的根目录下的 manifest.json 文件来定义应用程序的基础信息(如名称、图标路径等),同时指定目标平台为 android 并适当调整一些选项以适应移动操作系统的要求。 #### 编写业务逻辑代码 按照 Vue 单文件组件的方式实现各个页面的功能模块;对于那些已经在 Web 版本中存在的功能,则可以尽可能重用现有资源而不需要完全重构整个应用架构。 #### 测试与调试 借助于内置模拟器或连接真实设备来进行实时预览和测试,确保所有交互操作都能正常运作并且性能表现良好。如果遇到任何问题可以通过 Chrome DevTools 或者 WeChat Developer Tools 进行远程调试。 #### 构建 APK 文件 当确认无误之后就可以执行构建指令生成最终产物——APK 安装包了: ```bash # 执行此命令前请确保已正确设置了 keystore 相关的信息 npx hbuilderx build app-release.apk ``` 上述过程即完成了从 H5 到原生 Android 应用的一次完整迁移流程概述。 #### 处理软键盘高度变化事件 考虑到实际应用场景中的特殊需求,比如输入框聚焦时可能引起界面布局变动的情况,建议采用如下方式监听软键盘弹起落下状态的变化以便及时作出响应措施[^2]: ```javascript import { onKeyboardHeightChange } from '@dcloudio/uni-app'; onMounted(() => { const keyboardHandler = (res) => { console.log(`当前键盘高度为 ${res.height}px`); // 根据实际情况更新样式或其他属性... }; onKeyboardHeightChange(keyboardHandler); return () => offKeyboardHeightChange(keyboardHandler); }); ``` 这段代码展示了怎样注册回调函数用于捕捉到软键盘尺寸改变的通知消息,并据此动态调整视图元素的位置关系从而提供更好的视觉效果体验给用户。 #### 解决网络请求跨域难题 针对可能出现的数据交换障碍现象,特别是涉及到前后端分离部署模式下产生的 CORS 错误提示,推荐参照以下做法完成 request 请求方法的二次加工改造,使其能够满足多场景下的通信要求[^3]: ```javascript const httpConfig = require('./config/httpUrl'); export default function fetch(url, options={}) { if(process.env.NODE_ENV === 'development'){ url = '/api' + url; } Object.assign(options.headers || {}, {'Content-Type': 'application/json'}); return new Promise((resolve, reject)=>{ uni.request({ ...options, url: `${httpConfig.HTTP_REQUEST_URL}${url}`, success(res){ resolve(res.data); }, fail(err){ reject(err.errMsg); } }); }) } ``` 这里实现了根据不同运行时期切换 API 接口基址的能力,并且统一管理了默认头部携带的内容类型声明字段,进而提高了整体系统的灵活性与稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值