正文
在本期文章中, 我们将对上期已经初具雏形的点击弹出输入框结构进行进一步的优化
点击控制
二次弹出
如图可以看出, 当我们再次点击按钮弹出输入框时, 本机键盘并不会上拉, 而且输入框会固定在上一次的位置
这一问题主要是: 我们在第一次点击按钮时, 对控制本机键盘上拉的变量 inputFocus
和控制输入框位置的变量 keyboardHeight
进行设值后未对其初始化, 使其仍保留着之前的数值, 从而在第二次点击时本机键盘不会上拉, 输入框也会出现在先前的位置
显然, 要解决该问题, 我们要从变量 inputfocus
和变量 keyboardHeight
入手
-
inputfocuse
为了保证在点击按钮弹出输入框时, 变量
inputFocus
是从false
变为true
, 我们只需要在点击隐藏输入框时, 将inputFocus
重置为false
即可但我们比较点击显示和点击隐藏这两个函数可以发现, 变量
inputFocus
是随着控制整个结构显示隐藏的变量showOverlay
变化而变化的因此, 比起在两个函数中添加相同的修改
inputFocus
语句, 我们可以使用微信小程序在Component
构造器中提供的数据监听器 observers, 实现变量inputFocus
随变量showOverlay
变化而变化, 同时避免相同的逻辑编写两次observers: { showOverlay: function () { setTimeout(() => { this.setData({ inputFocus: !this.data.inputFocus }) }, 100); } },
由下图可以看出, 修改后, 此时第二次点击按钮也会弹出本机键盘
-
keyboardheight
但我们从图中也可以看出: 当第二次点击按钮时, 由于变量
keyboardheight
已经于第一次获取到了本机键盘上方的位置数值, 本次输入框的出现较第一次会快很多, 从而产生一种脱节感对于该问题, 目前我的解决办法是: 因为第一次点击弹出输入框时, 本机键盘上拉和输入框位置变化之间的配合效果较好, 所以我在点击隐藏输入框时对变量
keyboardheight
进行一次重置, 这样就保证每一次输入框出现的效果都会和第一次一样onClickHide: function () { this.setData({ showOverlay: !this.data.showOverlay, keyboardHeight: 0 }); },
改进后的效果如下图
下拉键盘隐藏输入框
目前, 我们隐藏整个结构是通过点击遮罩层实现. 但除此之外, 我们点击下拉本机键盘也表明我们需要隐藏整个结构, 而目前我们对于此功能尚未实现
对于此问题, 我们可以简化为: 当本机键盘收回时, 触发某一事件
我们首先查看 field 组件, 发现当键盘高度发生变化的时触发的事件 bind:keyboardheightchange
可以用于实现我们的需求
但该事件并不仅仅是在键盘下拉时触发, 键盘上拉时也会触发. 因此我们考虑用该事件替换之前用于在键盘上拉时设置输入框位置的事件 bind:focus
该事件需要实现的逻辑是
- 键盘上拉时设置输入框的位置
- 键盘下拉时隐藏整个结构
definePosition: function (e) {
if (this.data.keyboardHeight !== 0 && e.detail.height === 0) {
// 下拉键盘则隐藏输入框
this._hideInput();
} else {
// 弹出键盘则将设置输入框位置
this.setData({
keyboardHeight: e.detail.height
});
}
},
// 由于下拉键盘和点击遮罩层触发的逻辑相同, 我们将该部分独立
_hideInput: function () {
this.setData({
showOverlay: !this.data.showOverlay,
keyboardHeight: 0
});
},
自此, 我们就实现了下拉键盘隐藏整个结构的功能
点击输入
输入确认
输入框的功能是: 当用户完成内容输入后, 点击右侧按钮提交输入内容. 由于用户可能需要多次输入内容, 我们希望在点击提交按钮后, 整个输入结构仍能保留
但此时在我们的结构中, 若点击右侧因开启 is-link
产生的箭头按钮, 并不会触发点击尾部图标对应的事件 bind:click-icon
, 因此我们将其用 icon
接口替换
<van-field
model:value="{{ value }}"
focus="{{ inputFocus }}"
placeholder="打算做什么呢?"
left-icon="circle"
right-icon="envelop-o"
confirm-hold
adjust-position="{{ false }}"
bind:keyboardheightchange="definePosition"
bind:click-icon="submit"
/>
替换后却又出现一个问题, 右侧的提交按钮时灵时不灵. 但无论哪种情况, 进行一次点击后, 整个输入结构都会消失, 效果如下图所示
经过测试可以发现, 当我们点击右侧确认输入按钮, 无论是成功还是失败, 都会触发位于父元素 overlay
上的 bind:click="onClickHide"
事件, 即隐藏整个输入结构
可以看出, 在本次点击过程中, click
发生了事件冒泡, 对此, 我们可以在先前用于控制输入框位置的父元素 view
中放置一个 catch
事件来阻止事件冒泡
同时, 我们打开 field
组件开放的接口 hold-keyboard
, 即 focus
时, 点击页面不会收起键盘
-
WXML
<view class="input-wrap" style="bottom: {{ keyboardHeight }}px !important;" catch:tap="noop" > <van-field model:value="{{ value }}" focus="{{ inputFocus }}" placeholder="打算做什么呢?" left-icon="circle" right-icon="envelop-o" confirm-hold hold-keyboard adjust-position="{{ false }}" bind:keyboardheightchange="definePosition" bind:click-icon="submit" /> </view>
-
JavaScript
noop: function () {}
修改后的效果如下图所示, 可见目前已经基本实现了多次输入的功能
输入刷新
此时我们的输入仍存在一点小问题, 那就是我们在输入框中输入一些内容, 但不点击右侧图标确认, 而是隐藏结构, 当我们再次点击按钮弹出输入框时, 输入框中仍会保存上一次输入的内容, 如下图所示:
对此呢, 我们可以在每次弹出输入框时, 对输入框的内容进行一次刷新
onClickShow: function () {
this.setData({
showOverlay: !this.data.showOverlay,
value: ""
});
}
改进后的效果如下图所示:
样式
弹性
在我们的点击弹出输入框结构中, 还剩下输入框没有实现弹性, 对其我们需要实现的弹性大致有三部分, 分别是:
- 输入框的高度
- 左右图标的大小
- 输入文字的大小
从 field 组件文档中我们可以看出: 对于输入框, 文本和图标, 组件开放了三个外部样式接口, 且图标仅开放了右侧图标, 因此使用外部样式类来实现弹性显然会较为繁复
因此, 我们将采取使用 CSS
变量的方法来实现输入框的弹性
通过查看 field
组件的源码我们可以发现: 整个输入框都是放置于一个 cell
组件中, 而通过查看该 cell
组件的样式(如下图), 我们可以发现其中对于高度, 图标大小和文字大小都开放了 CSS
变量
我们可以在一个样式类中对这三个 CSS
变量进行设置, 然后将其直接绑定到 field
组件上即可实现整个输入框的弹性
-
CSS
.input { --cell-line-height: 4vh; --cell-font-size: 3vh; --field-icon-size: 4vh; }
-
WXML
<van-field class="input" model:value="{{ value }}" focus="{{ inputFocus }}" placeholder="打算做什么呢?" left-icon="circle" right-icon="envelop-o" confirm-hold hold-keyboard adjust-position="{{ false }}" bind:keyboardheightchange="definePosition" bind:click-icon="submit" />
-
iPhone 6/7/8
-
iPhone X
按钮变化
为了让用户在使用时能够明确理解右侧按钮是用于确认本次输入的, 我们可以在用户进行输入后让右侧的确认按钮图标发生一些变化
在此处我采用的方案是放置两个 icon
元素, 然后使用 wx:if
判断输入内容 value
是否为空来判断显示哪一个 icon
元素, 这样做的好处是可以将确认输入事件绑定在 value
不为空对应的 icon
上, 从而避免了当输入内容为空时点击右侧确认按钮触发无效事件
<van-field
class="input"
model:value="{{ value }}"
focus="{{ inputFocus }}"
placeholder="打算做什么呢?"
confirm-hold
hold-keyboard
adjust-position="{{ false }}"
bind:keyboardheightchange="definePosition"
bind:confirm="submit"
data-value="{{ value }}"
>
<van-icon
wx:if="{{ value === '' }}"
slot="right-icon"
name="fire-o"
/>
<van-icon
wx:else
slot="right-icon"
name="fire"
bind:click="submit"
data-value="{{ value }}"
/>
</van-field>
最终呈现出的效果如下图
预告
在本次文章中, 我们一步步地对我们的点击弹出输入框结构进行优化, 终于达到了一个勉强称得上是可用的层次
但作为整个页面的一小部分, 该结构对应的代码量却不小, 这显然不是一个好的实践
在下一期, 我们将利用之前学到的组件知识, 将整个结构处理为自定义组件, 给我们的代码减减负:)
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!