前言
微信小程式中,要為使用者提供安全密碼,用于後續的操作。UI設計稿類似微信的安全密碼設定,需要兩次輸入,驗證密碼一緻。之前剛入坑的時候,就收藏了一些小程式相關的好案例,沒有前人鋪路,也不會有今天的這篇文章。在此特别鳴謝,NAMECZ的博文(https://blog.csdn.net/namecz/article/details/79892451),文章的思路很巧妙。
正文
項目中多次使用到該子產品,是以抽象為一個元件(password-box)來實作。通過對外暴露的屬性和方法,達到項目需求。以下附上元件源碼,給大家一個參考:
wxml:
<view class="password-box">
<view class='password-wrapper'>
<!-- 僞裝的input -->
<block wx:for="{{inputLength}}" wx:key="item">
<!-- 寬高可以由外部指定 -->
<view class="password-item" style="width: {{inputWidth}}; height: {{inputHeight}}" catchtap='_focusInput'>
<!-- 隐藏密碼時顯示的小圓點【自定義】 -->
<view wx:if="{{!showValue && currentValue.length>=index+1}}" class="hidden"></view>
<!-- 顯示密碼時顯示對應的值 -->
<view wx:if="{{showValue}}" class="show">{{currentValue.length>=index+1?currentValue[index]:''}}</view></view>
</block>
</view>
<!-- 隐藏的輸入框 -->
<input type="number" password="{{true}}" value="{{currentValue}}" class='hidden-input' maxlength="{{inputLength}}" focus="{{inputFocus}}" bindinput="_setCurrentValue"></input>
</view>
js:
Component({
properties: {
// 輸入框的數量
inputLength: {
type: Number,
value: 6
},
// 單個輸入框的寬度
inputWidth: {
type: String,
value: '80rpx'
},
inputHeight: {
type: String,
value: '74rpx'
},
// 是否顯示輸入的值,預設隐藏
showValue: {
type: Boolean,
value: false
}
},
data: {
// input是否擷取焦點
inputFocus: false,
// 初始input值為空
currentValue: ''
},
methods: {
// 設定目前的值
_setCurrentValue(e) {
// 在此處判斷滿6(inputLength)位,把值傳回給上級父元件或頁面
let currentValue = e.detail.value
// 改變時,派發一個事件,如果父元件或頁面中需要實時擷取改變後的值,可以監聽這個事件。
this.triggerEvent('change', e.detail.value)
this.setData({
currentValue
}) if (currentValue.length >= this.data.inputLength) {
this._complate() return
}
},
// 點選僞裝的input時,讓隐藏的input獲得焦點
_focusInput() {
this.setData({
inputFocus: true
})
},
_complate() {
this.triggerEvent('inputComplate', this.data.currentValue)
},
// 提供給外部調用的方法,顯示/隐藏密碼。接收一個參數,可以顯性修改展示的狀态。
toggleValue(state) {
this.setData({
showValue: state != undefined ? state: !this.data.showValue
})
},
// 清除input目前的值
clearCurrentValue() {
this.setData({
currentValue: ''
})
}
}
})
wxss:
.password-box .password-wrapper {
display: flex;
justify-content: center;
align-items: center;
}
.password-box .password-item {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.password-box .password-item::after {
display: block;
content: '';
position: absolute;
top: 0;
left: 0;
border: 1px solid #999;
box-sizing: border-box;
width: 200%;
height: 200%;
border-radius: 0rpx;
transform: scale(0.5);
transform-origin: left top;
}
.password-box .password-item + .password-item {
margin-left: -1rpx;
}
.password-box .password-wrapper .hidden {
width: 14rpx;
height: 14rpx;
border-radius: 50%;
background: #999;
}
.password-box .password-wrapper .show {
color: #087b46;
}
.password-box .hidden-input {
width: 0;
height: 0;
min-height: 0;
}
json:
{
"component": true
}
使用
上面是元件的定義,接下來看看如何在頁面(setPassword)中使用它。
wxml:
<view class="set-password">
<view class="tip">{{tipText}}</view>
<!-- 密碼框 -->
<view class="password-wrapper">
<!-- 使用自定義元件。綁定一個事件,接收元件傳遞的值 -->
<password-box id="passwordBox" bind:change="inputChange"></password-box>
</view>
<!-- 顯示/隐藏密碼 -->
<view class="toggle-tip" bindtap="toggleValue">
<text class="tip {{valueIsShow?'active':''}}">{{valueIsShow?'隐藏密碼':'顯示密碼'}}</text></view>
<!-- 下一步操作按鈕 -->
<view wx:if="{{firstValue==''}}" class="btn-next {{currentValue.length==6?'btn-next-active':''}}" bindtap="saveInputValue">下一步</view>
<view wx:if="{{firstValue!=''}}" class="btn-next {{currentValue.length==6?'btn-next-active':''}}" bindtap="checkPassword">驗證</view>
</view>
js:
Page({
onLoad() {
console.log('Page Load...')
},
onShow: function() {
this.passwordBox = this.selectComponent('#passwordBox')
},
data: {
tipText: '請輸入六位數字密碼',
// 用于頁面樣式的
valueIsShow: false,
// 記錄臨時的值,點選按鈕後再儲存到對應變量中
currentValue: '',
firstValue: '',
secondValue: ''
},
navigatorTo(e) {
let url = e.currentTarget.dataset.url wx.navigateTo({
url: url
})
},
// 調用元件中的方法
toggleValue() {
this.setData({
valueIsShow: !this.data.valueIsShow
}) this.passwordBox.toggleValue()
},
inputChange(e) {
let currentValue = e.detail this.setData({
currentValue
})
},
saveInputValue() {
let value = this.data.currentValue
if (value.length < 6) {
return
}
if (this.data.firstValue == '') {
// 調用元件中的方法,清除之前的值
this.passwordBox.clearCurrentValue() this.passwordBox.toggleValue(false)
// 重置頁面初始的資料,以及文案的修改
this.setData({
firstValue: value,
currentValue: '',
valueIsShow: false,
tipText: '請再次确認6位數數字密碼'
})
} else {
this.setData({
secondValue: value
})
}
},
checkPassword(){
this.saveInputValue()
console.log('驗證密碼...')
}
})
wxss:
.set-password {
min-height: 100%;
background: #f0f0f0;
padding-top: 164rpx;
box-sizing: border-box;
}
.set-password .tip {
text-align: center;
font-size: 30rpx;
color: #666;
}
.set-password .password-wrapper {
margin-top: 47rpx;
}
.set-password .toggle-tip {
margin-top: 18rpx;
text-align: center;
}
.set-password .toggle-tip .tip {
font-size: 22rpx;
line-height: 22rpx;
color: #999;
}
.set-password .toggle-tip .active {
color: #087b46;
}
.set-password .btn-next {
margin: 138rpx auto 0;
width: 334rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border-radius: 6rpx;
color: #fff;
background: #9e9e9e;
}
.set-password .btn-next-active {
background: #087b46;
}
json:
{
"usingComponents": {
"password-box": "/components/passwordBox/password-box"
}
}
效果圖
1.首次輸入密碼
2.顯示密碼:
3.首次輸入完成:
4.再次輸入密碼:
5.再次輸入完成:
總結
主要總結一下與原作者的不同之處。原文章最最最大的亮點就是用一個input值控制多個虛拟的input,這個思路很巧妙,我一開始拿到設計稿,沒有想過這種解決方案。參考了這篇文章才慢慢請清晰,根據自己的需求,設計了一個元件,并記錄下來,分享給有類似需求的小夥伴。
原文是使用input設定disabled+value+password控制值的顯示和隐藏,但是設計稿與原生的input有些不同。為了友善控制顯示與隐藏時的樣式,采用view模拟了input。根據showValue判斷目前顯示的是小圓點還是數值。元件擴充了一些對外屬性和方法,使用時也更友善,也可根據自己的需求自定義。
噓寒問暖 不如打筆巨款~