vue 数字软键盘 插件 封装 可拖动

news2025/1/12 6:08:36

1、效果图 

4341ddb9a2c64ad194c71f6d4d8ea940.gif

2、使用方式

<Keyboard v-if="show" @close="show = false" :inputDom="$refs.input" />

封装的数字键盘 Keyboard.vue 组件代码

<template>
  <div
    class="keyboard"
    ref="keyboard"
    :style="{ left: moveX + 'px', bottom: moveY + 'px' }"
  >
    <div class="drag" @mousedown="keyDown">
      <p></p>
      <div @click="$emit('close')" @mousedown.stop @mousemove.stop>
        <img src="./arrow.svg" alt="" />
      </div>
    </div>
    <div class="main">
      <div class="left">
        <div
          v-for="text in symbols"
          :key="text"
          @click="insertTxtAndSetcursor(text)"
        >
          {{ text }}
        </div>
      </div>
      <div class="right">
        <div class="left">
          <div
            class="item"
            v-for="i in 9"
            :key="i"
            @click="insertTxtAndSetcursor(i)"
          >
            {{ i }}
          </div>
        </div>
        <div class="right">
          <div class="item" @click="insertTxtAndSetcursor('', true)">
            <img src="./delete.svg" alt="" />
          </div>
          <div class="item" @click="insertTxtAndSetcursor(' ')">
            <img src="./blank.svg" alt="" />
          </div>
          <div class="item" @click="insertTxtAndSetcursor(0)">0</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script scoped>
export default {
  data() {
    return {
      symbols: ["+", "-", "=", ".", "/", "@"],
      flag: false,
      seto: null,
      downInfo: {},
      moveX: 0,
      moveY: 0,
    };
  },
  props: {
    inputDom: {
      type: Node,
      default: null,
    },
  },
  mounted() {
    document.addEventListener("mousemove", this.keyMove);
  },
  methods: {
    // 输入文本
    insertTxtAndSetcursor(text, del) {
      let element = this.inputDom; // 获取到指定标签
      let startPos = element.selectionStart; // 获取光标开始的位置
      let endPos = element.selectionEnd; // 获取光标结束的位置
      if (startPos === undefined || endPos === undefined) return; // 如果没有光标位置 不操作
      let oldTxt = element.value; // 获取输入框的文本内容
      let result = "";
      // 光标位置不能小于0
      const num = startPos - 1;
      if (del && num >= 0) {
        result = oldTxt.substring(0, startPos - 1) + oldTxt.substring(endPos); // 将文本插入
      } else {
        result =
          oldTxt.substring(0, startPos) + text + oldTxt.substring(endPos); // 将文本插入
      }
      element.value = result; // 将拼接好的文本设置为输入框的值
      element.focus(); // 重新聚焦输入框
      if (del && num >= 0) {
        element.selectionStart = startPos - 1 + (text + "").length; // 设置光标开始的位置
        element.selectionEnd = startPos - 1 + (text + "").length; // 设置光标结束的位置
      } else {
        element.selectionStart = startPos + (text + "").length; // 设置光标开始的位置
        element.selectionEnd = startPos + (text + "").length; // 设置光标结束的位置
      }
    },
    keyUp() {
      this.flag = false;
      document.removeEventListener("mouseup", this.keyUp);
      document.removeEventListener("mouseleave", this.keyUp);
    },
    keyDown(e) {
      this.downInfo.x = e.pageX;
      this.downInfo.y = e.pageY;
      this.downInfo.left = this.moveX;
      this.downInfo.bottom = this.moveY;
      this.seto = setTimeout(() => {
        this.flag = true;
        document.addEventListener("mouseup", this.keyUp);
        document.addEventListener("mouseleave", this.keyUp);
        clearTimeout(this.seto);
      }, 1000);
    },
    keyMove(e) {
      if (this.flag) {
        const maxh =
          (document.clientHeight ||
            document.documentElement.clientHeight ||
            document.body.clientHeight) - this.$refs.keyboard.clientHeight;
        const htj = this.downInfo.bottom + this.downInfo.y - e.pageY;
        const maxw =
          (document.clientWidth ||
            document.documentElement.clientWidth ||
            document.body.clientWidth) - this.$refs.keyboard.clientWidth;
        const wtj = this.downInfo.left - (this.downInfo.x - e.pageX);
        if (wtj <= maxw && wtj >= 0) {
          //确保键盘始终在屏幕可见范围内
          this.moveX = wtj;
        }
        if (htj <= maxh && htj >= 0) {
          //确保键盘始终在屏幕可见范围内
          this.moveY = htj;
        }
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.keyboard {
  width: 100vw;
  height: 245px;
  max-width: 353px;
  min-width: 285px;
  position: fixed;
  bottom: 0;
  left: 0;
  background-color: #d6d7db;
  > .drag {
    width: 100%;
    height: 15%;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    > p {
      width: 30%;
      height: 13%;
      border-radius: 5px;
      background-color: #fff;
    }
    > div {
      width: 18.3%;
      height: 100%;
      position: absolute;
      top: 50%;
      right: 0;
      transform: translateY(-50%);
      &::before {
        width: 1px;
        content: "";
        height: 60%;
        background-color: #fff;
        position: absolute;
        top: 50%;
        left: 0;
        transform: translateY(-50%);
      }
      > img {
        user-select: none;
        width: 45%;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
      }
    }
  }
  > .main {
    height: calc(100% - 15%);
    display: flex;
    justify-content: space-between;
    padding: 2%;
    > .left {
      flex: 15;
      margin-right: 2%;
      height: 100%;
      border-radius: 6px;
      background-color: #fff;
      overflow: auto;
      user-select: none;
      &::-webkit-scrollbar {
        display: none;
      }

      > div {
        font-size: 20px;
        height: 25%;
        display: flex;
        align-items: center;
        justify-content: center;
        &:active {
          background-color: #a1a8b8;
        }
      }
    }
    > .right {
      height: 100%;
      border-radius: 5px;
      flex: 77;
      display: flex;
      justify-content: space-between;
      user-select: none;
      > .left {
        height: 100%;
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
        align-content: space-between;
        width: 77%;
        > .item {
          background-color: #fff;
          height: 30.8%;
          width: 31.5%;
          display: flex;
          align-items: center;
          justify-content: center;
          border-radius: 5px;
          font-size: 18px;
          &:active {
            background-color: #adb4be;
          }
          &:nth-of-type(3n) {
            margin-right: 0;
          }
          &:nth-of-type(7),
          &:nth-of-type(8),
          &:nth-of-type(9) {
            margin-bottom: 0;
          }
        }
      }
      > .right {
        width: 21%;
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        > .item {
          border-radius: 5px;
          display: flex;
          align-items: center;
          justify-content: center;
          height: 30.8%;
          background-color: #adb4be;
          > img {
            width: 40%;
          }
          &:active {
            background-color: #7e8492;
          }
        }
      }
    }
  }
}
</style>

3、使用方式代码 

<template>
  <div id="app">
    <input ref="input" type="text" @focus="show = true" v-model="text" />
    <Keyboard v-if="show" @close="show = false" :inputDom="$refs.input" />
  </div>
</template>

<script scoped>
import Keyboard from "./Keyboard.vue";
export default {
  components: { Keyboard },
  data() {
    return { show: false, text: "" };
  },
};
</script>

<style lang="scss" scoped>
#app {
  width: 100vw;
  height: 100vh;
  background-color: #000;
  > input {
    height: 25px;
    display: block;
    margin: 0 auto;
  }
}
</style>

4、完结 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1203476.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

日本it培训班,如何选择靠谱的赴日IT培训班?

随着科技的发展&#xff0c;信息技术行业在全球范围内迅速发展&#xff0c;并呈现出蓬勃的发展态势&#xff0c;在日本&#xff0c;IT行业也成为一种极为热门的职业选择。日本专门学校在这个领域内培养了许多IT从业者&#xff0c;成为了众多IT公司的培养基地。如果你对IT产业感…

【前端异常】JavaScript错误处理:分析 Uncaught(in promise) error

这里写目录标题 一、Promise是什么二、什么是 Uncaught(in promise) error三、解决方案3.1 使用catch方法处理Promise的错误3.2 使用 async/await 处理Promise的错误3.3 全局异常处理 四、结论 在开发过程中&#xff0c;JavaScript的错误处理是一个老生常谈的话题。当应用程序发…

AI机器人软件定制流程

一、项目概述 AI机器人软件定制流程是根据客户的需求&#xff0c;定制开发一款具有人工智能功能的机器人软件。本方案将详细介绍AI机器人软件定制的整个流程&#xff0c;包括需求分析、设计、开发、测试和交付等环节。 二、需求分析 在定制AI机器人软件之前&#xff0c;需要…

Linux系统上配置MySQL自动备份

1、编写Shell脚本&#xff0c;并保存为.sh文件 #!/bin/bash# 获取当前日期和时间 current_date$(date %Y%m%d) current_time$(date %H%M%S)# 设置备份文件名 path"/usr/local/mysql5.7/bak" bakFileName"dbname_backup_${current_date}_${current_time}.sql&qu…

阿里云国际站:应用实时监控服务

文章目录 一、阿里云应用实时监控服务的概念 二、阿里云应用实时监控服务的优势 三、阿里云应用实时监控服务的功能 四、写在最后 一、阿里云应用实时监控服务的概念 应用实时监控服务 (Application Real-Time Monitoring Service) 作为一款云原生可观测产品平台&#xff…

React Native简介 说明为什么要学习React Native

首先 什么是 React Native &#xff1f; React Native 是 Facebook 在 React.js Conf 2015 上推出了开源框架 React Native (简称 RN)是 React 的一个原生 (Native) 扩展 它允许我们通过 React 语法&#xff0c;来开发ios 和Android 原生应用 简单说 由Facebook发布 是一种Re…

笔尖笔帽检测1:笔尖笔帽检测数据集(含下载链接)

笔尖笔帽检测1&#xff1a;笔尖笔帽检测数据集(含下载链接) 目录 笔尖笔帽检测1&#xff1a;笔尖笔帽检测数据集(含下载链接) 1. 前言 2. 手笔检测数据集 &#xff08;1&#xff09;Hand-voc1 &#xff08;2&#xff09;Hand-voc2 &#xff08;3&#xff09;Hand-voc3 …

【OpenCV(3)】linux arm aarch 是 opencv 交叉编译与使用

文章目录 1、直接找github 别人编译好的2、自主编译参考 3使用CMake检查 参考 1、直接找github 别人编译好的 测试很多&#xff0c;找到一个可用的。 https://github.com/dog-qiuqiu/libopencv 它用了超级模块&#xff01; OpenCV的world模块也称为超级模块&#xff08;supe…

gStore入选BenchCouncil年度世界开源系统杰出成果

“只以贡献分高下” BenchCouncil&#xff08;国际测试委员会&#xff09; 邀请了多位独立科学家 从2022至2023年度数万项开源相关成果中 遴选出了102项代表性成果 在确定主要贡献者的基础上 产生了开源领域 年度人才榜、机构榜、国家榜 共195人进入榜单 中国在“开源…

Marin说PCB之 PCB封装和原理图封装的藕断丝连

最近天气开始降温了&#xff0c;小编我不得不拿出珍藏多年的秋裤穿上了&#xff0c;就是走路不太方便&#xff0c;有点紧啊&#xff0c;可能是当时衣服尺码买小了吧&#xff0c;不可能是我吃胖了&#xff0c;这个绝对不可能。 话说小编我今年属实有点走霉运啊&#xff0c;下班和…

Camtasia2024全新中文版电脑录屏工具

在这个视频的大舞台上&#xff0c;每一帧都是你炫耀的机会&#xff0c;每一秒都是让观众瞪大眼睛的瞬间。现在&#xff0c;让我们一起飞跃时空&#xff0c;用更少的时间创作更多的惊喜吧&#xff01; 就算你是个小白&#xff0c;毫无经验&#xff0c;别担心&#xff0c;Camtas…

Jmeter添加变量的四种方法

一、在样本中添加同请求一起发送的参数。根据服务器设置的数据类型&#xff0c;来添加不同类型的参数 二、用户定义的变量 1、创建&#xff1a;添加->配置元件->用户定义的变量 2、作用&#xff1a;当前的线程组内所有Sampler都可以引用变量&#xff0c;方便脚本更新&a…

2023年阿里云服务器最新日常价、活动价格、可使用优惠券金额及券后价格参考

阿里云服务器最新实际购买价格参考&#xff0c;轻量应用服务器2核2G3M带宽配置日常价720.00元/1年&#xff0c;最新活动价格为87元/1年&#xff0c;订单满300元以上即可使用满减优惠券&#xff0c;例如经济型e实例2核4G2M带宽日常价格为1802.40元&#xff0c;最新的活动价格为8…

从GPT定制到Turbo升级再到Assistants API,未来AI世界,你准备好了吗?

引言 在OpenAI DevDay发布会上&#xff0c;OpenAI再次震撼整个人工智能行业&#xff0c;为AI领域带来了重大的更新。CEO Sam Altman宣布推出了定制版本的ChatGPT&#xff0c;这意味着用户现在可以根据自己的需求打造个性化的GPT&#xff0c;并分享至GPT Store。这一消息对于受A…

C++网络编程库编写自动爬虫程序

首先&#xff0c;我们需要使用 C 的网络编程库来编写这个爬虫程序。以下是一个简单的示例&#xff1a; #include <iostream> #include <string> #include <curl/curl.h> #include <openssl/ssl.h>const char* proxy_host "duoip"; const in…

sd-wan网速测试:如何测试sd-wan网速?

SD-WAN是一种新兴的网络技术&#xff0c;可以显著提高企业的网络连接速度和性能。在当今的数字时代&#xff0c; 网络连接的质量对企业的运营至关重要。因此&#xff0c;sd-wan的网络速度测试尤为重要。 在进行sd-wan网速测试之前&#xff0c;我们首先需要知道什么是sd-wan-wa…

二十七、W5100S/W5500+RP2040树莓派Pico<iperf 测速示例>

文章目录 1 前言2 简介2 .1 什么是网络测速技术&#xff1f;2.2 网络测速技术的优点2.3 网络测速技术数据交互原理2.4 网络测速应用场景 3 WIZnet以太网芯片4 示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言…

全国不同级别高炉炼铁主要操作指标与分析

参考网址&#xff1a;https://www.zgltw.cn/liantiexinjishu/2020/0114/23584.html &#xff08;中国炼铁网&#xff09; 参考网址&#xff1a;https://www.zgltw.cn/liantiexinjishu/2020/0114/23584.html &#xff08;中国炼铁网 世界金属导报&#xff09;

Verilog基础:三段式状态机与输出寄存

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html 对于Verilog HDL而言&#xff0c;有限状态机(FSM)是一种重要而强大的模块&#xff0c;常见的有限状态机书写方式可以分为一段式&#xff0c;二段式和三段式&#xff0c;笔者强烈建议使用三…

JAVA弑神大阵之装饰者大阵

架构说明 构成简述&#xff1a; 总接口&#xff1a; 装饰者跟被装饰者都要来实现他&#xff08;或者理解成父接口&#xff09;&#xff0c;作用&#xff1a;对被装饰者做转换 被装饰者&#xff1a; 此处实现总接口。什么都不需要动&#xff0c;他只是被增强的功能&#xff0…