天天看點

微信小程式:自定義驗證碼/密碼輸入框元件

前言 

微信小程式中,要為使用者提供安全密碼,用于後續的操作。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判斷目前顯示的是小圓點還是數值。元件擴充了一些對外屬性和方法,使用時也更友善,也可根據自己的需求自定義。

噓寒問暖 不如打筆巨款~

微信小程式:自定義驗證碼/密碼輸入框元件