基于uni-app的自定义数字键盘封装

5,818 阅读3分钟

初衷

  • 封装自定义数字键盘,免去各个页面对数字的正确性校验,基础校验集中在数字键盘组件中即可。

  • H5中的input type为number,有一个弊病就是不支持负数。需求中有输入负数的情况。

思路

字符串拼接,将用户输入的每一个数字都认为是字符串。

在最后完成输入的时候,进行统一校验。

代码

<!--
 * @Description: 封装数字键盘
 * @Author: Kyeoni hujr
 * @Date: 2020-06-22 16:51:32
 * @LastEditors: Kyeoni hujr
 * @LastEditTime: 2020-09-16 15:29:07
--> 

<template>
  <view @tap="handleNumberKeyboardTap">
    <slot></slot>
    <uni-popup ref="popup" type="bottom" :mask-click="false">
      <view class="keyboard">
        <view class="keyboard-top-button">
          <view @tap.stop="handleCancelTap">取消</view>
          <view class="keyboard-top-button-title">{{ title }}</view>
          <view @tap.stop="handleConfirmTap">完成</view>
        </view>
        <view class="keyboard-show-box">
          {{ showNumber }}
        </view>
        <view class="keyboard-main-button">
          <view class="keyboard-main-button-left">
            <view 
              class="keyboard-button"
              hover-class="button-hover"
              v-for="(item, index) in [1,2,3,4,5,6,7,8,9]" 
              :data-key="item"
              :key="index"
              @tap.stop="handleButtonClick"
            >
              {{ item }}
            </view>
            <view 
              class="keyboard-button"
              hover-class="button-hover"
              data-key="00"
              @tap.stop="handleButtonClick"
            >00</view>
            <view 
              class="keyboard-button"
              hover-class="button-hover"
              :data-key="0"
              @tap.stop="handleButtonClick"
            >0</view>
            <view 
              :class="['keyboard-button', isInteger && 'integer']"
              hover-class="button-hover"
              data-key="."
              @tap.stop="handleButtonClick"
            >.</view>
          </view>
          <view class="keyboard-main-button-right">
            <view 
              class="keyboard-button-right"
              hover-class="button-hover"
              data-key="删除"
              @tap.stop="handleButtonClick"
            >删除</view>
            <view 
              class="keyboard-button-right"
              hover-class="button-hover"
              data-key="-"
              @tap.stop="handleButtonClick"
            >-</view>
          </view>
        </view>
      </view>
    </uni-popup>
  </view>
</template>

<script>
export default {
  model: {
    prop: 'number',
    event: 'change'
  },
  props: {
    number: String,
    title: String,
    disabled: {
      type: Boolean,
      default: false
    },
    isInteger: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      show: false,
      showNumber: this.number
    }
  },
  watch: {
    show (val) {
      if (val) {
        this.$refs.popup.open()
      } else {
        this.$refs.popup.close()
      }
    },
    number (val) {
      this.showNumber = val
    }
  },
  methods: {
    handleNumberKeyboardTap () {
      if (!this.disabled) {
        this.show = true
        this.showNumber = this.number
        this.$emit('open')
      }
    },
    handleButtonClick (e) {
      let num = this.showNumber
      let inputValue = e.currentTarget.dataset.key
      if (inputValue === '.' && this.isInteger) {
        return
      }
      if (inputValue === '删除') {
        num = num.substring(0, num.length - 1)
      } else {
        num = num + inputValue
      }
      this.showNumber = num
    },
    handleTopClick () {
      this.show = false
    },
    handleConfirmTap () {
      if (isNaN(Number(this.showNumber))) {
        this.$toast.showCommonToast('请输入格式正确的数字')
        return
      }
      this.$emit('change', this.showNumber = Number(this.showNumber) + '')
      this.show = false
    },
    handleCancelTap () {
      this.$emit('close')
      this.show = false
    }
  },
}
</script>

<style lang="scss" scoped>

.keyboard {
  background-color: $cyber-border-color;
  font-size: 18px;
  border-top: 1px solid $cyber-border-color;
  font-family: -apple-system;
  color: #323233;
  .keyboard-top-button {
    height: 45px;
    line-height: 45px;
    color: $cyber-color-primary;
    display: flex;
    justify-content: space-between;
    background-color: #fff;
    view {
      width: 15%;
      padding: 0 20px;
      text-align: center;
    }
    &-title {
      flex: 1;
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
    }
  }
  .keyboard-show-box {
    height: 50px;
    line-height: 50px;
    font-size: 20px;
    font-weight: 500;
    text-align: center;
    padding: 10px;
    letter-spacing: 1px;
    background-color: #fff;
    border-top: 1px solid $cyber-border-color;
  }
  .keyboard-main-button {
    padding: 0 10px 10px 10px;
    display: flex;
    text-align: center;
    &-left {
      width: 82%;
      display: flex;
      flex-wrap: wrap;
      justify-content: space-around;
    }
    &-right {
      width: 18%;
      display: flex;
      flex-direction: column;
      .keyboard-button-right {
        flex: 1;
        vertical-align: middle;
        color: #666;
        background-color: #fff;
        margin-top: 10px;
        box-shadow: 0 5px 5px 0 #ccc;
        font-weight: 500;
        border-radius: 5px;
        line-height: 100px;
      }
    }
    .keyboard-button {
      width: 30%;
      color: #666;
      background-color: #fff;
      height: 50px;
      line-height: 50px;
      border-radius: 5px;
      margin-top: 10px;
      box-shadow: 0 5px 5px 0 #ccc;
      font-weight: 500;
    }
    .integer {
      visibility: hidden;
    }
  }
}
.button-hover {
  background-color: $cyber-border-color !important;
}
</style>

收获

最大的收获就是最后的数字格式校验。

开发的时候思维定势,一直想的都是用正则进行校验,绞尽脑汁想正则怎么写,兼容正数负数,如果用户输入前导0,怎么把0去掉,等等。

后来经高人提醒,可以直接用类型转换,将字符串转换成数字,转换成功就是数字,转换不成功就是格式有误的字符串。

本文使用 mdnice 排版