1. 程式人生 > 其它 >自定義鍵盤元件封裝

自定義鍵盤元件封裝

自定義鍵盤元件封裝

父元件

wxml
<view class="total-amount">
 <view class="total-tit">消費總額</view>
 <!-- <view class="f-j-s total-input-block" catchtap="showKeyboard"> -->
 <view class="f-j-s total-input-block">
   <text class="input_label">¥</text>
   <view class="content" wx:if="{{inputValue.length}}">
     <view wx:for="{{inputValue}}" wx:key="index" data-str-index="{{index + 1}}" catchtap="getStrPosition">
       <view class="number-block">{{item}}<view class="cursor cursor-insert" wx:if="{{cursorIndex === index + 1 && cursorShow}}"></view></view>
     </view>
  </view>
  <view class="cursor" wx:if="{{cursorIndex <=0 && cursorShow}}"></view>
  <text class="default-content" wx:if="{{!inputValue.length}}">{{defaultContent}}</text>
</view>
    
   
<!-- 鍵盤 -->
<key-board
  cursorShow="{{cursorShow}}"
  keyBoardShow="{{true}}"
  cursorIndex="{{cursorIndex}}"
  payAmount="{{payAmount}}"
  realPayAmount="{{realPayAmount}}"
  bind:getKeyBoardData="getKeyBoardData"
  bind:payBtnAction="createdStoreOrder"
>
</key-board>
js
data: {
    payAmount: '', // 支付金額
    defaultContent: '輸入消費金額', // 預設內容
    keyBoardShow: true,  // 是否展示鍵盤
    cursorIndex: 0, // 插入游標位置
    cursorShow: true, // 游標顯示
  },
      
	// 獲取插入游標位置
  getStrPosition(e) {
    let { strIndex } = e.currentTarget.dataset
    this.setData({ cursorIndex: strIndex })
  },
  getKeyBoardData(e) {
    let { cursorIndex, inputValue} = e.detail
    this.setData({
      inputValue: inputValue.split(''),
      payAmount: inputValue,
      cursorIndex
    })
  }
json
"key-board": "/components/KeyBoard/index"
wxss
/* 自定義鍵盤 */
.total-input-block {
  display: flex;
  justify-content: flex-end;
  flex: 1;
  margin-top: 15rpx;
  height: 90rpx;
}
.total-amount {
  display: flex;
  align-items: center;
  padding: 35rpx 0rpx 10rpx;
  box-sizing: border-box;
  border-bottom: 2rpx solid #e5e5e5;
}
.page_box{
  width: 100%;
  height: 100%;
  background: #f3f7f7;
  overflow: hidden;
}
.input_view{
  width: 700rpx;
  height:500rpx;
  background: #fff;
   margin: 25rpx auto; 
  border-radius: 10rpx;
  padding: 40rpx;
  box-sizing: border-box;
}
.title{
  display: block;
  line-height: 90rpx;
  font-size:30rpx;
  color: #aaa;
}
.input_box{
  display: flex;
  align-items: center;
  padding: 20rpx 0;
  height: 90rpx;
  border-bottom: 1px solid #efefef;
}
.input_label{
  font-size: 35rpx;
  font-weight: bold;
  margin-right: 5rpx;
}
.content{
  display: flex;
  font-size: 80rpx;
  line-height: 90rpx;
  font-weight: 700;
}
.number-block{
  position: relative;
}
.cursor-insert{
  position: absolute;
  top: 0rpx;
  right: -1rpx;
}
.cursor{ 
  width: 2rpx;
  height: 90rpx;
  background: #666;
  border-radius: 6rpx;
  animation: twinkling 0.9s infinite ; 
} 
@-webkit-keyframes twinkling{ 
  0%{ 
    background: #fff;
  } 
  100%{ 
    background: #666;
  } 
} 
.default-content{
  color: #EDEDED;
  font-size: 70rpx;
  font-weight: 600;
  line-height: 98px;
}

子元件

js
// components/KeyBoard/index.js
Component({
  /**
   * 元件的屬性列表
   */
  properties: {
    keyBoardShow: Boolean,
    cursorShow: Boolean,
    cursorIndex: Number,
    payAmount: Number,
    realPayAmount: Number,
  },

  /**
   * 元件的初始資料
   */
  data: {
    inputValue:[], 
    KeyboardKeys: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0','.'],
    contentLengthMax: 6, // 小數點前最大長度
  },

  observers: {
    inputValue: function(value) {
      let spotIndex = value.indexOf('.')
      spotIndex >= 4 ? this.setData({contentLengthMax: spotIndex + 3}) : this.setData({contentLengthMax: 6})
    }
  },
  
  /**
   * 元件的方法列表
   */
  methods: {
    // 點選鍵盤 
    keyTap(e) {
      let { keys } = e.currentTarget.dataset,
        inputValue = this.data.inputValue.join(''),   // 轉為字串
        inputLen = inputValue.length, 
        { contentLengthMax } = this.data,
        { cursorIndex } = this.properties
      var spotIndex = inputValue.indexOf('.')         // 小數點的位置
  
      switch (keys) {
        case '.':
          // 已存在點
          if(inputValue.indexOf('.') !== -1) return 
          if(inputLen < contentLengthMax) {
            if(cursorIndex <= 0 || cursorIndex === inputLen) {
              if(inputValue.length < 1) {
                inputValue = '0.'
                cursorIndex = inputLen + 2
              }else{
                inputValue += '.'
                cursorIndex = inputLen + 1
              }
            }else if(cursorIndex) {
              // 從插入游標開始新增點
              this.data.inputValue.splice(cursorIndex, 0, keys)    // 新增點
              this.data.inputValue.splice(cursorIndex + 3)         // 只保留點的後兩位
              inputValue = this.data.inputValue.join('')
              cursorIndex++
            }
          }else if(inputLen === contentLengthMax){
            if(cursorIndex >= 4) {
              this.data.inputValue.splice(cursorIndex, 0, keys)
            }else{
              this.data.inputValue.splice(cursorIndex, 0, keys)    // 新增點
              this.data.inputValue.splice(cursorIndex + 3)         // 只保留點的後兩位
            }
            inputValue = this.data.inputValue.join('')
            cursorIndex++
          }
          break
        case '<':
          if(!inputLen) return
          // 從插入游標開始刪除元素
          if(cursorIndex > 0 && cursorIndex !== inputLen) {
            // 游標下一個為點,且點的位置大於4
            inputValue[cursorIndex - 1] === '.' && spotIndex > 4 ? this.data.inputValue.splice(spotIndex) : this.data.inputValue.splice(cursorIndex - 1, 1)
            inputValue = this.data.inputValue.join('')
            cursorIndex--
          }
          // 從尾部開始刪除元素
          else{
            inputValue = inputValue.substr(0, inputValue.length - 1)
            cursorIndex = inputLen - 1
          }
          // 插入游標位置重置
          if(!inputLen || cursorIndex === inputLen){    
            this.setData({ cursorIndex: 0 })
          }
          // 第一個是0, 第二個不是點, 擷取0之後的 
          if(inputValue[0] === '0' && inputValue[1] !== '.') {
            inputValue = inputValue.substr(1, inputValue.length - 1)
          }
          // 刪除到第一個為點
          if(inputValue[0] === '.') {
            inputValue = '0' + inputValue
          } 
          break
        default:
          // 超出最大長度
          if(inputLen >= contentLengthMax) {
            this.setData({ 
              inputValue: inputValue.split(''), // 轉為陣列
              cursorIndex: inputLen
            })    
            this.triggerEvent('getKeyBoardData', {inputValue, cursorIndex: inputLen})
            return
          }

          // 從尾部新增元素
          if(cursorIndex === inputLen || cursorIndex <= 0) {
            if(inputValue[0] === '0' && inputValue[1] !== '.') {
              inputValue = inputValue.substr(1, inputValue.length - 1)
              cursorIndex = --inputLen
            }
            if(spotIndex === -1 || inputLen - spotIndex !== 3) {  //小數點後只保留兩位
              inputValue += keys
              cursorIndex = ++inputLen
            }
          }
          // 從游標位置開始新增元素
          else if(cursorIndex > 0 && inputLen - spotIndex !== 3){
            // 新增元素
            this.data.inputValue.splice(cursorIndex, 0, keys)
            inputValue = this.data.inputValue.join('')
            cursorIndex++
          }
          break
      }
      this.setData({ 
        inputValue: inputValue.split(''), // 轉為陣列
        cursorIndex
      })    
      this.triggerEvent('getKeyBoardData', {inputValue, cursorIndex})
    },
    // 生成訂單
    payBtnAction() {
      this.triggerEvent('payBtnAction')
    }
  }, 
})

wxss
/* 鍵盤 */
.keyboard{
  position: fixed;
  bottom: 0;
  left: 0;
  height: calc(440rpx + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  width: 100%;
  background: #fff;
  transition:height 0.3s;
  display: flex;
}
.key_box{
  overflow: hidden;
  flex: 5;
}
.f-c{
  display: flex;
  align-items: center;
  justify-content: center;
}
.keys{
  box-sizing: border-box;
  float: left;
  width: 179rpx;
  height: 110rpx;
  text-align: center;
  line-height: 110rpx;
  border-left: 1px solid pink;
  border-top: 1px solid pink;
}
.action_box{
  display: flex;
  flex-direction: column;
  flex: 2;
}
.action_box-delete{
  flex: 1;
  background: #c10505;
}
.action_box-pay{
  flex: 3;
  background: #9CE5BF;
  border-radius: 8px;
}
.action_box-pay>view{
  width: 100%;
  height: 100%;
}
.can-pay{
  background: #05C160;
}
.border0{
  border-left: 0;
}
.double{
  width: 357rpx;
}
.truth-pay_box{
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.truth-pay{
  font-size: 34rpx;
  color: #FFFFFE;
  line-height: 48rpx;
}
.pay-btn{
  font-size: 40rpx;
  color: #FFFFFE;
  line-height: 56rpx;
}
wxml
<!-- 鍵盤 -->
<view class="keyboard" wx:if="{{keyBoardShow}}">
  <view class="key_box">
    <text class="keys {{index%3==0&&'border0'}} {{(index==9)&&'double'}}" wx:for='{{KeyboardKeys}}' wx:key="index" catchtap="keyTap" data-keys="{{item}}">{{item}}</text>
  </view>
  <view class="action_box">
    <view class="f-c action_box-delete" catchtap="keyTap" data-keys="<">刪除</view>
    <view class="action_box-pay {{payAmount && 'can-pay'}}">
      <view class="truth-pay_box" wx:if="{{payAmount > 0}}" catchtap="payBtnAction">
        <text class="truth-pay">¥{{realPayAmount}}</text>
        <text class="pay-btn">付款</text>
      </view>
      <view class="f-c pay-btn" wx:else>付款</view>
    </view>
  </view>
</view>

輸入游標實現原理

① 根據wx:for迴圈原理,第一步將字串使用join方法轉換為陣列

inputValue = this.data.inputValue.join('')

② wx:for迴圈陣列,同時在每個值後面生成一個帶有動畫特效的閃爍的豎線盒子充當游標(從1開始)

<view wx:for="{{inputValue}}" wx:key="index" data-str-index="{{index + 1}}" catchtap="getStrPosition">
    <view class="number-block">
    	{{item}}
    	<view class="cursor cursor-insert" wx:if="{{cursorIndex === index + 1 && cursorShow}}"></view>			</view>
</view>

③ 每個值都有一個索引值index,當點選任意一個值的時候,則相應的光標出現

// 獲取插入游標位置
getStrPosition(e) {
  let { strIndex } = e.currentTarget.dataset
  this.setData({ cursorIndex: strIndex })
},

根據小數點的位置動態變更最大的輸入長度

observers: {
    inputValue: function(value) {
      let spotIndex = value.indexOf('.')
      spotIndex >= 4 ? this.setData({contentLengthMax: spotIndex + 3}) : this.setData({contentLengthMax: 6})
    }
},