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

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、完结 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法通关村第八关-白银挑战二叉树的深度和高度问题

大家好我是苏麟 , 今天说说几道二叉树深度和高度相关的题目 . LeetCode给我们造了一堆的题目&#xff0c;研究一下104、110和111三个题&#xff0c;这三个颗看起来挺像的&#xff0c;都是关于深度、高度的。 最大深度问题 描述 : 二叉树的 最大深度 是指从根节点到最远叶子…

SharePoint 是什么

SharePoint 平台使您能够以在线方式和本地方式轻松地管理和协调业务数据。因为其灵活性和易使用性&#xff0c;公司可以快速采用SharePoint来管理其业务数据。 SharePoint Microsoft 365 一种基于云的服务&#xff0c;由 Microsoft 托管&#xff0c;适用于各种规模的企业。 任何…

【Redis】redis-server和redis-cli

上一篇《redis 的下载和安装》 https://blog.csdn.net/m0_67930426/article/details/134341071?spm1001.2014.3001.5501 安装完之后开始使用 打开客户端之前需要先打开服务端 redis-server 直接使用该命令打开就行 然后在打开客户端 redis-cli 使用ping命令查看是否连接服…

云原生 黑马Kubernetes教程(K8S教程)笔记——kubernetes介绍。Master集群控制节点、Node工作负载节点、Pod控制单元

参考文章&#xff1a;kubernetes介绍 文章目录 1. Kubernetes介绍1.1 应用部署方式演变传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上虚拟化部署&#xff1a;可以在一台物理机上运行多个虚拟机&#xff0c;每个虚拟机都是独立的一个环境&#xff…

如何提升管理组织能力?

组织能力能力属于管理能力中的一部分&#xff0c;所以也称之为管理组织能力&#xff0c;组织是将人和事物的组合&#xff0c;有效的梳理和导向结果的能力。每个人都有组织能力&#xff0c;只是能力和效率上存在较大的差异。 一人的组织能力从学生时代就能体现出来&#xff0c;…

华为ensp:vrrp双机热备负载均衡

现在接口ip都已经配置完了&#xff0c;直接去配置vrrp r1上192.168.1.100 作为主 192.168.2.100作为副 r2上192.168.1.199 作为副 192.168.2.100作为主 这样就实现了负载均衡&#xff0c;如果两个都正常运行时&#xff0c;r1作为1.1的网关&#xff0c;r2作为2.1网关…

springboot高校全流程考勤系统-计算机毕设 附源码 27637

Springboot高校全流程考勤系统 摘 要 本文针对高校考勤等问题&#xff0c;对其进行研究分析&#xff0c;然后开发设计出高校全流程考勤系统以解决问题。高校全流程考勤系统系统主要功能模块包括&#xff1a;考勤签到、课程信息、考勤情况、申请记录列表等&#xff0c;系统功能设…

OpenWRT浅尝 / 基于RAVPower-WD009便携路由文件宝的旁路网关配置

目录 前言需求分析手头的设备家庭网络拓扑图旁路网关配置OpenWRT固件选择OpenWRT固件刷入旁路网关配置流程 旁路网关的使用前置工作日常存储/关键备份内网穿透24小时待命下载器 前言 近期由于个人需求&#xff0c;需要一台OpenWRT设备实现一些功能。所以本文主要还是为了自己后…

堆的应用-----Top k 问题

目录 前言 Topk问题 1.问题描述 2.解决方法 3.代码实现&#xff08;C/C&#xff09; 前言 在人工智能算法岗位的面试中&#xff0c;TopK是问得最多的几个问题之一&#xff1a; 到底有几种方法&#xff1f; 这些方案里蕴含的优化思路究竟是怎么样的&#xff1f; 为啥T…

ARM Linux 基础学习 / 系统相关,文件系统,文件属性

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

高性能收发原始数据包的框架(Netmap)

一、Netmap 简介 Netmap 是一个高性能收发原始数据包的框架&#xff0c;由 Luigi Rizzo 等人开发完成&#xff0c;其包含了内核模块以及用户态库函数。其目标是&#xff0c;不修改现有操作系统软件以及不需要特殊硬件支持&#xff0c;实现用户态和网卡之间数据包的高性能传递。…

链表的逆置

方法1&#xff1a; 依次将指针反向&#xff0c;最后令头指针指向尾元素。 逆置过程如下&#xff1a; 当q指针为空时&#xff0c;循环结束。 //试写一算法&#xff0c;对单链表实现就地逆置&#xff0c; void Reverse1(List plist)//太复杂,不用掌握 {assert(plist ! NULL);i…

大二第四周总结——用原生js封装一个分页器

用原生js封装一个分页器 起因&#xff1a;这次项目还是用原生的js来写的&#xff0c;我负责的是后台&#xff0c;分页是后台最常见的一个功能了&#xff0c;于是干脆封装一下,废话少说&#xff0c;直接上代码 这里是基本的样式 .pagination {display: flex;width: 600px;hei…

git的分支及标签使用结合全网最详细的情景演示

目录 一git的分支 ⭐⭐ 补充一个拓展知识&#xff1a; 1.1 git分支 1.2 git分支的增删查命令 1.3 情景演示 二.git标签 2.1 分支与标签的关系 2.2 git标签的基本命令 2.3 情景演示 一git的分支 ⭐⭐ 补充一个拓展知识&#xff1a; 软件开发中常见的四个环境&…

jdk21 虚拟线程原理及使用分享

虚拟线程概述 jdk21已于北京时间9月19日21点正式发布, 其中引人注目的就是虚拟线程(Virtual Thread)随之正式发布, 不再是此前jdk19、jdk20中的预览版本。 平台线程&#xff1a;java传统的线程是对系统线程的包装&#xff0c;为了区别于虚拟线程&#xff0c;因此将通过传统方式…

【Git】工作中的留痕:分支及标签的超神搭配

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Git的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Git分支是什么 二.Git分支的使用 1.分…

HTTPS协议

目录 HTTPS概念加密是什么常见加密方式对称加密非对称加密数据摘要&&数据指纹数据签名 HTTP工作过程探究方案一&#xff1a;只使用对称加密方案二&#xff1a;只使用非对称加密方案三&#xff1a;双方都使用非对称加密方案四&#xff1a;非对称加密对称加密中间人攻击 …

常见面试题-JDK和CGLIB动态代理

JDK 动态代理和 CGLIB 动态代理对比 JDK 动态代理只能代理实现了接口的类&#xff0c;而 CGLIB 可以代理未实现任何接口的类。另外CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用&#xff0c;因此不能代理声明为final 类型的类和方法就二者的效率来说&a…

Unbuntu安装、测试和卸载gcc11

GCC 可用于编译 C、C&#xff0c;本文介绍如何 Ubuntu 上安装 gcc11、测试和卸载它。 1. 在Ubuntu 上安装 gcc11 添加工具链存储库 sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test在 Ubuntu 上安装 gcc11 sudo apt install -y gcc-11验证 gcc11 版本 gcc-11 --v…