关于simple-keyboard在vue的应用

宰父单弓
2023-12-01

1、安装

simple-keyboard

2、keyborard封装组件

<SimpleKeyboard
   :ref="keyboardClass"
   :keyboardClass="keyboardClass"
   @onChange="onChange"
   @onKeyPress="onKeyPress"
   :input="inputValue"
   :maxLength="maxlength"
/>

组件代码

SimpleKeyboard.vue

Keyboard配置可以根据自己定义

<template>
  <div :class="keyboardClass"></div>
</template>

<script lang="ts" setup>
import { reactive, ref, defineProps, watch, unref, onMounted, defineEmits } from 'vue'
import Keyboard from 'simple-keyboard'
import 'simple-keyboard/build/css/index.css'
import layout from 'simple-keyboard-layouts/build/layouts/chinese' // 中文输入法

const props = defineProps({
  keyboardClass: {
    default: 'simple-keyboard',
    type: String
  },
  input: {
    default: ''
  },
  maxLength: { default: '' }
})
const keyboard = ref(null)
const emit = defineEmits(['onChange', 'onKeyPress'])
const displayDefault = reactive({
  '{bksp}': 'backspace',
  '{lock}': 'caps',
  '{enter}': '无',
  '{tab}': 'tab',
  '{shift}': 'shift',
  '{change}': '中文',
  '{space}': ' ',
  '{clear}': '清空',
  '{close}': '关闭'
})

watch(
  () => unref(props).input,
  (input) => {
    keyboard.value.setInput(input)
  }
)

function onChange(input) {
  keyboard.value.setInput(input)
  emit('onChange', input)
}

function handleShift() {
  let currentLayout = keyboard.value.options.layoutName
  let shiftToggle = currentLayout === 'default' ? 'shift' : 'default'

  keyboard.value.setOptions({
    layoutName: shiftToggle
  })
}

function onKeyPress(button, $event) {
  // 点击关闭
  if (button === '{close}') {
    let keyboard = $event.path[3]
    keyboard.style.visibility = 'hidden'
    return false
  } else if (button === '{change}') {
    // 切换中英文输入法
    if (keyboard.value.options.layoutCandidates !== null) {
      displayDefault['{change}'] = '中文'
      // 切换至英文
      keyboard.value.setOptions({
        layoutCandidates: null,
        display: displayDefault
      })
    } else {
      // 切换至中文
      displayDefault['{change}'] = '英文'
      keyboard.value.setOptions({
        layoutCandidates: layout.layoutCandidates,
        display: displayDefault
      })
    }
  } else if (button === '{clear}') {
    keyboard.value.clearInput()
  } else if (button === '{enter}') {
    // keyboard.value.setInput('')
    // emit('onKeyPress', button)
  } else {
    let value = $event.target.offsetParent.parentElement.children[0].children[0].value
    // 输入框有默认值时,覆写
    if (value) {
      keyboard.value.setInput(value)
    }
    emit('onKeyPress', button)
  }
  if (button === '{shift}' || button === '{lock}') handleShift()
}

onMounted(() => {
  keyboard.value = new Keyboard(props.keyboardClass, {
    onChange: onChange,
    onKeyPress: onKeyPress,
    layoutCandidates: null,
    layout: {
      // 默认布局
      default: [
        '` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
        '{tab} q w e r t y u i o p [ ] \\',
        "{lock} a s d f g h j k l ; ' {enter}",
        '{shift} z x c v b n m , . / {clear}',
        '{change} {space} {close}'
      ],
      // shift布局
      shift: [
        '~ ! @ # $ % ^ & * ( ) _ + {bksp}',
        '{tab} Q W E R T Y U I O P { } |',
        '{lock} A S D F G H J K L : " {enter}',
        '{shift} Z X C V B N M < > ? {clear}',
        '{change} {space} {close}'
      ]
    },
    // 按钮展示文字
    display: displayDefault,
    // 按钮样式
    buttonTheme: [
      {
        class: 'hg-red close',
        buttons: '{close}'
      },
      {
        class: 'change',
        buttons: '{change}'
      }
    ],
    // 输入限制长度
    maxLength: props.maxLength
  })
})
</script>

<style lang="less">
@deep: ~'>>>';
.hg-theme-default {
  width: 70%;
  .hg-button {
    &.hg-red {
      background: #db3e5d;
      color: white;
      &.close {
        max-width: 200px;
      }
    }
    &.change {
      max-width: 200px;
    }
  }
}
</style>

3、ui库封装 

KeyboardInput.js
<template>
  <div class="input-keyboard">
    <n-input
      v-model:value="inputValue"
      :autofocus="autofocus"
      :class="inputClass"
      :type="type"
      :show-password-on="showPassword"
      :rows="rows"
      :disabled="disabled"
      :maxlength="maxlength"
      :clearable="clearable"
      :showPasswordOn="showPasswordOn"
      :size="size"
      :placeholder="placeholder"
      @focus="focusInput($event)"
      @input="inputFun"
    >
      <slot></slot>
    </n-input>
    <SimpleKeyboard
      :ref="keyboardClass"
      :keyboardClass="keyboardClass"
      @onChange="onChange"
      @onKeyPress="onKeyPress"
      :input="inputValue"
      :maxLength="maxlength"
    />
  </div>
</template>

<script>
import SimpleKeyboard from './simpleKeyboard.vue'

export default {
  name: 'KeyboardInput',
  components: {
    SimpleKeyboard
  },
  props: {
    keyboardClass: String,
    autofocus: Boolean,
    field: String,
    value: {
      default: ''
    },
    inputClass: String,
    type: {
      type: String,
      default: 'text'
    },
    showPassword: {
      type: Boolean,
      default: false
    },
    rows: Number,
    disabled: {
      type: Boolean,
      default: false
    },
    maxlength: Number,
    clearable: {
      type: Boolean,
      default: true
    },
    showPasswordOn: {
      type: String,
      default: ''
    },
    size: String,
    placeholder: String,
    autocomplete: {
      default: ''
    }
  },
  data() {
    return {
      input: null,
      inputEle: null
    }
  },
  computed: {
    inputValue: {
      get() {
        return this.value
      },
      set(value) {
        this.$emit('inputChange', value, this.field)
      }
    }
  },
  methods: {
    inputChange() {
      this.$emit('inputChange')
    },
    inputFun() {
      this.$emit('input')
    },
    focusInput(e) {
      this.inputEle = e.srcElement
      // 关闭所有keyboard
      let arr = document.querySelectorAll('.hg-theme-default')
      arr.forEach((ele) => {
        ele.style.visibility = 'hidden'
      })

      // 打开当前输入框的keyboard
      let currentKeyborad = this.$refs[this.keyboardClass]
      currentKeyborad.$el.style.visibility = 'visible'
      this.$emit('focus')
    },
    onChange(input) {
      this.inputValue = input
      // 解决当输入框为密码输入框时,切换显示/隐藏密码,光标在开头问题,注意:element-ui版本号需为2.15.2及以上
      this.inputEle.focus()
    },
    onKeyPress(button) {
      this.$emit('inputChange', button)
    }
  }
}
</script>

<style lang="less" scoped>
@deep: ~'>>>';
.input-keyboard {
  width: 100%;
  @{deep}.hg-theme-default {
    position: fixed;
    left: 50%;
    bottom: 20px;
    transform: translate(-50%);
    visibility: hidden;
    margin-top: 20px;
    z-index: 2000;
    // 中文文字选择框
    .hg-candidate-box {
      position: static;
      transform: translateY(0);
    }
    // 键盘
    .hg-rows {
    }
  }
  &.citc-search-input {
    .el-input {
      width: 100% !important;
    }
  }
  // 密码输入框显示密码图标效果
  @{deep}.el-input__inner[type='text'] + span .el-icon-view {
    color: red;
  }
}
</style>

4、最外层调用

<keyboard-input
   keyboardClass="login-password"
   field="password"
   type="password"
   :value="formInline.password"
   :maxlength="30"
   showPasswordOn="click"
   @inputChange="formItemChange"
   placeholder="请输入密码"
>
</keyboard-input>
import KeyboardInput from '@/components/SimpleKeyboard/KeyboardInput.vue'

5、最后在使用input外层div,加入监听点击关闭键盘

@click="judgeCloseKeyboard"

import { judgeCloseKeyboard } from '@/utils'

/**
 * 点击除输入框及虚拟键盘外元素时,隐藏虚拟键盘
 * @param  {e} 点击的元素
 */
export const judgeCloseKeyboard = (e) => {
  e.stopPropagation() // 阻止事件冒泡
  const arr = document.querySelectorAll('.input-keyboard') // 设置目标区域
  if (!arr || (arr && arr.length === 0)) return
  let flag = false
  const excludeClassName = [
    'n-input__input', // 带虚拟键盘的输入框
    'n-input__input-el', // 输入框
    'n-base-clear', // 输入框-清除图标
    'hg-candidate-box', // 中文选择框
    'hg-candidate-box-prev', // 中文选择框-上一页
    'hg-candidate-box-list', // 中文选择框-内容列表
    'hg-candidate-box-list-item', // 中文选择框-内容选项
    'hg-candidate-box-next', // 中文选择框-下一页
    'hg-theme-default', // 虚拟键盘
    'hg-rows', // 虚拟键盘-内容
    'hg-row', // 虚拟键盘-行
    'hg-button' // 虚拟键盘-按钮
  ]
  const classList = e.target.classList.value.split(' ')
  const concatArr = excludeClassName.concat(classList)

  arr.forEach((ele) => {
    // 判断点击事件发生在区域外的条件是:1. 点击事件的对象不是目标区域本身 2. 事件对象同时也不是目标区域的子元素
    if (
      // 判断当前点击的元素类名,是否包含排除元素
      new Set(concatArr).size === concatArr.length &&
      !ele.contains(e.target)
    ) {
      flag = true
    }
  })
  flag && hideKeyboard()
}
/**
 * 隐藏虚拟键盘
 */
export const hideKeyboard = () => {
  console.log('我出发了')
  const arr = document.querySelectorAll('.hg-theme-default')
  arr.forEach((ele) => {
    ele.style.visibility = 'hidden'
  })
}

excludeClassName里面是点击不会关闭键盘的classname

 类似资料: