首页 > 其他分享 >vue 软键盘组件封装

vue 软键盘组件封装

时间:2023-03-28 19:13:19浏览次数:39  
标签:vue 封装 elem value 输入框 软键盘 key return type

场景和需求

1 软键盘固定
2 多输入框共用一个组件,聚焦切换时操作对象自动切换
3 根据光标在输入框的位置进行相应的输入和删除操作
4 点击软键盘时保存输入框光标活跃
5 输入框和键盘在一个弹窗组件中,弹窗打开时对其中一个输入框默认聚焦
6 样式方面,按键宽度自适应,可以给特定按键特定样式。
7 场景下特殊需求,当不对任意输入框聚焦时,默认对其中某个输入框进行操作。
image

实现

光标这个没做到输入框保持活跃,和删除光标处内容。
这里是获取光标位置的函数,但是当点击按钮时输入框就会blur,就无法获取了。

//获取光标位置函数
getCursorPosition(id) {
  const elem = document.querySelector(id);
  var pp = 0;
  // IE
  if (document.selection) {
    elem.focus();
    var aa = document.selection.createRange();
    aa.moveStart('character', -elem.value.length);
    pp = aa.text.length;
  }
  // FF, Chrome
  else if (elem.selectionStart || elem.selectionStart == '0') {
    pp = elem.selectionStart;
  }
  return pp;
},

子组件

<template>
  <div class="keyboards">
    <div class="keyboards-row" v-for="(keyArr, index) in activeKey" :key="index">
      <button
        class="keyboards-key"
        v-for="item in keyArr"
        v-text="item"
        :key="item + index"
        :class="{
          'keyboards-key--active': item === activeButton,
          'keyboards-key--number': type === 'number',
          'keyboards-key--all': type !== 'number',
          'keyboards-key--star': item === '*',
          'keyboards-key--option': isOption(type, item)
        }"
        @click="clickKey(item)"
        @mousedown="changeActiveButton(item)"
      />
    </div>
  </div>
</template>

<script>
export default {
  name: 'SoftKeyboard',
  props: {
    type: {
      type: String,
      // number || uppercase || lowercase
      default: () => 'number'
    },
    inputText: {
      type: String,
      default: () => ''
    },
    inputDom: {
      type: String,
      default: () => ''
    }
  },
  data() {
    return {
      activeKey: [],
      isUppercase: '',
      activeButton: '', // 当前按压按钮
      // 数字键盘布局
      numberKey: [
        ['7', '8', '9'],
        ['4', '5', '6'],
        ['1', '2', '3'],
        ['0', '*', '删除', '清空']
      ],
      // 全键布局
      allBigKey: [
        ['!', '@', '#', '$', '%', '^', '&', '*', '-', '_'],
        ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
        ['切换', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
        ['删除', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '.', '清空']
      ],
      allsmallKey: [
        ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
        ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],
        ['切换', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],
        ['删除', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '.', '清空']
      ]
    };
  },
  created() {
    this.changeKeyborad(this.type);
    if (this.type === 'uppercase') {
      this.isUppercase = true;
    }
    document.addEventListener('mouseup', this.mouseUp);
  },
  mounted() {},
  destroyed() {
    // 组件销毁时移除添加到document上的事件,避免影响到其他组件
    document.removeEventListener('mouseup', this.mouseUp);
  },
  methods: {
    changeKeyborad(type) {
      switch (type) {
        case 'number':
          this.activeKey = this.numberKey;
          break;
        case 'uppercase':
          this.activeKey = this.allBigKey;
          break;
        case 'lowercase':
          this.activeKey = this.allsmallKey;
          break;
        default:
          break;
      }
    },
    isOption(type, btn) {
      if (type === 'number') {
        return false;
      }
      if (btn === '切换' || btn === '删除' || btn === '清空') {
        return true;
      }
      return false;
    },
    clickKey(key) {
      let value = this.inputText;
      switch (key) {
        case '删除':
          value = value.length ? value.slice(0, -1) : value;
          break;
        case '清空':
          value = '';
          break;
        case '切换':
          this.isUppercase = !this.isUppercase;
          this.activeKey = this.isUppercase ? this.allBigKey : this.allsmallKey;
          break;
        default:
          value = value + key;
          break;
      }
      this.$emit('onChange', value);
    },
    changeActiveButton(button) {
      this.activeButton = button;
    },
    //获取光标位置函数
    getCursorPosition(id) {
      const elem = document.querySelector(id);
      var pp = 0;
      // IE
      if (document.selection) {
        elem.focus();
        var aa = document.selection.createRange();
        aa.moveStart('character', -elem.value.length);
        pp = aa.text.length;
      }
      // FF, Chrome
      else if (elem.selectionStart || elem.selectionStart == '0') {
        pp = elem.selectionStart;
      }
      return pp;
    },
    mouseUp() {
      this.activeButton = '';
    }
  }
};
</script>
<style scoped lang="scss">
.keyboards {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  background-color: #f0f0f0;
  padding: 3px;
  border-radius: 5px;
  .keyboards-row {
    width: 100%;
    display: flex;
    justify-content: space-around;
    .keyboards-key {
      width: 100%;
      height: 56px;
      margin: 2px;
      padding: 5px;
      flex-grow: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      border: 1px solid #dedede;
      // border-radius: 4px;
      border-bottom: 1px solid #b5b5b5;
      border-radius: 5px;
      -webkit-box-shadow: 0 0 3px -1px rgba(0, 0, 0, 0.3);
      box-shadow: 0 0 3px -1px rgba(0, 0, 0, 0.3);
      cursor: pointer;
      font-size: 1.5em;
      font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Noto Sans CJK SC,
        WenQuanYi Micro Hei, Arial, sans-serif;
      font-weight: 400;
      background-color: #fdfdfd;
      // &:hover {
      //   box-shadow: 0 0 4px 2px #ccd1e7;
      // }
      &.keyboards-key--active {
        background-color: #e5e5e5;
      }
      // &.keyboards-key--number {
      //   width: 32%;
      // }
      &.keyboards-key--all {
        width: 9.1%;
      }
      &.keyboards-key--star {
        font-size: 2em;
      }
      &.keyboards-key--option {
        width: 20%;
      }
    }
  }
}
</style>

父组件

<el-form ref="modelForm" :model="modelForm" :rules="modelRules" label-width="60px" size="medium">
  <el-form-item label="输入框1"  prop="input1">
    <el-input
      id="input-input1"
      size="small"
      clearable
      v-model.trim="modelForm.input1"
      @focus="setInput('input1')"
      style="width: 100%"
    ></el-input>
  </el-form-item>
  <el-form-item label="输入框2" prop="input2">
    <el-input
      id="input-input2"
      size="small"
      maxlength="3"
      ref="input2"
      clearable
      v-model.trim="modelForm.input2"
      @focus="setInput('input2')"
    ></el-input>
  </el-form-item>
</el-form>
<softKeyBoard @onChange="onChange" type="number" :inputText="input" :inputDom="inputDom" />

<script>
export default {
  computed: {
    input() {
      if (this.activeInput) {
        return this.modelForm[this.activeInput];
      }
      return '';
    }
  },
  data() {
    return {
      activeInput: '',
    };
  },
  methods: {
    setInput(prop) {
      this.activeInput = prop;
    },
    onChange(input) {
      if (this.activeInput === 'input1') {
        input = input.slice(0, 7);
      }
      if (this.activeInput === 'input2') {
        input = input.slice(0, 3);
      }
      this.$set(this.modelForm, this.activeInput, input);
    },
  }
}
</script>

标签:vue,封装,elem,value,输入框,软键盘,key,return,type
From: https://www.cnblogs.com/code-R/p/17263875.html

相关文章

  • 记录--vue刷新当前页面
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助背景项目当中如果做新增/修改/删除等等操作通常情况下都需要刷新数据或者刷新当前页面.思路(1)如果......
  • vue-cookies用法
    importCookiesfrom'vue-cookies';constcookies={};cookies.set=function(name='default',value='',cookieSetting=60*60*24*365){Co......
  • vue全家桶进阶之路23:Element UI
    ElementUI是一套基于Vue.js的组件库,它提供了一系列常用的UI组件,包括表单、弹窗、布局、导航等等。ElementUI的设计风格简洁、易用、美观,且易于定制。ElementUI......
  • Spring boot 、Vue学习体会
    近期集中学习了Springboot、Vue等技术,学习过程也是不断碰壁,总的来说自认为有些涨进,抓住核心、深入关键、逐步剖析。两个技术分别负责后台和前端,学习后一个感受,两个技术......
  • Vue子组件向父组件传值(this.$emit()方法)
    子组件使用this.$emit()向父组件传值首先必须在父组件中引用子组件,然后实现传值第一步在父组件中引入子组件 importUnitByPurchaseAddOrUpdatefrom'@views/module......
  • vue图片上传前压缩图片
    前言需求:项目当中上传图片的需求点肯定有很多,再上传之后,如果图片很大的话,在加载的时候就会很慢。最近发现系统首次加载越来越慢,就开始思考怎么能降低这个加载时间,由于首页......
  • 第七章 工程化 - 实例体验 - 基于 vue框架 开发一个完整的组件库 一
    基于vue框架开发一个完整的组件库来体验前端工程化的魅力对一个组件库的开发来全面认识熟悉前端工程化的配置,系统的理解工程化中各个工具所起到的作用,并且将其最终可......
  • 第八章 工程化 - 实例体验 - 基于 vue框架 开发一个完整的组件库 二
    基础Monorepo环境建设包名选择与注册1、给组件库命名=>最终会发布到npm.js仓库2、查看组件库的命名是否可注册方法npmviewpackage-nameversion如......
  • vue全家桶进阶之路22:Vue CLI脚手架
    VueCLI是一个基于Vue.js的官方脚手架工具,它可以帮助我们快速创建和管理Vue.js项目,提供了一些工具和配置来帮助我们开发和调试Vue.js应用。一切框架都是为了将开发......
  • Vue学习总结笔记(六)【转载】
    Vue学习总结笔记(六)IT_Holmes已于 2022-03-0811:07:02 修改2061收藏19分类专栏:......