你真的完全掌握了 Input 组件的键盘控制么? ——百度智能小程序 Input 组件原理剖析与键盘行为说明

1,458 阅读5分钟

在百度智能小程序的很多开发场景中,我们都会使用到 Input 输入框组件。而在操作输入框的过程中,正确处理键盘的弹出和收起行为也是十分重要的一环。键盘行为不仅需要完美符合业务场景,同时也和用户体验息息相关。

那么,你真的完全掌握了 Input 组件的键盘控制么?

更多内容查看开发者社区

更多招聘信息

Input 组件的使用

在智能小程序的开发过程中,开发者通过使用 Input 组件的 focus 和 blur 属性来控制键盘,从而实现当用户点击 Input 框时,键盘弹起;当用户点击空白区时,键盘收起的效果。

属性名 类型 默认值 必填 说明
focus Boolean false 获取焦点,调起键盘。开发者工具暂不支持自动获取焦点
bindblur EventHandle 输入框失去焦点时触发,event.detail = {value: value}

那么智能小程序组件的开发同学在开发 Input 组件的时候,又做了什么呢?

让我们来深入了解一下 Input 组件的实现原理。

Input 组件底层对 focus/bindblur 的处理

由于百度智能小程序的 Input 组件是基于同层渲染来开发,我们首先需要了解什么是同层渲染技术。

而在讨论同层渲染前,我们又需要先了解一下什么是原生组件。

原生组件

原生组件是小程序当中的一类特殊的内置组件,这类组件有别于 WebView 渲染的内置组件,他们是交由原生客户端渲染的。

原生组件有哪些优点呢?

  • 原生组件带来了更加流畅的原生化体验和更加丰富的控件功能。

  • 提供 H5 组件无法实现的一些功能,例如 H5 Video 不支持视频格式优先、Canvas 不支持绘制本地图片、Input 无法调起客户端定制的身份证键盘等。

  • 使用原生控件减少了 H5 组件利用 JS 与 Objective-C(端)交互流程,降低了通信开销。

但原生组件也存在限制:

原生组件的层级是最高的。页面中的其他 H5 组件无论设置 z-index 为多少,都无法覆盖原生组件,后插入的原生组件可以覆盖之前的原生组件。造成的影响有:

  • 无法支持在原生控件上覆盖自定义 HTML 元素。

  • 所有的 H5 弹出元素都会被原生控件遮挡,如 Alert 、Toast 等。

如何才能享用到原生组件的优点,同时又可以避开这些限制呢?同层渲染技术应运而生。

同层渲染与原生组件的关系

同层渲染是指通过一定的技术手段把原生组件直接渲染到 WebView 层级上,此时原生组件此时已被直接挂载到 WebView 节点上,可以像使用非原生组件一样去使用同层渲染的原生组件。

focus处理

我们在上文已经理解了同层渲染的概念,Input 组件就是通过同层渲染技术实现的,但是在 IOS 和 Android 上的实现方式有一些差异。

  • Android 的 Input 组件是一个纯 H5 组件,由前端和内核统一处理。NA 端的能力实际上是通过API来与 NA端进行通信,之后由客户端去处理,例如:调起自定义键盘功能。

  • IOS 的 Input 组件全流程是一个 NA 组件,在未获取焦点时,NA 组件是 DOM 树中的一个节点,和其他前端组件节点的区别是该节点是 NA 组件。在获得焦点的时候,该 NA 组件的视图树关系发生了变化,不再继承于 DOM 树,而是客户端 Webview 组件的一个子节点;再次失去焦点的时候,会再次将这个 NA 组件放回 DOM 树当中。下图以 IOS 的处理为例:

张晓倩 > 你真的完全掌握了Input组件的键盘控制么? > fovus.001.jpeg

  1. 首先 Input 组件会接收到开发者传来的 focus 值并保存在 focus 变量中。
  2. 之后在用户点击时,将focus 变量置为 true。
  3. 其次调 Input insert 端能力,与端通信插入 input 标签,组件底层触发 bindFocus 方法,失去焦点后,触发 bindBlur 方法。
  4. 最后底层会将 focus 的值设为客户端返回值。在触发 blur 方法时,会销毁 Input 原生组件。

需要注意的是,在触发 bindConfirm 时,会触发两个事件:confirm 和 blur。IOS 端和 Android 端执行这两个事件的顺序有所差别,IOS 会先触发 confirm 再触发 blur; Android 端会先触发 blur 再触发 confirm。

Tips

这里提供一些使用 Input 组件的 tips,帮助你避开一些体验问题。

1. 避免快速切换 focus 的状态。

如下图的代码段,会导致键盘双次弹起,造成体验问题。

// badcase
data: {
    focus: true
}
searchFocus(e) {
    this.setData({
        focus: false
    }, () => {
        this.setData({
            focus: true
        });
    });
}

// goodcase
data: {
    focus: true
}
searchFocus(e) {
    this.setData({
        focus: true
    });
}

2. 不要滥用 blur 等变量。

客户端会自动响应键盘的基本操作,所以开发者无需在 bindBlur 事件中去手动维护 blur 的值。

// badcase
data: {
    blur: false
}
searchBlur(e) {
    // 没有与blur有关逻辑下,更改blur状态
    this.setData({
        blur: true
    });
}

最后,感谢各位开发者积极投身百度小程序的开发当中,在开发过程中有任何问题都可以在社区与官方或其他开发者进行互动,也可将您的意见发送邮件至smartprogramtech@baidu.com,期待您的参与!