自定义安全键盘

由于移动端H5项目的需要,前段时间做了一个安全键盘,给大家分享一下,也给自己做个笔记。

首先建一个文件safeKeyboard.vue安全键盘子组件

<template>
  <div class="keyboard">
    <div class="key_title">
      <p><img src="../../../../static/img/ic_logo@2x.png"><span>泸州银行安全键盘</span></p>
    </div>
    <p v-for="keys in keyList" :style="(keys.length<10&&keys.indexOf('ABC')<1&&keys.indexOf('del')<1&&keys.indexOf('suc')<1)?'padding: 0px 20px;':''">
      <template v-for="key in keys">
        <i v-if="key === 'top'" @click.stop="clickKey" @touchend.stop="clickKey" class="tab-top"><img class="top" :src='top_img'></i>
        <i v-else-if="key === 'del'" @click.stop="clickKey" @touchend.stop="clickKey" class="key-delete"><img class="delete" src='删除图标路径'></i>
        <i v-else-if="key === 'blank'" @click.stop="clickBlank" class="tab-blank">空格</i>
        <i v-else-if="key === 'suc'" @click.stop="success" @touchend.stop="success" class="tab-suc">确定</i>
        <i v-else-if="key === '.?123' || key === 'ABC'" @click.stop="symbol" class="tab-sym">{{(status==0||status==1)?'.?123':'ABC'}}</i>
        <i v-else-if="key === '123' || key === '#+='" @click.stop="number" class="tab-num">{{status==3?'123':'#+='}}</i>
        <i v-else @click.stop="clickKey" @touchend.stop="clickKey">{{key}}</i>
      </template>
    </p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      keyList: [],
      status: 0, // 0 小写 1 大写 2 数字 3 符号
      topStatus: 0, // 0 小写 1 大写
      top_img: require('小写图片路径'),
      lowercase: [
        ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],
        ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],
        ['top', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'del'],
        ['.?123', 'blank', 'suc']
      ],
      numbercase: [
        ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
        ['-', '/', ':', ';', '(', ')', '$', '&', '@', '"'],
        ['#+=', '.', ',', '?', '!', "'", 'del'],
        ['ABC', 'blank', 'suc']
      ],
      symbolcase: [
        ['[', ']', '{', '}', '#', '%', '^', '*', '+', '='],
        ['_', '\\', '|', '~', '<', '>', '€', '`', '¥', '·'],
        ['123', '.', ',', '?', '!', "'", 'del'],
        ['ABC', 'blank', 'suc']
      ],
      uppercase: [
        ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
        ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
        ['top', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', 'del'],
        ['.?123', 'blank', 'suc']
      ],
      equip: !!navigator.userAgent.toLocaleLowerCase().match(/ipad|mobile/i)// 是否是移动设备
    }
  },
  props: {
    option: {
      type: Object
    }
  },

  mounted () {
    this.keyList = this.lowercase
  },

  methods: {
    tabHandle ({value = ''}) {
      if (value.indexOf('tab-num') > -1) {
        if (this.status === 3) {
          this.status = 2
          this.keyList = this.numbercase
        } else {
          this.status = 3
          this.keyList = this.symbolcase
        }
        // 数字键盘数据
      } else if (value.indexOf('delete') > -1) {
        this.emitValue('delete')
      } else if (value.indexOf('tab-blank') > -1) {
        this.emitValue(' ')
      } else if (value.indexOf('tab-point') > -1) {
        this.emitValue('.')
      } else if (value.indexOf('tab-sym') > -1) {
        if (this.status === 0) {
          this.topStatus = 0
          this.status = 2
          this.keyList = this.numbercase
        } else if (this.status === 1) {
          this.topStatus = 1
          this.status = 2
          this.keyList = this.numbercase
        } else {
          if (this.topStatus == 0) {
            this.status = 0
            this.top_img = require('小写图片路径')
            this.keyList = this.lowercase 
          }else{
            this.status = 1
            this.keyList = this.uppercase
            this.top_img = require('大写图片路径')
          }
        }
        // 符号键盘数据
      } else if (value.indexOf('top') > -1) {
        if (this.status === 0) {
          this.status = 1
          this.keyList = this.uppercase
          this.top_img = require('大写图片路径')
        } else {
          this.status = 0
          this.keyList = this.lowercase
          this.top_img = require('小写图片路径')
        }
      } else if (value.indexOf('tab-suc') > -1) {
        this.$emit('closeHandle', this.option) // 关闭键盘
      }
    },
    number (event) {
      this.tabHandle(event.srcElement.classList)
    },
    clickBlank (event) {
      this.tabHandle(event.srcElement.classList)
    },
    symbol (event) {
      this.tabHandle(event.srcElement.classList)
    },
    success (event) {
      this.tabHandle(event.srcElement.classList)
    },
    english (event) {
      this.tabHandle(event.srcElement.classList)
    },
    clickKey (event) {
      if (event.type === 'click' && this.equip) return
      let value = event.srcElement.innerText
      value ? this.emitValue(value) : this.tabHandle(event.srcElement.classList)
    },

    emitValue (key) {
      this.$emit('keyVal', key) // 向父组件传值
    },

    closeModal (e) {
      if (e.target !== this.option.sourceDom) {
        this.$emit('closeHandle', this.option)
        this.keyList = this.lowercase
      }
    },
  }
}
</script>
<style scoped lang="scss">
.keyboard {
  width: 100%;
  margin: 0 auto;
  font-size: 18px;
  border-radius: 2px;
  background-color: #fff;
  box-shadow: 0 -2px 2px 0 rgba(89,108,132,0.20);
  user-select: none;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 999;
  pointer-events: auto;
  .key_title{
    height: 84px;
    font-size: 32px;
    color: #0B0B0B;
    overflow: hidden;
    margin-bottom: 16px;
    p{
      display: flex;
      justify-content: center;
      align-items: center;
      min-width: 302px;
      height: 32px;
      margin: 32px auto 0px;
      img{
        width: 32px;
        height: 32px;
        margin-right: 10px;
      }
    }
  }
  p {
    width: 99%;
    margin: 0 auto;
    height: 84px;
    margin-bottom: 24px;
    display: flex;
    display: -webkit-box;
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: center;
    box-sizing: border-box;
    i {
      position: relative;
      display: block;
      margin: 0px 5px;
      height: 84px;
      line-height: 84px;
      font-style: normal;
      font-size: 48px;
      border-radius: 8px;
      width: 64px;
      background-color: #F2F4F5;
      box-shadow: 0 2px 0 0 rgba(0,0,0,0.25);
      text-align: center;
      flex-grow: 1;
      flex-shrink: 1;
      flex-basis: 0;
      -webkit-box-flex: 1;
      img{
        width: 48px;
        height: 48px;
      }
    }
    i:first-child{
      margin-left: 0px
    }
    i:last-child{
      margin-right: 0px
    }
    i:active {
      background-color: #A9A9A9;
    }
    .tab-top, .key-delete, .tab-num, .tab-eng, .tab-sym{
      background-color: #CED6E0;
    }
    .tab-top,.key-delete {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 84px;
      height: 84px;
    }
    .tab-top{
      margin-right: 30px;
      font-size: 32px;
    }
    .key-delete{
      margin-left: 30px;
    }
    .tab-num, .tab-eng, .tab-sym{
      font-size: 32px;
    }
    .tab-point {
      width: 70px;
    }
    .tab-blank, .tab-suc{
      text-align: center;
      line-height: 84px;
      font-size: 32px;
      color: #000;
    }
    .tab-blank{
      flex: 2.5;
    }
    .tab-suc{
      background-color: #CFA46A;
    }
  }
  p:last-child{
    margin-bottom: 8px;
  }
}
</style>

但是,键盘的特性是,点击除键盘和输入框以外的地方,键盘收起。

所以还需要一个clickoutside.js文件,用来自定义一个指令,实现需求:

export default {
  bind(el, binding, vnode) {
    function documentHandler(e) {
      if (el.contains(e.target)) {
        return false;
      }
      if (binding.expression) {
        binding.value(e);
      }
    }
    el.__vueClickOutside__ = documentHandler;
    document.addEventListener('click', documentHandler);
  },
  unbind(el, binding) {
    document.removeEventListener('click', el.__vueClickOutside__);
    delete el.__vueClickOutside__;
  }
};

然后在safeKeyboard.vue中引入:

import clickoutside from './clickoutside'

并注册局部指令:

directives: { clickoutside }

然后绑定方法:

<div class="keyboard" v-clickoutside="closeModal">

声明方法:

closeModal (e) {

      if (e.target !== this.option.sourceDom) {

        this.$emit('closeHandle', this.option)

        this.keyList = this.lowercase

      }

    },

安全键盘组件就构建完成了,接下来是在需要用到安全键盘的页面引入:

import Keyboard from './safeKeyboard'

components: {

      Keyboard

 }

键盘相关数据对象

option: {

          show: false, // 键盘是否显示

          sourceDom: '', // 键盘绑定的Input元素

          _type: '' // 键盘绑定的input元素ref

 },

<input type="password" ref="setPwd" v-model='password'/> 

<Keyboard v-if="option.show" :option="option" @keyVal="getInputValue" @closeHandle="onLeave"></Keyboard>

getInputValue(val)会接收键盘录入的数据,val是输入的单个字符或者是删除操作,由于是单个字符,所以需在方法中手动拼接成字符串。在方法中根据option._type区分是哪个输入框的数据。

onLeave()相当于blur,这是由于在移动端H5项目中,input获取焦点时会调起手机软键盘,所以需要禁止软键盘被调起来,办法是:

document.activeElement.blur() // ios隐藏键盘

this.$refs.setPwd.blur() // android隐藏键盘

就相当于强制使input元素处于blur状态,那么软键盘就不会被调起,所以如果要做blur监听,就需要onLeave()。

但是这样出现了一个新的问题,输入框里面没有光标!!虽然不影响业务逻辑,但是用户用起来会很不舒服。

所以,只能和input元素说再见了,自己手写一个吧:

再来一个子组件cursorBlink.vue

<template>
  <div class="cursor-blink" @click.stop="isShow">
    <span v-if="pwd.length>0" :style="options.show?'':'border:0;animation:none;'" class="blink">{{passwordShow}}</span>
    <span v-else style="color: #ddd" :style="options.show?'':'border:0;animation:none;'" class="blink_left">{{options.desc}}</span>
  </div>
</template>
<script>
export default {
  props: {
    pwd: {
      type: String
    },
    options: {
      type: Object
    },
  },
  data(){
    return {
      passwordShow: '',
    }
  },
  mounted() {
    if(this.pwd.length > 0){
      for (let i = 0; i < this.pwd.length; i++) {
        this.passwordShow += '*' // 显示为掩码
      }
    }
  },
  watch: {
    pwd(curVal, oldVal){
      if (oldVal.length < curVal.length) {
        // 输入密码时
        this.passwordShow += '*'
      } else if (oldVal.length > curVal.length) {
        // 删除密码时
        this.passwordShow = this.passwordShow.slice(0, this.passwordShow.length - 1)
      }
    }
  },
  methods: {
    isShow(){
      this.$emit('cursor')
    }
  },
}
</script>
<style lang="scss" scoped>
  .cursor-blink{
    display: inline-block;
    width: 500px;
    height: 43px;
    letter-spacing: 0px;
    word-spacing: 0px;
    padding: 2px 0px;
    font-size: 28px;
    overflow: hidden;
    .blink,.blink_left{
      display: inline;
      margin: 0px;
    }
    .blink{ // 输入密码后
      border-right: 2px solid #000;
      animation: blink 1s infinite steps(1, start);
    }
    .blink_left{ // 输入密码前
      border-left: 2px solid #000;
      animation: blinkLeft 1s infinite steps(1, start);
    }
  }
  @keyframes blink {
    0%, 100% {
      border-right: 2px solid #fff;
    }
    50% {
      border-right: 2px solid #000;
    }
  }
  @keyframes blinkLeft {
    0%, 100% {
      border-left: 2px solid #fff;
    }
    50% {
      border-left: 2px solid #000;
    }
  }
</style>

引入之后光荣的接替input的位置:

<CursorBlink :pwd='password' ref="setPwd" :options='option2' @cursor="onFocus"></CursorBlink>

option2: {

          show: false,  // 区分输入前输入后

          desc: '请重复输入密码'  // 相当于placeholder

  },

onFocus() 相当于input标签的focus

如有兴趣一起探讨技术,请关注公众号

​​​​​​​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: WPF自定义工控触控键盘是一种特殊的应用程序,主要是为了更好地满足工业控制领域的需求。在传统的工控设备中,物理键盘通常很大,不便于移动和安装。而且,有时需要工程师们花费大量精力来编写复杂的驱动程序。 WPF自定义工控触控键盘可以解决这些问题。相对于传统物理键盘,它更加轻便和灵活;更重要的是,只需要少量的代码即可实现高度个性化的特征,大大减少了工程师们的工作量。因此,WPF自定义工控触控键盘已成为很多工业控制领域的首选方案。 在实际应用过程中,WPF自定义工控触控键盘通常有以下特点: 1. 优秀的触摸感应效果,能够更好地适应不同的触摸屏幕需求。 2. 可以高度定制化,可以根据客户的需求来进行UI界面和交互方式的调整,满足更广泛的应用需求。 3. 实时性高,能够满足各类复杂的系统应用,保证数据的实时采集与处理。 4. 代码量少,相对于传统的物理键盘,它无需编写太多的驱动程序,能够更加高效地进行开发。 总之,WPF自定义工控触控键盘具有很多优势,并逐渐成为工业控制领域的主流方案。它能够为用户提供更加灵活和可定制的应用方案,带来更高效、安全的工业生产和操作体验。 ### 回答2: WPF自定义工控触控键盘是一种便捷的实现机器人人机交互的方法。这种自定义工控触控键盘根据机器人实际需求,以可视化的方式设计界面,并实现可定制的功能,既简单又灵活。 在WPF自定义工控触控键盘中,我们可以使用WPF中的控件和布局来定义机器人控制面板。机器人控制面板可以通过添加按钮、文本框、下拉框等控件进行快捷控制。在这个过程中,我们可以使用各种布局以确保面板的外观精美和可用性。 使用WPF自定义工控触控键盘时还可以使用许多流行的控件库,使设计变得更加简单,如Telerik、Syncfusion、DevExpress等,这些库提供了大量可重用的控件和样式,可以轻松创建可定制化的控制面板以及其他用户界面。 WPF自定义工控触控键盘不仅可以使机器人控制面板可视化,也可以将机器人控制与电脑的其他硬件设备、应用程序和网络设备有机地结合在一起。例如,可以通过编写代码将机器人的控制指令发送到网络设备,从而实现通过互联网控制机器人。 总之,WPF自定义工控触控键盘使机器人控制面板的设计更加自由和灵活,使机器人控制更加便捷和高效。这种自定义工控触控键盘可以实现各种机器人任务的快速实现,是机器人应用领域的重要技术之一,同时也是人机交互领域不可或缺的一部分。 ### 回答3: WPF是一种用于.NET框架的GUI开发工具,可以用来创建各种桌面应用程序。在工控应用领域,触控键盘已经成为常见的工具,可以用来实现人机交互,提高工作效率。通过WPF自定义工控触控键盘,可以实现更加灵活和个性化的功能。 WPF提供了许多UI控件,可以用来创建各种视觉元素。开发者可以利用这些控件创建自定义的触控键盘,并将其集成到工控应用中。例如,可以使用按钮控件来创建各种键位,使用文本框控件来显示输入的字符等等。WPF还提供了丰富的样式和模板功能,可以用来美化自定义键盘的外观,并实现与应用程序的整体风格统一。 在工控应用中,触控键盘需要具备一些特殊的功能,如支持多种输入方式(单击、滑动、长按等)、精准的触控响应和持久化的自定义设置等。为了实现这些功能,开发者需要对WPF的触摸事件机制有深入的理解,并根据实际需求进行相应的处理和优化。 总之,通过WPF自定义工控触控键盘,可以提高工控应用的交互性和实用性,满足不同场景下的需求,同时也能增加开发者的编程技能和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值