vue2 数字软键盘 封装 可拖动 使用简单

news2024/12/24 0:37:57

1、效果图 

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/1199776.html

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

相关文章

CS224W6.2——深度学习基础

在本文中&#xff0c;我们回顾了深度学习的概念和技术&#xff0c;这些概念和技术对理解图神经网络至关重要。从将机器学习表述为优化问题开始&#xff0c;介绍了目标函数、梯度下降、非线性和反向传播的概念。 文章目录 1. 大纲2. 优化问题2.1 举例损失函数 3. 如何优化目标函…

matlab Silink PID 手动调参

&#xff08;业余&#xff09;PID即比例积分微分&#xff0c;它将给定值r(t)与实际输出值y(t)的偏差的比例(P)、积分(I)、微分(D)通过线性组合形成控制量&#xff0c;对被控对象进行控制。我们先用matlab Silink弄一个简易的PID例子&#xff1a; 中间三条就是比例&#xff0c;积…

【Python】一篇带你掌握数据容器之列表

目录 前言&#xff1a; 一、列表 1.列表的定义 2.列表的下标索引 3.列表的常用操作 &#xff08;1&#xff09;index方法&#xff1a;查找某元素的下标 (2)修改特定位置下标的元素 &#xff08;3&#xff09;insert&#xff08;下标&#xff0c;元素&#xff09;方法&a…

C/C++调试工具 - gdb详解

C/C调试工具 -gdb详解 1 简介 2 常用的命令 3 使用的条件 4 程序调试 4.1 直接运行程序 4.2 断点调试(在某一行) 4.3 断点调试(在函数入口处打断点) 5 调试core文件 5.1 生成core文件的方法 5.2 调试core文件 1 简介 GDB是Linux下非常好用且强大的调试工具。GD…

Linux组调度

为什么引入组调度可以参考这篇文章的讨论。核心原因是基础的调度算法都是基于任务的&#xff0c;如果用户A有10个任务&#xff0c;用户B只有1个任务&#xff0c;假设这些任务的优先级都相同&#xff0c;那么用户A得到的CPU时间将是用户B的10倍&#xff0c;这样从任务的角度看虽…

Mac Qt 5.13.2无法加载文件

在Mac OS 14.0系统上&#xff0c;离线安装了Qt5.13.2&#xff0c;但是新建一个工程&#xff0c;却无法正常使用&#xff0c;只能加载出pro文件&#xff0c;其他文件都加载不出来&#xff0c;提示错误&#xff1a;Project ERROR: failed to parse default search paths from com…

手机号验证码登录

登录入口 1.app 正常登录入口 2.app 网页登录&#xff0c;比如分享直播卡片时&#xff0c;进入直播间需要先进行登录 3.pc 登录 一&#xff0c;app常见的登录方式 1.手机号验证码登录 2.用户名密码登录 3.一键登录 二&#xff0c;手机验证码登录示意图 三&#xff0c;流程 0.登…

No178.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

已解决:java.net.BindException: 地址已在使用

解决zookeeper报错&#xff1a;java.net.BindException: 地址已在使用&#xff0c;是因为端口被占用。显示Starting zookeeper ... STARTED&#xff0c;jps没有QuorumPeerMain进程。 问题截图&#xff1a; 看似Starting zookeeper ... STARTED&#xff0c;实则集群并没有启动…

Linux 程序开发流程 / 基本开发工具 / Vim / GCC工具链 / Make 工具 / Makefile 模板

编辑整理 by Staok。 本文部分内容摘自 “100ask imx6ull” 开发板的配套资料&#xff08;如 百问网的《嵌入式Linux应用开发完全手册》&#xff0c;在 百问网 imx6ull pro 开发板 页面 中的《2.1 100ASK_IMX6ULL_PRO&#xff1a;开发板资料》或《2.2 全系列Linux教程&#xf…

华为ensp:rip宣告

ip全部配置好 R1 进入r1视图模式 rip network 192.168.1.0 network 1.0.0.0 R2 进入r2视图模式 rip network 192.168.2.0 network 1.0.0.0 这样就完成了宣告 display ip routing-table 查看路由表

Java基础——数组(一维数组与二维数组)

文章目录 一维数组声明初始化与赋值内存图解 二维数组声明初始化与赋值内存图解 数组练习 数组是多个相同类型的数据按一定顺序排列的集合。 说明&#xff1a; 数组是引用数据类型&#xff0c;数组的元素是同一类型的任何数据类型&#xff0c;包括基本数据类型和引用数据类型…

基于YOLOv8的输电线路异物识别算法应用

基于 YOLOv8 的输电线路异物识别算法应用 输电线路作为电力系统的重要一环&#xff0c;保证其安全稳定运行是十分必要的。由于长期暴露于室外&#xff0c;线路所面临的不安全因素繁多&#xff0c;异物入侵便是其中之一。异物可能会引起线路短路甚至诱发火灾&#xff0c;因此要加…

使用3D Touch,让你左右逢源,操作更自然

本文介绍了如何在苹果设备上使用3D Touch&#xff0c;以及哪些应用程序支持该工具。3D Touch在Apple Watch上也称为Force Touch&#xff0c;在iPhone XR上也称为Haptic Touch。 如何改变3D触摸的灵敏度 按照以下步骤调整3D Touch的灵敏度&#xff1a; 1、打开“设置”应用程…

docker安装AWVS 23.9.231005181

本文声明仅AWVS用作学习使用 将镜像文件secfa_awvs.tar复制到目标机器上。 我的百度网盘文件路径&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1frbOH4UZlMz9bMXyZs1o0g 提取码&#xff1a;na6y –来自百度网盘超级会员V6的分享 在目标机器上&#xff0c;使用以下命…

原码补码相关运算

求补码步骤 原补转换 -127为负数&#xff0c;其补码为原码01111111&#xff0c;取反10000000&#xff0c;加一&#xff0c;10000001。 例如&#xff1a; 【-1】原码 10000001 反码bai11111110 补码duzhi 11111111 【3】原码 00000011 反码 00000011 补码 00000011 【-127】…

【多线程】

文章目录 概念一、线程的生命周期图二、线程的创建方式一方式二线程API线程优先级sleep阻塞守护线程多线程并发安全问题 总结 概念 线程:一个顺序的单一的程序执行流程就是一个线程。代码一句一句的有先后顺序的执行。多线程:多个单一顺序执行的流程并发运行。造成"感官上…

算法——滑动窗口

什么是窗口&#xff1f;就是符合题目要求的区域内的数据&#xff0c;将每次符合数据的窗口内的数据记录下来&#xff0c;然后将窗口后移&#xff0c;寻找其他符合要求的数据&#xff0c;每次进入窗口和退出窗口都需要一定的要求 一、 LCR 008. 长度最小的子数组 - 力扣&#…

Git之分支与版本->课程目标及知识点的应用场景,分支的场景应用,标签的场景应用

1.课程目标及知识点的应用场景 Git分支和标签的命名规范 分支 dev/test/pre/pro(即master) dev:开发环境--windows (自己的电脑) test:测试环境--windows/linux (公司专门的测试电脑 pre:灰度环境(非常大的公司非常重要的项目) pro:正式环境 灰度环境与正式环境的服务器配置…

论文笔记:Deep Trajectory Recovery with Fine-Grained Calibration using Kalman Filter

TKDE 2021 1 intro 1.1 背景 用户轨迹数据对于改进以用户为中心的应用程序很有用 POI推荐城市规划路线规划由于设备和环境的限制&#xff0c;许多轨迹以低采样率记录 采样的轨迹无法详细说明物体的实际路线增加了轨迹中两个连续采样点之间的不确定性——>开发有效的算法以…