Vue实现快捷键录入功能的示例代码

项目需要在页面使用快捷键,而且需要对快捷键进行维护,然后参考了此篇文章,改成自己的。

记录一下。

首先有一个组件,用来实现快捷键的录入操作。

直接上代码:

hotkeyInput.vue

<doc>
  快捷键输入框 —— 用于快捷键的录入
</doc>
<template>
  <div class="shortcut-key-input" :class="{ cursor: focus }" :style="$props.style" tabindex="0" @focus="handleFocus"
    @blur="focus = false" @keydown="handleKeydown">
    <template v-if="list.length">
      <template v-for="(item, index) in list">
        <span :key="`${item.text}_${index}`">{{ item.text }} <i @click="handleDeleteKey(index)"></i></span>
      </template>
    </template>
    <div v-else class="placeholder">{{ placeholder }}</div>
  </div>
</template>

<script>
  const CODE_NUMBER = Array.from({ length: 10 }, (v, k) => `Digit${k + 1}`);
  const CODE_NUMPAD = Array.from({ length: 10 }, (v, k) => `Numpad${k + 1}`);
  const CODE_ABC = Array.from(
    { length: 26 },
    (v, k) => `Key${String.fromCharCode(k + 65).toUpperCase()}`
  );
  const CODE_FN = Array.from({ length: 12 }, (v, k) => `F${k + 1}`);
  const CODE_CONTROL = [
    "Shift",
    "ShiftLeft",
    "ShiftRight",
    "Control",
    "ControlLeft",
    "ControlRight",
    "Alt",
    "AltLeft",
    "AltRight",
  ]; // ShiftKey Control(Ctrl) Alt

  export default {
    name: "HotKeyInput",
    props: {
      // 默认绑定值
      // 传入 ['Ctrl+d'] 格式时会自动处理成 [{ text: 'Ctrl+d', controlKey: { altKey: false, ctrlKey: true, shiftKey: false, key: 'd', code: 'KeyD } }]
      hotkey: {
        type: Array,
        required: true,
      },
      // 校验函数 判断是否允许显示快捷键
      verify: {
        type: Function,
        default: () => true,
      },
      // 无绑定时提示文字
      placeholder: {
        type: String,
        default: "",
      },
      // 限制最大数量
      max: {
        type: [String, Number],
        default: 1,
      },
      // 快捷键使用范围
      range: {
        type: Array,
        default: () => ["NUMBER", "NUMPAD", "ABC", "FN"],
      },
    },
    data() {
      return {
        focus: false,
        list: this.hotkey,
        keyRange: [],
      };
    },
    watch: {
      list: function (list) {
        if (list.length) this.focus = false;
        this.$emit("update:hotkey", this.list);
      },
      hotkey: {
        handler: function (val) {
          if (!val.length) return;
          const list = [];
          val.forEach((item) => {
            const arr = item.split("+");
            const controlKey = {
              altKey: arr.includes("Alt"),
              ctrlKey: arr.includes("Control"),
              shiftKey: arr.includes("Shift"),
              key: arr[arr.length - 1],
              code: `Key${arr[arr.length - 1].toUpperCase()}`,
            };
            list.push({
              text: arr.reduce((text, item, i) => {
                if (i) text += "+";
                if (controlKey.key === item) text += item.toUpperCase();
                else text += item;
                return text;
              }, ""),
              controlKey,
            });
          });
          this.list = list;
        },
        immediate: true,
      },
      range: {
        handler: function (val) {
          const keyRangeList = {
            NUMBER: CODE_NUMBER,
            NUMPAD: CODE_NUMPAD,
            ABC: CODE_ABC,
            FN: CODE_FN,
          };
          val.forEach((item) => {
            this.keyRange = this.keyRange.concat(
              keyRangeList[item.toUpperCase()]
            );
          });
        },
        immediate: true,
      },
    },
    methods: {
      handleFocus() {
        if (!this.list.length) this.focus = true;
      },
      handleDeleteKey(index) {
        this.list.splice(index, 1);
      },
      handleKeydown(e) {
        const { altKey, ctrlKey, shiftKey, key, code } = e;
        if (!CODE_CONTROL.includes(key)) {
          if (!this.keyRange.includes(code)) return;
          let controlKey = "";
          [
            { key: altKey, text: "Alt" },
            { key: ctrlKey, text: "Ctrl" },
            { key: shiftKey, text: "Shift" },
          ].forEach((curKey) => {
            if (curKey.key) {
              if (controlKey) controlKey += "+";
              controlKey += curKey.text;
            }
          });
          if (key) {
            if (controlKey) controlKey += "+";
            controlKey += key.toUpperCase();
          }
          this.addHotkey({
            text: controlKey,
            controlKey: { altKey, ctrlKey, shiftKey, key, code },
          });
        }
        e.preventDefault();
      },
      addHotkey(data) {
        if (this.list.length && this.list.some((item) => data.text === item.text))
          return;
        if (
          this.list.length &&
          this.list.length.toString() === this.max.toString()
        )
          return;
        this.list.push(data);
      },
    },
  };
</script>

<style scoped>
  @keyframes Blink {
    0% {
      opacity: 0;
    }

    100% {
      opacity: 1;
    }
  }

  .shortcut-key-input {
    position: relative;
    border: 1px solid #dcdcdc;
    border-radius: 4px;
    background-color: #fff;
    color: #333;
    width: 100%;
    height: 40px;
    /* padding: 2px 0; */
    cursor: text;
    transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
  }

  .shortcut-key-input:focus {
    border-color: #188cff;
    box-shadow: 0 0 4px rgba(24, 140, 255, 0.38);
  }

  .shortcut-key-input.cursor::after {
    content: "|";
    animation: Blink 1.2s ease 0s infinite;
    font-size: 18px;
    position: absolute;
    top: 2px;
    left: 12px;
  }

  .shortcut-key-input span {
    position: relative;
    display: inline-block;
    box-sizing: border-box;
    background-color: #f4f4f5;
    border-color: #e9e9eb;
    color: #909399;
    padding: 0 22px 0 8px;
    height: 28px;
    font-size: 13px;
    line-height: 28px;
    border-radius: 4px;
    margin: 5px;
  }

  .shortcut-key-input .placeholder {
    position: absolute;
    top: 10px;
    left: 11px;
    color: #c0c4cc;
    font-size: 13px;
    text-indent: 4px;
    font: 400 13.3333px Arial;
  }

  .shortcut-key-input span i {
    position: absolute;
    top: 6px;
    right: 4px;
    content: "";
    background: url("data:image/svg+xml,%3Csvg class='icon' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cpath d='M512 64C264.58 64 64 264.58 64 512s200.58 448 448 448 448-200.58 448-448S759.42 64 512 64zm0 832c-212.08 0-384-171.92-384-384s171.92-384 384-384 384 171.92 384 384-171.92 384-384 384z' fill='%23909399'/%3E%3Cpath d='M625.14 353.61L512 466.75 398.86 353.61a32 32 0 0 0-45.25 45.25L466.75 512 353.61 625.14a32 32 0 0 0 45.25 45.25L512 557.25l113.14 113.14a32 32 0 0 0 45.25-45.25L557.25 512l113.14-113.14a32 32 0 0 0-45.25-45.25z' fill='%23909399'/%3E%3C/svg%3E") no-repeat center;
    background-size: contain;
    width: 14px;
    height: 14px;
    transform: scale(0.9);
    opacity: 0.6;
  }

  .shortcut-key-input span i:hover {
    cursor: pointer;
    opacity: 1;
  }
</style>

然后需要的地方引用一下。

  import hotkeyInput from '@/views/modules/hotkeyInput'
  components: {
      hotkeyInput,
    },
<hotkey-input v-if="dialogVisible" :hotkey.sync="form.shortcutKey" placeholder="请按需要绑定的按键,支持组合按键"></hotkey-input>

但是吧,选择之后的数据是这个样子的:

到此这篇关于Vue实现快捷键录入功能的示例代码的文章就介绍到这了,更多相关Vue快捷键录入内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue实现一个获取按键展示快捷键效果的Input组件

    遇到一个需求,页面内要自定义快捷键,这就需要可以有地方设置和展示快捷键,找了一圈Element UI发现没有能稍微改改就能用的组件,所以自己动手写了一个. 这个只有快捷键展示功能,快捷键实际绑定生效的话是依赖传回的快捷键数据,由另外的组件处理的.目前只测试了Chrome的环境. 效果如下: 关键点 虽然看起来像是一个Input但在组件内实际上是展示一个标签效果,还需要有删除按钮.这就得在输入框内放下html代码,浏览器的Input组件显然不适合,这就只能自己仿一个类Input组件效果了. foc

  • vue快捷键与基础指令详解

    v-bind可以简写成   : <img src="{{url}}">→<img :src="url" :width="50px"> v-on:click可以写成@click <button @click="up()"></button> v-if实例  可以通过对对象操作条件来实现想要展示的效果 <!DOCTYPE html> <html> <he

  • Vue实现快捷键录入功能的示例代码

    项目需要在页面使用快捷键,而且需要对快捷键进行维护,然后参考了此篇文章,改成自己的. 记录一下. 首先有一个组件,用来实现快捷键的录入操作. 直接上代码: hotkeyInput.vue <doc> 快捷键输入框 -- 用于快捷键的录入 </doc> <template> <div class="shortcut-key-input" :class="{ cursor: focus }" :style="$prop

  • 基于vue的换肤功能的示例代码

    最近在做的一个几月vue的移动端小demo,其中有一块是实现各个页面的统一换肤功能的.想着写一篇文章,来写一写实现过程中遇到的一些问题. 项目github地址 项目github地址 一 先看一下实现效果吧 设置主题颜色 讲道理这么一个功能,我觉得这么几点可以说下,分步实现: 1. 色值的选取 2. scss 的一些小众用法(多变量CSS值的批量设置) 3. 全局事件巴士的应用 1 色值的选取和原则 推荐大家看下蚂蚁金服的设计指引,里面对常见的交互和界面设计有一套不错的指引和建议,喜欢看书的也可以

  • vue 左滑删除功能的示例代码

    最近有个需求是要添加一个左滑删除的功能.参考了一下别的老哥的代码,做了一点点改进.记录一下.以备不时之需,话不多说 ,上代码 <template> <div class="slider-item"> <div class="content" @touchstart='touchStart' @touchmove='touchMove' @touchend='touchEnd' :style="deleteSlider"

  • VUE饿了么树形控件添加增删改功能的示例代码

    本文介绍了VUE饿了么树形控件添加增删改功能的示例代码,分享给大家,具体如下: element-ui树形控件:地址 在原文档中有个案例是有新增和删除功能,但是后来发现其修改的数据并不能直接影响到树形数据,所以采用了 render-content 的API重新写了个组件. 写个开发的步骤,所以文章比较长emmm 大致效果如图: 1.省市API 在网上复制了个省市的list,有两个属性是新增的 isEdit :控制编辑状态 maxexpandId :为现下id的最大值 export default{

  • vue实现禁止浏览器记住密码功能的示例代码

    查找资料 网上查到的一些方法: 使用 autocomplete="off"(现代浏览器许多都不支持) 使用 autocomplete="new-password" 在真正的账号密码框之前增加相同 name 的 input 框 使用 readonly 属性,在聚焦时移除该属性 初始化 input 框的 type 属性为 text,聚焦时修改为 password 使用 type="text",手动替换文本框内容为星号 "*" 或者

  • Vue实现输入框@功能的示例代码

    目录 前言 成员列表 创建 使用 输入框 获取光标的坐标 保存光标 插入文本 运行结果 总结 前言 前几篇文章中分别介绍了如何实现聊天输入框的双向绑定.回车键发送.粘贴文本图片等功能,本着完善输入框的目的,文本重点介绍聊天框如何实现@功能. 文章回顾: Vue实现contenteditable元素双向绑定的方法详解 Vue实现输入框回车发送和粘贴文本与图片功能 首先需要先理清思路: 成员列表组件,需要根据光标的位置调整,点击成员项时回调成员信息 获取光标的位置坐标(x值,y值) 输入框失焦时记录

  • Vue后台实现点击图片放大功能的示例代码

    目录 需求 代码 父组件 子组件 dom.js util.js types.js 需求 点击小图可以放大,放大后,通过手势等比例放大缩小.左右切换图.旋转.关闭.由于element-ui版本较低不支持使用图片放大的image组件. 代码 父组件 <template> <div> <!-- 放大图 --> <el-image-viewer v-if="showImg" :on-close="closeViewer" :src=

  • vue制作抓娃娃机的示例代码

    去年为联通制作双十一活动,做四个小游戏:'配对消消乐'.移动拼图.抓娃娃.倒计时. 现在先做来分享一下制作抓娃娃游戏时的经验 先上效果图 游戏规则:在指定时间内抓到上图四张卡片为挑战成功. 现在直接说游戏主要内容:娃娃滚动.爪子向下抓取.抓到卡片 废话不多说直接上代码!(此样式是根据需求而定) <!--布局样式--> <div class="game"> <!--爪子--> <div class="paw"> <

  • vue实现lodop打印功能的示例

    1.官网下载 http://www.lodop.net/download.html 2.解压安装运行 3.vue部分实现 3.1将lodopDuncs.js文件放入工程中,具体操作可见:http://www.lodop.net/faq/pp35.html 3.2 编写代码 <template> <div class="hello"> <button class="print-btn" v-on:click="btnClickP

  • vue实现菜单权限控制的示例代码

    大家在做后台管理系统时一般都会涉及到菜单的权限控制问题.当然解决问题的方法无非两种--前端控制和后端控制.我们公司这边的产品迭代速度较快,所以我们是从前端控制路由迭代到后端控制路由.下面我会分别介绍这两种方法的优缺点以及如何实现(不熟悉vue-router API的同学可以先去官网看一波API哈). 我先简单说下项目的需求:如下图所示,有一级菜单和二级菜单,然后不同的人登录进去会展示不同的菜单. 前端控制路由的思路:将所有的路由映射表都拿到前端来维护,就是我的router.js里面将所有的菜单p

随机推荐