vue2使用use注册自定义指令实现输入控制与快捷复制

news2024/11/18 0:22:19

使用场景

在一些form表单填写内容的时候,要限制输入的内容必须是数值、浮点型,本来el-input-number就可以实现,但是它本身带那个数值控制操作,等一系列感觉不舒服的地方。如果只是使用el-input该多好,只要监听一下输入的内容就好了。于是就可以考虑使用注册指令的方式,限制输入的内容。

因为只是限制数值和浮点型,数值挺好的,限制浮点类型最好是可以传入参数,限制具体多少位数。

版本环境

vue的版本是^2.6.12,elementui的版本是^2.15.6,使用到Vue.directive()方法,浏览器的requestAnimationFrame方法、cancelAnimationFrame方法,文档对象document的execCommand方法。

文件位置

与index.js同级的文件夹中。src/directive/input.js

引入方式

在入口文件内引用,

import App from './App'

import "@/directive/input.js"


// 省略其他

new Vue({
    el: '#app',
    router,
    store,
    render: h => h(App)
})

复制功能实现

Vue.directive("copy", {
  bind(el) {
    el.$value = el.innerText
    el.handler = () => {
      const textarea = document.createElement("textarea")
      textarea.readOnly = "readonly"
      textarea.style.position = "absolute"
      textarea.style.left = "-9999px"
      textarea.value = el.innerText.trim()
      document.body.appendChild(textarea)
      textarea.select()
      const result = document.execCommand("Copy")
      if (result) {
        Message.success("复制成功!")
      }
      document.body.removeChild(textarea)
    }
    el.addEventListener("click", el.handler)
  },
  unbind(el) {
    el.removeEventListener("click", el.handler)
  }
})

注册指令过程中有几个钩子函数

实现原理就是为指令绑定的组件设置一个点击事件,在销毁的时候注销掉那个点击事件。

在dom文档流中添加一个textarea文本域,然后设置一系列的样式使其不会出现在视图窗口中,为它赋值,将其添加到文档流中,然后选中整个文本域的内容。然后调用文档流的document.execCommand("Copy")方法,将文本内容复制出来。

这个复制内容功能做的比较简单,因为复制出来的内容是取的元素的innerText的,所以最好是在那种span标签使用这个指令。

使用方式

<div class="page-head-text">
  <span>订单编号:</span>
  <el-tooltip content="复制单号" type="light">
     <span v-copy class="pointer" style="color: #1890ff">
        {{ form.orderSn }}
     </span>
  </el-tooltip>
</div>

限制整数,浮点数的输入

因为是限制输入类型,因此对于绑定的元素需要进行判断,判断是否是一个Input类型。如果不是的话,就直接通过querySelector去寻找input标签。

需要给指令传递参数,用来区分是想进行整数限制,还是浮点数限制。需要注意的是,这个参数和赋值是两个概念。

v-filter:int  其中的int是一个参数,让我们知道这个输入框限制的是整数。

v-filter:decimals  其中的decimals也是一个参数,让我们知道这个输入框限制的是浮点数。如果我们想设置这个浮点数最多两位呢?在组件里面要怎么用?

这就是参数和赋值的区别。以限制两位浮点数为例

v-filter:decimals="2"

在钩子函数的四个参数之一binding对象中,value对应的是2,arg对应的是decimals

Vue.directive("filter", {
  bind(el, binding) {
    if (el.tagName.toLowerCase() !== "input") {
      el = el instanceof HTMLInputElement ? el : el.querySelector("input")
    }
    switch (binding.arg) {
      case "int":
        intFilter(el)
        break
      case "decimals":
        let decimalsFilterO = new DecimalsBinding()
        decimalsFilterO.decimalsFilter(el, binding)
        break
    }
  },
  unbind(el, binding) {
    // 解除事件监听
    switch (binding.arg) {
      case "int":
        el.removeEventListener("input", intFilterEx, true)
        break
      case "decimals":
        el.removeEventListener("input", decimalsFilterEx, true)
        break
      default:
        break
    }
  }
})

整数限制

其中intFilter实现

const intFilter = function (el) {
  el.addEventListener("input", intFilterEx, true)
}
const intFilterEx = e => {
  e.target.removeEventListener("input", intFilterEx, true)
  let stop = requestAnimationFrame(() => {
    let num = e.target.value.replace(/\D/g, "").replace(".", "")
    e.target.value = ""
    e.target.value = num.replace(/^0([0-9])/g, "$1") || 0
    e.target.dispatchEvent(new Event("input"))
    e.target.addEventListener("input", intFilterEx, true)
    window.cancelAnimationFrame(stop)
  }, 1)
}

requestAnimationFrame是浏览器的一个事件,在mdn中有详细的解释

https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame

 浮点数限制

function decimalsFilterEx(e) {
  e.target.removeEventListener("input", this.decimalsFilterEx, true)
  let re = new RegExp(`^\\D*([0-9]\\d*\\.?\\d{0,${this.decimalsBinding.value}})?.*$`)
  let stop = requestAnimationFrame(() => {
    e.target.value = e.target.value.replace(re, "$1").replace(/^0([0-9])/g, "$1")
    e.target.dispatchEvent(new Event("input"))
    e.target.addEventListener("input", this.decimalsFilterEx, true)
    window.cancelAnimationFrame(stop)
  }, 1)
}
class DecimalsBinding {
  decimalsBinding = {}
  decimalsFilter = function (el, binding) {
    this.decimalsBinding = binding
    el.addEventListener("input", this.decimalsFilterEx, true)
  }
  decimalsFilterEx = decimalsFilterEx.bind(this)
}

实现方式 

 第一步,创建一个对象,DecimalsBinding对象有三个属性。decimalsBinding用来存储钩子函数中的binding值信息;decimalsFilter用来设置对象存储的binging值,以及为el添加input事件监听;decimalsFilterEx是事件的执行内容。

这里有一些绕,因为在整个input.js文件中,定义了一个decimalsFilterEx函数方法。而且DecimalsBinding里面也有一个同名的属性。

在new DecimalsBinding()创建实例的时候,对象的decimalsFilterEx与input.js文件中的decimalsFilterEx是同一个,因为bind方法改变了外围的decimalsFilterEx的this指向。此时decimalsFilterEx里面的this指向的是实体类

第二步  decimalsFilter为输入框绑定input事件,在这个事件中,先移除原先绑定的监听事件,设定正则校验,拿到输入框的值,使用replace替换里面的值。

然后重新绑定input事件

requestAnimationFrame是一个异步方法,像setTimeOut一样,会返回一个ID值,用来清除这个执行。

requestAnimationFrame的刷新频率和浏览器的渲染频率一样。因此几乎是无感限制。其他监听方法会有几帧显示输入的内容,然后立马消失。这种方法会让用户体验更好一点。

最后就是cancelAnimationFrame方法,清除这个渲染。因为是嵌套设置,如果不清除的话,就像是在setInterval里面再次调用setInterval一样。

 完整文件代码

import { Message } from "element-ui"
import Vue from "vue"

const intFilter = function (el) {
  el.addEventListener("input", intFilterEx, true)
}
const intFilterEx = e => {
  e.target.removeEventListener("input", intFilterEx, true)
  let stop = requestAnimationFrame(() => {
    let num = e.target.value.replace(/\D/g, "").replace(".", "")
    e.target.value = ""
    e.target.value = num.replace(/^0([0-9])/g, "$1") || 0
    e.target.dispatchEvent(new Event("input"))
    e.target.addEventListener("input", intFilterEx, true)
    window.cancelAnimationFrame(stop)
  }, 1)
}

function decimalsFilterEx(e) {
  e.target.removeEventListener("input", this.decimalsFilterEx, true)
  let re = new RegExp(`^\\D*([0-9]\\d*\\.?\\d{0,${this.decimalsBinding.value}})?.*$`)
  let stop = requestAnimationFrame(() => {
    e.target.value = e.target.value.replace(re, "$1").replace(/^0([0-9])/g, "$1")
    e.target.dispatchEvent(new Event("input"))
    e.target.addEventListener("input", this.decimalsFilterEx, true)
    window.cancelAnimationFrame(stop)
  }, 1)
}
class DecimalsBinding {
  decimalsBinding = {}
  decimalsFilter = function (el, binding) {
    this.decimalsBinding = binding
    el.addEventListener("input", this.decimalsFilterEx, true)
  }
  decimalsFilterEx = decimalsFilterEx.bind(this)
}

Vue.directive("copy", {
  bind(el) {
    el.$value = el.innerText
    el.handler = () => {
      const textarea = document.createElement("textarea")
      textarea.readOnly = "readonly"
      textarea.style.position = "absolute"
      textarea.style.left = "-9999px"
      textarea.value = el.innerText.trim()
      document.body.appendChild(textarea)
      textarea.select()
      const result = document.execCommand("Copy")
      if (result) {
        Message.success("复制成功!")
      }
      document.body.removeChild(textarea)
    }
    el.addEventListener("click", el.handler)
  },
  unbind(el) {
    el.removeEventListener("click", el.handler)
  }
})

Vue.directive("filter", {
  bind(el, binding) {
    if (el.tagName.toLowerCase() !== "input") {
      el = el instanceof HTMLInputElement ? el : el.querySelector("input")
    }
    switch (binding.arg) {
      case "int":
        intFilter(el)
        break
      case "decimals":
        let decimalsFilterO = new DecimalsBinding()
        decimalsFilterO.decimalsFilter(el, binding)
        break
    }
  },
  unbind(el, binding) {
    // 解除事件监听
    switch (binding.arg) {
      case "int":
        el.removeEventListener("input", intFilterEx, true)
        break
      case "decimals":
        el.removeEventListener("input", decimalsFilterEx, true)
        break
      default:
        break
    }
  }
})

export default Vue

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

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

相关文章

docker安装ElasticSearchKibana

本文参考以下两篇文章 ✅ElasticSearch&Kibana 部署 云效 Thoughts 企业级知识库 (aliyun.com) docker安装ElasticSearch&Kibana - 飞书 安装elasticsearch 使用docker下载es&#xff1a; docker pull elasticsearch:8.13.0 挂载配置 创建挂在文件目录 mkdir…

AIGC在软件开发中的应用

目录 1. AIGC技术概述1.1 定义与背景1.2 发展历程 2. AIGC在软件开发中的应用2.1 代码生成2.2 错误检测与修复2.3 自动化测试 3. AIGC对开发者职业前景的影响3.1 助力与赋能开发者代码示例&#xff1a;自动化测试 3.2 技能需求转变与职业转型压力代码示例&#xff1a;AIGC辅助的…

云原生技术架构详解

云原生技术最全详解(图文全面总结) 容器技术 容器技术&#xff1a;是将应用程序、及其所有依赖项&#xff0c;打包到一个独立的、可移植的容器中。 如下图所示: 容器技术的实现&#xff0c;最典型的就是以Docker为代表的。 如下图所示&#xff1a; 主要解决&#xff1a; 1、…

#LinuxC高级 笔记一

linux命令 什么是嵌入式&#xff1f; 以应用为中心&#xff0c;以计算机技术为基础&#xff0c;软件硬件可裁剪&#xff0c;适用于对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统 计算机系统组成&#xff1f; 硬件、软件 操作系统&#xff1f; ios windows harmo…

Docker的架构原理

例子可以想象成一个买手机的场景 clien可以想象 你个人 docker deamon &#xff1a;店员 images&#xff1a; 样机 regisitry&#xff1a; 手机仓库 container: 使用的手机 首先我要在店员买一个手机&#xff0c;店员发现是样机&#xff0c;但是仓库有&#xff0c;&…

Zabbix 配置端口监控

Zabbix 端口监控简介 在Zabbix中配置端口监控&#xff0c;可以帮助你实时监控服务器或网络设备上的特定端口是否开放和可访问。Zabbix提供了多种方式来监控端口&#xff0c;主要包括简单的端口可用性检查和更复杂的服务监控。 在Zabbix中进行端口监控时&#xff0c;不一定需要…

小白尝试某程机票信息爬取

实训课需要机票数据集&#xff0c;网上没有&#xff0c;所以我选择爬取数据 此过程可谓经历的九九八十一难&#xff0c;也参考了不少大佬的文章&#xff0c;在此特别记录一下 弯路不多说&#xff0c;我直接讲成功的方法 找到请求url 通过控制台&#xff0c;最后确认下面的 …

C# 编程中互斥锁的使用

C# 中的互斥锁 互斥锁是 C# 中使用的同步原语&#xff0c;用于控制多个线程或进程对共享资源的访问。其目的是确保在任何给定时间只有一个线程或进程可以获取互斥锁&#xff0c;从而提供互斥。 C# 中互斥锁的优点 可以使用互斥锁 (Mutex) 并享受其带来的好处。 1. 共享资源…

使用 PCA 可视化数据的分类能力

使用 PCA 探索数据分类的效果&#xff08;使用 Python 代码&#xff09; 「AI秘籍」系列课程&#xff1a; 人工智能应用数学基础人工智能Python基础人工智能基础核心知识人工智能BI核心知识人工智能CV核心知识 主成分分析 (PCA) 是数据科学家使用的绝佳工具。它可用于降低特征…

LabVIEW自动探头外观检测

开发了一套基于LabVIEW的软件系统&#xff0c;结合视觉检测技术&#xff0c;实现探头及连接器外观的自动检测。通过使用高分辨率工业相机、光源和机械手臂&#xff0c;系统能够自动定位并检测探头表面的细微缺陷&#xff0c;如划痕、残胶、异色、杂物等。系统支持多种探头形态&…

机器学习简介--NLP(二)

机器学习简介 机器学习简介机器学习例子机器学习分类有监督学习有监督学习的应用 无监督学习 机器学习常见概念数据集k折交叉验证过拟合欠拟合评价指标 机器学习简介 机器学习例子 问题&#xff1a; 2&#xff0c;4&#xff0c;6&#xff0c;8&#xff0c;&#xff1f;&#…

智能语音门锁:置入NV170D语音芯片ic 打造便捷生活新体验

一、智能门锁语音芯片开发背景 随着科技的飞速发展&#xff0c;传统门锁的局限性日益凸显&#xff0c;无法满足现代人对高效、安全生活的需求。在这样的时代背景下&#xff0c;智能门锁应运而生&#xff0c;它不仅继承了传统门锁的基本功能&#xff0c;更通过融入先进的科技元素…

数据库安全:MySQL权限体系划分与实战操作

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 这一章节我们需…

基于OpenMV识别数字及程序说明

OpenMV简介 OpenMV是一个开源、低成本且功能强大的机器视觉模块。它基于STM32F427CPU&#xff0c;集成了OV7725摄像头芯片&#xff0c;能在小巧的硬件模块上&#xff0c;用C语言高效地实现核心机器视觉算法&#xff0c;并提供了Python编程接口&#xff0c;使得图像处理的复杂度…

k8s_集群搭建_k8s管理前端_dashboard安装部署---分布式云原生部署架构搭建017

然后再去安装一下一个dashboard,有了这个以后,操作k8s集群就不用 一直敲命令了 可以看到上面的命令拿过来,然后 执行就可以了 然后如果执行慢,可以直接先去下载,使用wget,然后再去 也可以在浏览器访问,把内容拿到,然后 下面是内容: # Copyright 2017 The Kubernetes Author…

金融科技企业的数据治理与合规挑战

随着科技的发展&#xff0c;金融科技行业在我国得到了迅猛发展。金融科技创新不仅为消费者带来了便捷的金融服务&#xff0c;也极大地提高了金融行业的运营效率。然而&#xff0c;在金融科技发展的同时&#xff0c;数据治理与合规挑战也日益显现。本文将深入探讨金融科技企业在…

84 柱状图中最大的矩形

题目 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 输入&#xff1a;heights [2,1,5,6,2,3] 输出&#xff1a;10 解释&#xff1a;最大的矩…

华为OD机试 - 最长合法表达式 - 双指针(Java 2024 D卷 100分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

竞赛选题 交通目标检测-行人车辆检测流量计数 - 竞赛选题

文章目录 0 前言1\. 目标检测概况1.1 什么是目标检测&#xff1f;1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…

苹果Mac电脑能玩什么游戏 Mac怎么运行Windows游戏

相对于Windows平台来说&#xff0c;Mac电脑可玩的游戏较少。虽然苹果设备的性能足以支持各种大型游戏&#xff0c;但由于系统以及苹果配套服务的限制&#xff0c;很多游戏无法在Mac系统中运行。不过&#xff0c;借助虚拟机软件&#xff0c;Mac电脑可以突破系统限制玩更多的游戏…