美文网首页
Vue自定义数字键盘组件

Vue自定义数字键盘组件

作者: hai_phon | 来源:发表于2019-08-05 16:18 被阅读0次

本文采用需求导向阐述,需求->实现效果->实现思路->核心细节->详细代码以及调用方法
1.需求:需要实现一个安全认证的键盘,如下图效果图

键盘效果图.png
2.实现效果:
实际开发实现图.png
3.实现思路
首先要考虑的是直接用input控件,让手机系统弹出输入法是否可行,我原本是做android的,从android的角度来看,涉及到键盘弹出需要再WebView所在Activity设置android:windowSoftInputMode="stateHidden|adjustResize"属性,否则可能会发生键盘把底部一些布局弹起来的问题,例如:
input自动弹起键盘的实现方式.png
看上面的效果感觉不行,一是样式没有保持一致,还不干净;二是依赖android系统默认设置,三是还要依赖android那边的实现,所以最后决定自己写。
4.实现细节
  • 直接按照普通的样式来写,最后保证键盘控件在父布局的最底部,使用
    position fixed
    left 0
    bottom 0

代码即可实现类似键盘在最底部弹出

  • 父布局需要传递一个值isShowKeyBoard给这个键盘子组件,让父布局根据业务控制是否显示这个键盘组件;
  • 子组件需要在点击确定后取消后告诉父布局,用户输入的密码是什么,或者优化成在键盘子组件进行密码验证,最后返回一个验证结果给父组件,我上传的代码没有调用服务进行验证,而是返回了密码给父组件。

5.详细代码以及调用方法
子组件实现代码(基于pug和style模板语言,不懂的可看我之前的博客):

  • 键盘子组件代码
<!--密码键盘,只能输入6位数字-->
<template lang="pug">
  .keyboard(:class="{isIos : isIOS}" v-show="isShowChild")
    .safe
      .tip 安全验证
      .password {{sercet}}
    .operator
      .btn.sure(@click="clickSure" :class="{sure_canClick: isCanClick}") 确定
      .btn.cancel(@click="clickCancel") 取消
    .num_board
      .row
        button(@click="clickNum('1')") 1
        button.center(@click="clickNum('2')") 2
        button(@click="clickNum('3')") 3
      .row
        button(@click="clickNum('4')") 4
        button(class = "center" @click="clickNum('5')") 5
        button(@click="clickNum('6')") 6
      .row
        button(@click="clickNum('7')") 7
        button(class = "center" @click="clickNum('8')") 8
        button(@click="clickNum('9')") 9
      .row
        button(class= "num_null")
        button(class = "center" @click="clickNum('0')") 0
        button(class = "num_delete" @click="clickNum('X')")
          img(src="../../assets/delete.png" class="icon")


</template>

<script>
  export default {
    props:{// 接受调用处传进来的值
      isShowKeyBoard:{// 是否显示键盘
        required: true,
        default() {
          return false// 默认不显示
        }
      },
    },
    data() {
      return {
        isIOS: false,// 判断当前页面是否跑在ios平台,因为ios平台兼容性问题,要特殊处理
        isCanClick: false,// 如果不可点击'确定'的按钮样式更改
        password: '',//(真正的密码)
        sercet: '',// 密文密码(******)

        // 因为父组件传递进来的属性不支持进行双向绑定,需要创建一个副本isShowChild来进行双向绑定操作。
        isShowChild: this.isShowKeyBoard,
      }
    },
    created(){// 在html渲染前先拿isIOS的值
      let u = navigator.userAgent
      this.isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)

      this.clickNum('X') // 清空数据,恢复默认值
    },
    watch: {// 动态监听父布局是否有改动了传进来的这个值
      isShowKeyBoard: {
        handler(newValue) {
          this.isShowChild = newValue// 有改动则重新赋值给副本
        },
        deep: true,
        immediate: true
      },
    },
    methods: {
      clickCancel() {
        // 因为子组件直接改了副本后  第二次父组件再改  子组件的watch监听不到了,所以这里直接改父控件调用处的原变量,让那边去触发watch,这样第二次还能触发。
        this.$emit('onShowChange', false)
        this.clickNum('X')// 清空密码
      },
      clickSure() {
        if(this.password.length === 6) {
          // 密码长度对了,返回密码,这里也可以调用服务进行验证,最后返回验证的值。
          console.log(this.password)
          this.$emit('onCheckPassword', this.password)
        } else {
          this.$toast('请输入6位数密码')// 请输入6位数密码
        }
      },
      clickNum(num) {
        console.log(num)
        if(num != 'X') {
          if( this.sercet === '请输入交易密码' ) {
            this.password = ''
            this.password +=num
            this.sercet = ''
            this.sercet += '*'
          } else if(this.password.length === 6){
            this.$toast('已经输入6位数了')
          } else{
            this.password +=num
            this.sercet += '*'
            if(this.password.length === 6) {
              this.isCanClick = true
            }
          }
        } else { // 清空密码和相关属性恢复
          this.isCanClick = false
          this.password = ''
          this.sercet= '请输入交易密码'
        }
      },
    },
  }
</script>

<style scoped lang="stylus">
  .keyboard
    background white
    width 100%
    height 355px
    border-radius 8px 8px 0px 0px
    position fixed
    left 0
    bottom 0
    &.isIos
      bottom 48px
    .safe
      height:52px;
      background #E5EBF7
      border-radius:8px;
      display flex
      justify-content space-between
      margin 20px 10px 12px
      padding 16px 14px
      .tip
        font-size 14px
        line-height:20px;
        text-align left
        color #333333
      .password
        color #999999
        font-size 14px
        line-height:20px;
        text-align right
        opacity:1;
    .operator
      display flex
      flex-direction row-reverse
      margin-bottom 20px
      .btn
        width:80px;
        height:32px;
        font-size 14px
        line-height 32px
        display flex
        justify-content center
        &.cancel
          border-radius:4px;
          border:1px solid rgba(68,114,197,1);
          color #4472C5
        &.sure
          background:rgba(144,171,220,1);
          border-radius:4px;
          color #D2DDF1
          margin-right 10px
          margin-left 20px
          &.sure_canClick
            background  #4472C5
            color white
    .num_board
      background #D2D5DB
      height 100%
      padding 6px
      .row
        margin-bottom 7px
        display flex
        flex-direction row
        button
          width:117px;
          height:46px;
          background:rgba(255,255,255,1);
          box-shadow:0px 0 0px 0px rgba(132,134,136,1);
          border-radius:5px;
          text-align center
          font-size 25px
          color #000000
          display flex
          justify-content center
          line-height:46px;
          &.center
            margin 0 6px
        .num_null
          width:117px;
          height:46px;
          float: right;
          margin: 0;
          padding: 0;
          background-color: #D2D5DB;
          border: none
          outline:none
        .num_delete
          width:117px;
          height:46px;
          background #D2D5DB
          position relative
          .icon
            position absolute
            width 23px
            height 18px
            top 30%
            right  40%

</style>
  • 父布局调用代码:
<template lang="pug">
      Keyboard(:isShowKeyBoard="" @onShowChange="showKeyBoard" @onCheckPassword="onCheckPassword")
</template>

<script>
import Keyboard from '_components/keyboard'

data(){
    return {
        isShowKeyBoard: false,// 是否展示数字键盘
    }
},

methods: {
    // 显示或关闭按钮
    showKeyBoard(flag) {
      this.isShowKeyBoard = flag
    },
    // 点击确定的回调
    onCheckPassword(password) {
      this.submitData(password)
    },
},
</script>

相关文章

网友评论

      本文标题:Vue自定义数字键盘组件

      本文链接:https://www.haomeiwen.com/subject/aqnpdctx.html