菜鸟读文档-Vant Weapp-11(点击弹出输入框实践-2)

931 阅读3分钟

正文

输入框

本期我们来到了点击弹出输入框结构的最后一部分, 输入框部分, 该部分的需求为:

  1. 出现在遮罩层的上方
  2. 位置贴合本机弹出键盘
  3. 出现时自动对焦

查看接口

首先我们来查看 field 组件开放的接口, 并着重分析几个较为特殊的接口

  • value: 当前输入的值

    因为用户使用小程序是在渲染层, 但对数据进行进一步处理需要在逻辑层. 因此通常会需要将用户在渲染层的输入通过事件传递到逻辑层

    但在此处我们可以通过双向绑定, model:value="{{ todoTitle }}", 来实现在渲染层的输入直接修改逻辑层, 从而简化上述逻辑

  • bind:focus: 输入框聚焦时触发

    该事件的回调参数中包含 event.detail.height, 即弹出键盘高度, 这将有助于我们实现自动对焦的同时实现输入框位置贴合本机弹出键盘

结合一些特定的细节, 最终 field 组件接口的使用情况为:

<van-field
  model:value="{{ todoTitle }}"
  focus="{{ true }}"
  placeholder="打算做什么呢?"
  is-link
  arrow-direction="up"
  left-icon="circle"
  confirm-hold
  adjust-position="{{ false }}"
  bind:focus="adjustPosition"
/>

具体需求实现

  1. 出现在遮罩层的上方

    实现出现在遮罩层内部的需求较为简单, overlay 组件开放了默认插槽, 可以将输入框直接嵌入 overlay 组件的内部

  2. 位置贴合本机弹出键盘

  3. 出现时自动对焦

    输入框位置贴合本机弹出键盘输入框出现时自动对焦这两大需求我认为可以利用之前提到的 bind:focus 事件一起实现

以下是实现输入框三点需求对应的代码. (由于 field 组件使用到的接口较多, 为了代码的可读性, 我将其定位和大小两部分的样式拆分到一个外层 view 中)

  • WXML

    <van-overlay
      show="{{ showOverlay }}"
      bind:click="onClickHide"
    >
      <view
        class="input-wrap"
        style="bottom: {{ keyboardHeight }}px !important;"
      >
        <van-field
          model:value="{{ todoTitle }}"
          focus="{{ true }}"
          placeholder="打算做什么呢?"
          is-link
          arrow-direction="up"
          left-icon="circle"
          confirm-hold
          adjust-position="{{ false }}"
          bind:focus="adjustPosition"
        />
      </view>
    </van-overlay>
    
  • WXSS

    .input-wrap {
      width: 100% !important;
      position: fixed !important;
    }
    
  • JavaScript

    adjustPosition: function (e) {
      this.setData({
        keyboardHeight: e.detail.height
      });
    },
    

问题

此时出现了一个问题: 当我们点击按钮出现遮罩层后, 本机键盘并不会弹出, 且输入框会位于页面的最底部, 被下方 tabbar 遮挡. 即键盘并没有弹出, 其高度也就并没有被获取到

解决办法

我们可以在聚焦触发事件中打上 log, 结果如下图

结合该事件被触发的时机我们可以得出: 即便是在 field 组件为 display: none 的状态下, 该聚焦事件也会在进入页面时被立即触发, 但键盘并不会弹出, 因此聚焦事件获取到的键盘高度为 0

对于该问题, 我的解决方案是, 将 field 组件的自动获取焦点接口 focus 的初始设置为 false, 然后在点击出现遮盖层事件: onClickShow 中将 focus 的值设置为 true

但是此处有一个小细节: 将 focus 接口从 falsetrue 的设置需要放置在一个计时器 setTimeout 中才能够实现我们想要的逻辑, 即获取到本机弹出键盘高度后, 将输入框的位置设置为紧贴弹出键盘上方

onClickShow: function () {
  this.setData({
    showOverlay: !this.data.showOverlay,
  }, () => {
    setTimeout(() => {
      this.setData({
        inputFocus: !this.data.inputFocus
      })
    }, 100);
  });
}

改进后效果:

预告

点击弹出输入框结构的优化

自此, 我们的点击弹出输入框结构已经初具雏形, 但其可用性距离我们的目标仍存在一定的距离. 在下一期文章中, 我们将在目前已有的基础上, 对该结构进行进一步的优化:)