需求
实现一个能够输入6位密码框组件(如微信支付密码框类似)
思路一(不可行方案)
使用一个Input 配合 letter-spacing 属性使用。后实验下来,input 并不使用css中的 letter-spacing 属性。
思路二 (可行方案)
在页面中,隐藏一个input,然后控制 input 组件的 focus 属性从而实现6位密码框输入。
需要注意的是,在我写这个组件并验证时,(iphone xs max ios13.3) 微信版本为7.0.8,实测组件可以正常工作。当我微信升级为7.0.9时,input 手动设置 focus 并没有生效,同时,该 input 没有办法再次聚焦并弹出输入法。(很奇怪的是,我同事的手机也是iphone xs max ios13.3 微信 7.0.9 没有这个问题
组件布局拆分
组件wxml
<view class="pay-password-container">
<text class="pay-password-title">安全验证</text>
<text class="pay-password-tips">您使用了虚拟资产,为保障安全,请输入支付密码!</text>
<view style="position:relative">
<view class="pay-password-layout">
<view wx:for="{{passwordlayout}}" class="pay-password-item">
<view wx:if="{{index < passwordCode.length}}" class="dot" />
</view>
</view>
<!-- 这里采用了一个投机取巧的办法,使用两个Input 防止在某些机型上,input设置focus会导致input整个失效-->
<input value="{{passwordCode}}" password maxlength="6" type="number" class='input-container-2' bindinput="passwordInput" />
</view>
<input value="{{passwordCode}}" focus="{{focus}}" maxlength="6" type="number" class='input-container-2' bindinput="passwordInput" bindfocus="getFocus" bindblur="blur" />
<view class='forget-password' catchtap="clickForgetPassword">忘记密码?</view>
<view class="empty-layout" />
<view class="controll-layout">
<view class="cancel-button" catchtap="dismiss">
<text>取消</text>
</view>
<view class="divider" />
<view class="sure-button" catchtap="sure">
<text>确定</text>
</view>
</view>
</view>
组件wxss
.pay-password-container {
width: 650rpx;
height: 525rpx;
border-radius: 16rpx;
background: #fff;
display: flex;
display: -webkit-flex;
flex-direction: column;
align-items: center;
}
.pay-password-title {
font-size: 40rpx;
font-weight: bold;
color: #030303;
margin-top: 59rpx;
flex-shrink: 0;
}
.pay-password-tips {
font-size: 24rpx;
color: #333;
opacity: 0.5;
margin-top: 31rpx;
flex-shrink: 0;
}
.pay-password-layout {
display: flex;
display: -webkit-flex;
flex-direction: row;
margin-top: 40rpx;
flex-shrink: 0;
z-index: 105rpx;
}
.pay-password-item:first-child {
height: 90rpx;
width: 90rpx;
border-radius: 8rpx 0rpx 0rpx 8rpx;
border-top: 1px solid #bbb;
border-left: 1px solid #bbb;
border-bottom: 1px solid #bbb;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
display: flex;
display: -webkit-flex;
justify-content: center;
align-items: center;
}
.pay-password-item {
height: 90rpx;
width: 90rpx;
border-top: 1px solid #bbb;
border-left: 1px solid #bbb;
border-bottom: 1px solid #bbb;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
display: flex;
display: -webkit-flex;
justify-content: center;
align-items: center;
}
.pay-password-item:last-child {
height: 90rpx;
width: 90rpx;
border-radius: 0rpx 8rpx 8rpx 0rpx;
border-top: 1px solid #bbb;
border-left: 1px solid #bbb;
border-bottom: 1px solid #bbb;
border-right: 1px solid #bbb;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
display: flex;
display: -webkit-flex;
justify-content: center;
align-items: center;
}
.pay-password-item .dot {
height: 20rpx;
width: 20rpx;
background: #030303;
border-radius: 50%;
}
.input-container-2 {
position: absolute;
top: 40rpx;
height: 100rpx;
width: 1500rpx;
left: -500rpx;
}
.empty-layout {
flex-grow: 1;
}
.controll-layout {
flex-shrink: 0;
border-top: 1px solid #e9e9e9;
width: 100%;
height: 100rpx;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
display: flex;
display: -webkit-flex;
}
.controll-layout .cancel-button {
flex-grow: 1;
display: flex;
display: -webkit-flex;
justify-content: center;
align-items: center;
}
.cancel-button text {
color: #333;
opacity: 0.5;
font-size: 34rpx;
}
.controll-layout .divider {
background: #e9e9e9;
height: 100%;
width: 1px;
flex-shrink: 0;
}
.controll-layout .sure-button {
flex-grow: 1;
display: flex;
display: -webkit-flex;
justify-content: center;
align-items: center;
}
.sure-button text {
font-size: 34rpx;
color: #f8aa00;
font-weight: bold;
}
.forget-password {
font-size: 24rpx;
color: #333;
opacity: 0.5;
margin-top: 30rpx;
align-self: flex-end;
margin-right: 55rpx;
}
组件js
input1 带 focus 属性,手动设置 focus 让其弹出。
input2 不带 focus 属性,需要用户手动点击输入框(6格)后,输入。
这样就避免了对 输入框(6格)监听tap事件,并设置focus 来让 input 聚焦,让输入法弹起。就解决了部分手机上手动设置 focus 会导致 input 组件没有响应的问题。
Component({
data: {
passwordlayout: [1, 1, 1, 1, 1, 1],
passwordCode: "",
focus: false
},
methods: {
showModal: function () {
this.setData({
focus: true
})
},
closeModal: function () {
this._clearData();
},
passwordInput: function (e) {
this.setData({
passwordCode: e.detail.value
})
},
focusInput: function () {
this.setData({
focus: true
})
},
getFocus: function () {
this.setData({
focus: true
})
},
blur: function () {
this.setData({
focus: false
})
},
dismiss: function (e) {
this.closeModal();
},
sure: function (e) {
if (this.data.passwordCode.length < 6) {
UIManager.showToast('请输入支付密码');
return;
}
//todo 支付密码验证
},
clickForgetPassword: function (e) {
//todo 忘记密码
},
}
})