微信小程序组件(车牌号输入,支付键盘,滑块验证)

目录

车牌号输入组件

密码支付键盘组件

滑块验证组件


车牌号输入组件

如图

基于微信小程序组件封装,输出值为当前选择车牌号,可回显车牌号。

支持7位8位车牌号,因为我的项目没有此需求,所以没有测试,具体功能待验证。

话不多说,上代码。

json文件

{
  "component": true,
  "usingComponents": {
    "van-overlay": "@vant/weapp/overlay/index",
    "van-divider": "@vant/weapp/divider/index"
  }
}

wxs文件

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 组件显示
    keyboardShow: {
      type: Boolean,
      value: false
    },
    // 初始传入车牌号
    vehicleNo: {
      type: String,
      value: ''
    },
    // 车牌号位数
    plateLimit: {
      type: Number,
      value: 7
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    keyboardShow: false, // 整体键盘显示
    numberIsDis: 1, // 输入键盘不可点击 2可点击
    fieldBoardShow: true, // 省键盘
    provincesKeyList: '京津冀晋蒙辽吉黑沪苏浙皖闽赣鲁豫鄂湘粤桂琼渝川贵云藏陕甘青宁新',
    numberKeyList: '0123456789',
    englishKeyOneList: 'ABCDEFGHJKLMNPQRSTUV',
    englishKeyTwoList: 'WXYZ',
    currentFocus: 0,
    currIndex: 0,
    codeList: [],
    codeReset: []
  },

  /**
   * 组件的生命周期
   * ready方法要正确执行需要在父页面中写入当前组件时,wx:if 绑定组件显示属性
   * 组件隐藏之后要注销,否则ready方法只执行一次
   */
  ready: function() {
    let temp = []
    let reset = []
    let carLen = this.properties.vehicleNo ? this.properties.vehicleNo.length + 1 : 0
    if (carLen) {
      let arr = this.properties.vehicleNo.split('')
      arr.forEach(item => {
        temp.push({ value: item })
        reset.push({ value: '' })
      })
      // 解决车牌号异常数据导致的样式问题(车牌号位数不够)
      if (carLen < this.data.plateLimit) {
        let num = this.data.plateLimit - carLen
        for (let index = 0; index <= num; index++) {
          temp.push({ value: '' })
          reset.push({ value: '' })
        }
      }
    } else {
      // 初始化设置数据
      for (let index = 0; index < this.data.plateLimit; index++) {
        temp.push({ value: '' })
        reset.push({ value: '' })
      }
    }
    this.setData({
      codeList: temp,
      codeReset: reset,
      numberIsDis: carLen ? 2 : 1,
      fieldBoardShow: carLen ? false : true,
      currentFocus: carLen,
      currIndex: this.properties.vehicleNo ? this.properties.vehicleNo.length : 0
    })
  },

  /**
   * 组件的方法列表
   */
  methods: {
    // 省份键盘
    provinceKeyClick(e) {
      const { val } = e.currentTarget.dataset
      const { currentFocus, codeList } = this.data
      let temp = codeList
      temp[0].value = val
      this.setData({
        codeList: temp,
        fieldBoardShow: false,
        currIndex: 1,
        numberIsDis: 1,
        currentFocus: currentFocus + 1
      })
    },

    //数字键盘不可点击事件
    numberKeyDisabled(e) {
      // 获取组件
      // this.keyboard = this.selectComponent("#keyboard");
      return
    },

    // 数字键盘可点击
    numberKeyEnabled(e) {
      const { currIndex, codeList } = this.data
      if (currIndex > codeList.length - 1) return
      const { val } = e.currentTarget.dataset
      let temp = this.data.codeList
      temp[currIndex].value = val
      this.setData({
        codeList: temp,
        currIndex: currIndex + 1,
        currentFocus: currIndex + 1
      })
    },

    // 字母键盘点击
    englishKeyClick(e) {
      const { currIndex, codeList } = this.data
      if (currIndex > codeList.length - 1) return
      const { val } = e.currentTarget.dataset
      let temp = this.data.codeList
      temp[currIndex].value = val
      this.setData({
        codeList: temp,
        currentFocus: currIndex + 1,
        currIndex: currIndex + 1,
        numberIsDis: 2
      })
    },

    // 退格
    backspace: function(e) {
      const { currIndex } = this.data
      let temp = this.data.codeList
      if (!currIndex) return
      temp[currIndex - 1].value = ''
      this.setData({
        codeList: temp,
        currentFocus: currIndex - 1,
        currIndex: currIndex - 1,
        fieldBoardShow: currIndex === 1,
        numberIsDis: currIndex === 2 ? 1 : 2
      })
    },

    // 关闭
    closeKeyBoard: function(e) {
      const { codeReset } = this.data
      this.setData({
        keyboardShow: false,
        codeList: codeReset,
        currentFocus: 0,
        currIndex: 0,
        fieldBoardShow: true,
        numberIsDis: 1
      })
      this.triggerEvent('closeKeyBoard')
    },

    // 确定
    confirmKeyBoard: function(e) {
      const { currIndex, codeList } = this.data
      if (currIndex < codeList.length) return
      let plate = ''
      codeList.map(item => (plate += item.value))
      this.triggerEvent('keyboardConfirm', plate)
      this.closeKeyBoard()
    }
  }
})

wxml文件

<!--车牌号输入组件-->
<van-overlay show="{
   
   { keyboardShow }}" z-index="9990">
  <view class="keyBoard_content">
    <!-- header -->
    <view class="top-part flex">
      <view class="font-30 close" bindtap="closeKeyBoard">x</view>
      <view class="message color-333">输入车牌号</view>
      <view class="font-30 confirm {
   
   {currIndex === codeList.length ? 'confirm-active' : ''}}" bindtap="confirmKeyBoard">确定</view>
    </view>

    <!-- input -->
    <view class="license flex">
      <view wx:for="{
   
   {codeList}}" wx:key="index" class="edit-text {
   
   {currentFocus === index ? 'border-active' : ''}} {
   
   {index === 2 ? 'space-left' : ''}}">
        <view>{
   
   {item.value}}</view>
      </view>
    </view>
    
    <!-- 键盘 -->
    <view class="keyboard">
      <!-- 省份键盘 -->
      <block wx:if="{
   
   {fieldBoardShow}}">
        <view class="province-keyboard flex">
          <view
            class="td td-nor color-333"
            wx:for="{
   
   {provincesKeyList}}"
            wx:key="index"
            wx:for-index="idx"
            wx:for-item="itemName"
            catch:tap="provinceKeyClick"
            data-index="{
   
   {idx}}"
            data-val="{
   
   {itemName}}"
            hover-class="board-active"
            hover-start-time="0"
            hover-stay-time="80"
          >
            {
   
   {itemName}}
          </view>
        </view>
      </block>
      <!--数字键盘-->
      <block wx:if="{
   
   {!fieldBoardShow}}">
        <view class="number-keyboard flex between">
          <!-- 不可点击 -->
          <block wx:if="{
   
   {numberIsDis === 1}}">
            <view
              class="td td-num color-333 board-active"
              wx:for="{
   
   {numberKeyList}}"
              wx:key="idx"
              wx:for-index="idx"
              wx:for-item="itemName"
              catch:tap="numberKeyDisabled"
              data-val="{
   
   {itemName}}"
            >
              {
   
   {itemName}}
            </view>
          </block>
          <!-- 可点击 -->
          <block wx:if="{
   
   {numberIsDis === 2}}">
            <view
              class="td td-num color-333"
              wx:for="{
   
   {numberKeyList}}"
              wx:key="idx"
              wx:for-index="idx"
              wx:for-item="itemName"
              catch:tap="numberKeyEnabled"
              data-index="{
   
   {idx}}"
              data-val="{
   
   {itemName}}"
              hover-class="board-active"
              hover-start-time="0"
              hover-stay-time="80"
            >
              {
   
   {itemName}}
            </view>
          </block>
        </view>
      </block>
      <!--字母键盘-->
      <block wx:if="{
   
   {!fieldBoardShow}}">
        <view class="english-keyboard flex between">
          <view
            class="td td-num color-333"
            wx:for="{
   
   {englishKeyOneList}}"
            wx:key="idx"
            wx:for-index="idx"
            wx:for-item="itemName"
            data-index="{
   
   {idx}}"
            data-val="{
   
   {itemName}}"
            hover-class="board-active"
            hover-start-time="0"
            hover-stay-time="80"
            catch:tap="englishKeyClick"
          >
            {
   
   {itemName}}
          </view>
        </view>
        <view class="english-keyboard flex englishtTwo">
          <view
            class="td td-num color-333"
            wx:for="{
   
   {englishKeyTwoList}}"
            wx:key="idx"
            wx:for-index="idx"
            wx:for-item="itemName"
            data-index="{
   
   {idx}}"
            data-val="{
   
   {itemName}}"
            hover-class="board-active"
            hover-start-time="0"
            hover-stay-time="80"
            catch:tap="englishKeyClick"
          >
            {
   
   {itemName}}
          </view>
        </view>
      </block>
      <!--清除按钮-->
      <view
        catch:tap="backspace"
        class="delete flex"
        hover-class="board-active"
        hover-start-time="0"
        hover-stay-time="80"
      >
        <image class="deleteImg" src="/images/clear.png" />
      </view>
    </view>

  </view>
</van-overlay>


wxss文件

@import "../../styles/style.wxss";

.keyBoard_content {
  z-index: 9999;
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  height: auto;
  background: #fff;
}

.top-part {
  width: 100%;
  padding: 25rpx 40rpx;
  height: 92rpx;
  justify-content: center;
  align-items: center;
  box-sizing: border-box;
  border-bottom: 1rpx solid #EAEAEA;
  margin-bottom: 15rpx;
  text-align: center;
}

.close {
  width: 10%;
  font-size: 47rpx;
  color: #A0A0A0;
}

.message {
  width: 80%;
  text-align: center;
  font-weight: Semibold;
}

.confirm {
  width: 10%;
  color: #A0A0A0;
  font-weight: Regular;
}

.confirm-active {
  color: #27B57D;
}

.license {
  box-sizing: border-box;
  justify-content: space-around;
  margin: 60rpx 90rpx 50rpx;
}

.edit-text {
  height: 80rpx;
  line-height: 80rpx;
  width: 60rpx;
  border: 1rpx solid #A0A0A0;
  border-radius: 8rpx;
  text-align: center;
  font-size: 36rpx;
}

.space-left {
  margin-left: 30rpx;
}

.border-active {
  border: 1rpx solid #5BCA92;
}

.keyboard {
  width: 100%;
  height: 450rpx;
  box-sizing: border-box;
  position: relative;
}

.province-keyboard {
  margin: 0 50rpx;
  flex-wrap: wrap;
}

.number-keyboard {
  margin: 0 5rpx;
}

.english-keyboard {
  margin: 0 5rpx;
  flex-wrap: wrap;
}

.englishtTwo {
  margin-left: 10%;
}

.td {
  font-family: "PingFangSC";
  font-size: 36rpx;
  font-weight: Medium;
  margin: 12rpx 4rpx;
  border: 1rpx solid #E0E0E0;
  border-radius: 8rpx;
  height: 84rpx;
  line-height: 84rpx;
  text-align: center;
}

.td-nor {
  flex: 0 1 9%;
}

.td-num {
  flex: 0 1 8%;
}

.board-active {
  box-shadow: 0 0 0 #e5e5e5;
  background: #e5e5e5;
}

.delete {
  width: 140rpx;
  height: 84rpx;
  text-align: center;
  background-color: #D8D8D8;
  border-radius: 8rpx;
  position: absolute;
  right: 80rpx;
  bottom: 30rpx;
  justify-content: center;
  align-items: center;
}

.deleteImg {
  width: 44rpx;
  height: 30rpx;
}

style.wxss 文件

.van-dialog__header {
  padding-bottom: 20rpx;
}

.flex {
  display: flex;
}

.between {
  justify-content: space-between;
}

.font-30 {
  font-size: 30rpx;
}

.color-333 {
  color: #333333;
}

密码支付键盘组件

交互样式如上图

上代码:

json文件

{
  "component": true,
  "usingComponents": {
    "van-popup": "@vant/weapp/popup/index",
    "van-tab": "/miniprogram_npm/@vant/weapp/tab/index"
  }
}

 wxs文件

import { throttle } from '../../utils/throttle'
const passwordInputData = ['', '', '', '', '', '']
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 显示隐藏弹窗
    passWordShow: {
      type: Boolean,
      observer(value) {
        if (!value) {
          this.setData({
            passwordInput: JSON.parse(JSON.stringify(passwordInputData)),
            passwordIndex: -1
          })
        }
      }
    },
    // 支付金额
    payAmount: {
      type: Number
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    passwordInput: JSON.parse(JSON.stringify(passwordInputData)),
    passwordIndex: -1,
    keyboardNumber: '123456789*0*',
    password: ''
  },
  /**
   * 启用插槽
   */
  options: {},
  lifetimes: {
    attached: function() {}
  },
  externalClasses: ['custom-class'],

  /**
   * 组件的方法列表
   */
  methods: {
    // 忘记密码
    forgetPassWord() {
      this.onClose()
      wx.navigateTo({
        url: `/pages/manage-password/refund-password/index?source=Back`
      })
    },

    //tab切换
    onTabChange(e) {
      this.triggerEvent('onTabChange', {
        currStatus: e.currentTarget.dataset.value
      })
    },

    onClose() {
      this.setData({
        passwordInput: JSON.parse(JSON.stringify(passwordInputData)),
        passWordShow: false
      })
      this.triggerEvent('closeFun')
    },

    // throttle防抖
    tapKeyboard: throttle(function(e) {
      const { val } = e.currentTarget.dataset
      const passwordIndex = this.data.passwordIndex + 1
      if (passwordIndex > 5) {
        return
      }
      this.data.passwordInput[passwordIndex] = val
      this.setData({
        passwordIndex,
        passwordInput: this.data.passwordInput
      })
      if (passwordIndex === 5) {
        const password = this.data.passwordInput.join('')
        this.triggerEvent('submitFun', {
          password: password
        })
        this.onClose()
      }
    }),

    tapKeyboardDelete() {
      const passwordIndex = this.data.passwordIndex - 1
      if (passwordIndex < -1) {
        return
      }
      this.data.passwordInput[this.data.passwordIndex] = ''
      this.setData({
        passwordIndex,
        passwordInput: this.data.passwordInput
      })
    }
  }
})
// throttle
export function throttle(fn, delay) {
  let timer = null
  return function(...args) {
    clearTimeout(timer)
    timer = setTimeout(() => fn.apply(this, [...args]), delay)
  }
}

wxml文件

<van-popup
  show="{
   
   { passWordShow }}"
  closeable
  close-icon-position="top-left"
  position="bottom"
  close-icon="cross"
  custom-style="height: 20%"
  bind:close="onClose"
  z-index="99"
  custom-style="height: 914rpx"
>
  <view class="content">
    <view class="title color-333">请输入退款密码</view>

    <view class="password-box">
      <view class="password-main">
        <view
          class="password-item"
          wx:for="{
   
   {passwordInput}}"
          wx:for-index="boxIndex"
          wx:key='boxIndex'
        >
          <view class="star">{
   
   {item ? "*" : ''}}</view>
        </view>
      </view>
      <view class="forget" catch:tap="forgetPassWord">忘记密码</view>
    </view>

    <view class="keyboard flex between">
      <!-- 数字键盘可点击 -->
      <view
        class="td flex color-333"
        wx:for="{
   
   {keyboardNumber}}"
        wx:key="index"
        wx:for-index="idx"
        wx:for-item="itemName"
        data-index="{
   
   {idx}}"
        data-val="{
   
   {itemName}}"
        hover-class="board_bg"
        hover-start-time="0"
        hover-stay-time="80"
      >
        <view
          class="del_icon flex"
          wx:if="{
   
   {idx === 11}}"
          catch:tap="tapKeyboardDelete"
          data-index="{
   
   {idx}}"
          data-val="{
   
   {itemName}}"
        >
          <image class="deleteImg" src="/images/clear.png" />
        </view>
        <view
          class="keyboard-num flex"
          wx:if="{
   
   {idx !== 9 && idx !== 11}}"
          catch:tap="tapKeyboard"
          data-index="{
   
   {idx}}"
          data-val="{
   
   {itemName}}"
        >
          {
   
   {itemName}}
        </view>
      </view>
    </view>

  </view>
</van-popup>

wxss文件

style.wxss文件上面有

@import "../../styles/style.wxss";

.title{
  font-size: 34rpx;
  font-family: PingFangSC, PingFangSC-Medium;
  font-weight: Medium;
  text-align: center;
  min-height: 136rpx;
  line-height: 136rpx;
  border-bottom: 1px solid #eaeaea;
}

.van-popup__close-icon--top-left {
  top: 50rpx!important;
}
.password-box{
  padding-top: 40rpx;
}
.forget{
  font-size: 28rpx;
  text-align: right;
  color: #0091ff;
  padding: 12rpx 28rpx 20rpx;
}
.password-main{
  width: 684rpx;
  height: 104rpx;
  border: 1px solid #a1a1a1;
  border-radius: 3px;
  display: flex;
  margin: 0 auto;
}
.password-item{
  width: 114rpx;
  border-right: 1px solid #a1a1a1;
  display: flex;
  justify-content: center;
  align-items: center;
}
.password-item:last-child{
  border: none;
}
.star{
  font-size: 60rpx;
  line-height: 108rpx;
  padding-top: 20rpx;
}


.keyboard{
  width: 100%;
  height: 490rpx;
  padding: 40rpx 16rpx 0;
  box-sizing: border-box;
  background: #EEEEEE;
  flex-wrap: wrap;
}

.td {
  flex: 0 1 32%;
  border-radius: 8rpx;
  background-color: #fff;
  font-size: 50rpx;
  font-weight: Regular;
  align-items: center;
  justify-content: center;
  margin-bottom: 16rpx;
  height: 96rpx;
}

.board_bg {
  box-shadow: 0 0 0 #e5e5e5;
  background: #e5e5e5;
}

.del_icon {
  width: 100%;
  height: 100%;
  align-items: center;
  justify-content: center;
}

.del_icon .deleteImg {
  width: 54rpx;
  height: 34rpx;
}

.keyboard-num {
  width: 100%;
  height: 100%;
  justify-content: center;
  align-items: center;
}

滑块验证组件

使用微信小程序官方文档提供的滑动组件:

movable-areamovable-view。如下:

 wxml

<movable-area class="sliding-box">
  <view class="label" style="z-index: {
   
   {isSlidePass? 1 : 2}};"> 请按住滑块,拖到最右边</view>
  <view class="has-slip" style="width:{
   
   {isSlidePass ? '100%' : width+'px'}}">{
   
   {isSlidePass ? '验证通过':''}}</view>
  <movable-view
    x="{
   
   {x}}"
    disabled="{
   
   {isSlidePass}}"
    bind:touchend="touchend"
    bindchange="slidChange"
    direction="horizontal"
    scale="true"
    class="sliding-area"
  >
    <view wx:if="{
   
   {!isSlidePass}}" class="sliding-block"> >></view>
    <view wx:else class="sliding-block sliding-icon">
      <van-icon name="checked" color='#29C701' />
    </view>
  </movable-view>
</movable-area>

js

import { $https } from '../../libs/http'
import { encryptionDecodeParmas, encryptionParmas } from '../../utils/encrypt'

const app = getApp()
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 根据具体业务场景需求确实是否需要传递,或者触发父组件事件
    // isSlidePass: {
    //   type: Boolean,
    //   value: false
    // }
  },

  /**
   * 组件的初始数据
   */
  data: {
    width: 0,
    boxWidth: 0,
    sliderData: {},
    x: 0,
    flag: false,
    isSlidePass: false
  },

  ready() {
    const _that = this
    var obj = wx.createSelectorQuery().in(_that)
    obj.selectAll('.sliding-box').boundingClientRect()
    obj.exec(function(rect) {
      const boxWidth = rect[0][0].width.toFixed(2) - 35
      _that.setData({ boxWidth: boxWidth })
    })
  },
  /**
   * 组件的方法列表
   */
  methods: {
    slidChange(e) {
      let { isSlidePass, width } = this.data
      if (isSlidePass) return
      const { x } = e.detail
      width = +x
      this.setData({ width: width })
    },

    async touchend(e) {
      let { isSlidePass, width, boxWidth } = this.data
      // 滑动成功
      if (boxWidth <= +width) {
        // 请求后端接口
        const res = await $https.get('xxx')
        const { code, data, msg } = res.data
        if (+code !== 1000) {
          app.tools.Toast(msg)
          this.setData({ x: 0 })
          return
        }
        // 请求成功更改状态
        isSlidePass = true
        this.setData({ width: width, isSlidePass: isSlidePass })
        // 触发父组件事件,修改 isSlidePass 的值
        // if (isSlidePass) this.triggerEvent('slidePass')
      } else {
        this.setData({ x: 0 })
      }
    }
  }
})

json

{
  "component": true,
  "usingComponents": {}
}

wxss

.sliding-box{
  width: 100%;
  margin: 0 auto;
  height: 60rpx;
  line-height: 60rpx;
  background: #ddd;
  text-align: center;
  box-sizing: border-box;
  padding-right: 40rpx;
}

.label{
  width: 100%;
  line-height: 60rpx;
  position: absolute;
  top: 0;
  left: 0;
  text-align: center;
  z-index: 2;
  font-size: 24rpx;
  color: #333;
}

.sliding-area{
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
}

.sliding-block{
  position: absolute;
  top: 0;
  left: 0;
  background: #fff;
  border: 1rpx solid #ddd;
  text-align: center;
  line-height: 56rpx;
  padding: 0 16rpx;
  color: #999;
  font-size: 24rpx;
}

.sliding-icon{
  border: 1rpx solid #29C701;
}

.has-slip{
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  line-height: 60rpx;
  height: 60rpx;
  background:  #29C701;
  text-align: center;
  overflow:hidden;
  z-index: 1;
  color: #fff;
  font-size: 24rpx;
}

猜你喜欢

转载自blog.csdn.net/lwx931449660/article/details/121736738