如何封装一个键盘并且在vue项目中使用?

651 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第九天,点击查看活动详情.

今天工作中遇到这么一个需求

自己封装一个下图这样的键盘

image.png

我参考了网上的做法,但是过程中遇到了一些问题.

下面是他的步骤:

安装依赖

安装simpleKeyboard依赖:

npm install simple-keyboard --save

安装simpleKeyboard输入法依赖:

npm install simple-keyboard-layouts --save

虚拟键盘组件simpleKeyboard.vue

image.png

image.png

image.png

image.png

image.png

image.png

<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>

输入框组件keyboard-input.vue

<template>
  <div class="input-keyboard">
    <el-input
      v-model="inputValue"
      :autofocus="autofocus"
      :class="inputClass"
      :suffix-icon="suffixIcon"
      :type="type"
      :show-password="showPassword"
      :rows="rows"
      :show-word-limit="showWordLimit"
      :disabled="disabled"
      :maxlength="maxlength"
      :clearable="clearable"
      :size="size"
      :placeholder="placeholder"
      @focus="focusInput($event)"
      @input="inputFun"
    >
      <template v-if="appendPort" slot="append">[1-65535]</template></el-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: 'keyboard-input',
  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,
    showWordLimit: {
      default: true,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    maxlength: Number,
    clearable: {
      type: Boolean,
      default: true,
    },
    size: String,
    placeholder: String,
    appendPort: {
      type: Boolean,
      default: false,
    },
    autocomplete: {
      default: '',
    },
    suffixIcon: {
      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) {
      // console.log('onKeyPress', button);
    },
  },
};
</script>

<style lang="less" scoped>
@import 'style/less/var';
@deep: ~'>>>';
.input-keyboard {
  @{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>

<template>
  <div class="login" @click="judgeCloseKeyboard">
    <div class="form-card" id="form-card">
      <div class="form-body">
        <el-form :model="form" ref="form" :rules="rules" @submit.native.prevent>
          <el-form-item prop="username">
            <keyboard-input
              keyboardClass="login-username"   <== 注意:页面内有多个输入框时,每个输入框的keyboardClass必须是唯一的,才不会报错
              field="username"
              :value="form.username"
              :maxlength="10"
              clearable
              @inputChange="formItemChange"
              placeholder="用户名"
            ></keyboard-input>
          </el-form-item>
          <button
            class="btn-login"
            :disabled="loginDisabled"
            @click.prevent="submit('form')"
          >
            {{ isSubmitting ? '登录中' : '登录' }}
          </button>
        </el-form>
      </div>
    </div>
  </div>
</template>

<script>
import { KeyboardInput } from '../../components/keyboard-input';
import { keyboardInputMixin } from '@/util/mixins';
import { judgeCloseKeyboard } from '@/util/core';

export default {
  components: { KeyboardInput, LoginDialog },
  mixins: [keyboardInputMixin], 
  data() {
    return {
      judgeCloseKeyboard,
      isSubmitting: false,
      form: {
        username: '',
      },
      rules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' },
        ],
      },
    };
  },
  computed: {
    loginDisabled() {
      return this.form.username === '' || this.isSubmitting;
    },
  },
  methods: {
    submit(formName) {
      this.$refs[formName].validate((valid, errFields) => {
        if (valid) {}
      });
    },
  },
};
</script>

<style lang="less" scoped>
@deep: ~'>>>';

.login {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  @{deep}.vue-touch-keyboard{
    width: 600px;
  }
}
.form-card {
  width: 550px;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.8);
  padding: 40px 120px 80px 120px;
  box-sizing: border-box;
  .btn-login {
    width: 100%;
    height: 40px;
    background: #db3e5d;
    border-radius: 2px;
    border: none;
    color: rgba(255, 255, 255, 1);
    &:hover {
      cursor: pointer;
    }
    &:focus {
      outline: none;
    }
    &:disabled {
      cursor: not-allowed;
      background-color: rgba(219, 62, 93, 0.5);
    }
  }
}
@{deep}.el-form-item {
  margin-bottom: 30px;
  .el-input__inner {
    padding: 0 16px;
    font-size: 13px;
    border-radius: 2px;
    border-color: rgba(0, 0, 0, 0.15);
    &:hover,
    &:focus,
    &.is-active {
      border-color: #db3e5d;
    }
  }
}
</style>