vue中的自定义指令

2023-10-26

一、什么是指令

指令系统是计算机硬件的语言系统,也叫机器语言,它是系统程序员看到的计算机的主要属性。因此指令系统表征了计算机的基本功能决定了机器所要求的能力

vue中提供了一套为数据驱动视图更为方便的操作,这些操作被称为指令系统

我们看到的v-开头的行内属性,都是指令,不同的指令可以完成或实现不同的功能

除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令

指令使用的几种方式:

//会实例化一个指令,但这个指令没有参数
;`v-xxx` // -- 将值传到指令中
`v-xxx="value"` // -- 将字符串传入到指令中,如`v-html="'<p>内容</p>'"`
`v-xxx="'string'"` // -- 传参数(`arg`),如`v-bind:class="className"`
`v-xxx:arg="value"` // -- 使用修饰符(`modifier`)
`v-xxx:arg.modifier="value"`

二、如何实现

注册一个自定义指令有全局注册与局部注册

全局注册主要是通过Vue.directive方法进行注册

Vue.directive第一个参数是指令的名字(不需要写上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus() // 页面加载完成之后自动让输入框获取到焦点的小功能
  },
})

局部注册通过在组件options选项中设置directive属性

directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus() // 页面加载完成之后自动让输入框获取到焦点的小功能
    }
  }
}

然后你可以在模板中任何元素上使用新的 v-focus property,如下:

<input v-focus />

自定义指令也像组件那样存在钩子函数:

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用

  • unbind:只调用一次,指令与元素解绑时调用

所有的钩子函数的参数都有以下:

  • el:指令所绑定的元素,可以用来直接操作 DOM
  • binding:一个对象,包含以下 property
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnodeVue 编译生成的虚拟节点
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用

除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行

举个例子

<div v-demo="{ color: 'white', text: 'hello!' }"></div>
<script>
  Vue.directive('demo', function (el, binding) {
    console.log(binding.value.color) // "white"
    console.log(binding.value.text) // "hello!"
  })
</script>

三、有什么应用场景?

使用自定义指令可以满足我们日常一些场景,这里给出几个自定义指令的案例:

  • 防抖
  • 图片懒加载
  • 一键 Copy 的功能

输入框防抖

防抖这种情况设置一个v-throttle自定义指令来实现

举个例子:

// 1.设置v-throttle自定义指令
Vue.directive('throttle', {
  bind: (el, binding) => {
    let throttleTime = binding.value; // 防抖时间
    if (!throttleTime) { // 用户若不设置防抖时间,则默认2s
      throttleTime = 2000;
    }
    let cbFun;
    el.addEventListener('click', event => {
      if (!cbFun) { // 第一次执行
        cbFun = setTimeout(() => {
          cbFun = null;
        }, throttleTime);
      } else {
        event && event.stopImmediatePropagation();
      }
    }, true);
  },
});
// 2.为button标签设置v-throttle自定义指令
<button @click="sayHello" v-throttle>提交</button>

图片懒加载

设置一个v-lazy自定义指令完成图片懒加载

const LazyLoad = {
  // install方法
  install(Vue, options) {
    // 代替图片的loading图
    let defaultSrc = options.default
    Vue.directive('lazy', {
      bind(el, binding) {
        LazyLoad.init(el, binding.value, defaultSrc)
      },
      inserted(el) {
        // 兼容处理
        if ('IntersectionObserver' in window) {
          LazyLoad.observe(el)
        } else {
          LazyLoad.listenerScroll(el)
        }
      },
    })
  },
  // 初始化
  init(el, val, def) {
    // data-src 储存真实src
    el.setAttribute('data-src', val)
    // 设置src为loading图
    el.setAttribute('src', def)
  },
  // 利用IntersectionObserver监听el
  observe(el) {
    let io = new IntersectionObserver((entries) => {
      let realSrc = el.dataset.src
      if (entries[0].isIntersecting) {
        if (realSrc) {
          el.src = realSrc
          el.removeAttribute('data-src')
        }
      }
    })
    io.observe(el)
  },
  // 监听scroll事件
  listenerScroll(el) {
    let handler = LazyLoad.throttle(LazyLoad.load, 300)
    LazyLoad.load(el)
    window.addEventListener('scroll', () => {
      handler(el)
    })
  },
  // 加载真实图片
  load(el) {
    let windowHeight = document.documentElement.clientHeight
    let elTop = el.getBoundingClientRect().top
    let elBtm = el.getBoundingClientRect().bottom
    let realSrc = el.dataset.src
    if (elTop - windowHeight < 0 && elBtm > 0) {
      if (realSrc) {
        el.src = realSrc
        el.removeAttribute('data-src')
      }
    }
  },
  // 节流
  throttle(fn, delay) {
    let timer
    let prevTime
    return function (...args) {
      let currTime = Date.now()
      let context = this
      if (!prevTime) prevTime = currTime
      clearTimeout(timer)

      if (currTime - prevTime > delay) {
        prevTime = currTime
        fn.apply(context, args)
        clearTimeout(timer)
        return
      }

      timer = setTimeout(function () {
        prevTime = Date.now()
        timer = null
        fn.apply(context, args)
      }, delay)
    }
  },
}
export default LazyLoad

一键 Copy 的功能

import { Message } from 'ant-design-vue'

const vCopy = {
  //
  /*
    bind 钩子函数,第一次绑定时调用,可以在这里做初始化设置
    el: 作用的 dom 对象
    value: 传给指令的值,也就是我们要 copy 的值
  */
  bind(el, { value }) {
    el.$value = value // 用一个全局属性来存传进来的值,因为这个值在别的钩子函数里还会用到
    el.handler = () => {
      if (!el.$value) {
        // 值为空的时候,给出提示,我这里的提示是用的 ant-design-vue 的提示,你们随意
        Message.warning('无复制内容')
        return
      }
      // 动态创建 textarea 标签
      const textarea = document.createElement('textarea')
      // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
      textarea.readOnly = 'readonly'
      textarea.style.position = 'absolute'
      textarea.style.left = '-9999px'
      // 将要 copy 的值赋给 textarea 标签的 value 属性
      textarea.value = el.$value
      // 将 textarea 插入到 body 中
      document.body.appendChild(textarea)
      // 选中值并复制
      textarea.select()
      // textarea.setSelectionRange(0, textarea.value.length);
      const result = document.execCommand('Copy')
      if (result) {
        Message.success('复制成功')
      }
      document.body.removeChild(textarea)
    }
    // 绑定点击事件,就是所谓的一键 copy 啦
    el.addEventListener('click', el.handler)
  },
  // 当传进来的值更新的时候触发
  componentUpdated(el, { value }) {
    el.$value = value
  },
  // 指令与元素解绑的时候,移除事件绑定
  unbind(el) {
    el.removeEventListener('click', el.handler)
  },
}

export default vCopy

关于自定义指令还有很多应用场景,如:拖拽指令、页面水印、权限校验等等应用场景

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue中的自定义指令 的相关文章

  • jQuery:查找具有特定自定义属性的元素

    我只想找到具有特定自定义属性值的元素 例如 我想找一个div其具有属性data divNumber 6 var number 6 var myDiv data divNumber number 我尝试使用http api jquery co
  • 使用 jQuery inputmask 插件范围 0-100

    如何创建 0 到 100 范围内的掩码 document ready function masked inputmask 您可以使用jquery inputmask regex extensions js为了那个原因 你可以找到带有所有扩展
  • 我可以在 GWT 中使用第三方 Javascript 库吗

    例如穆工具 用 js 编码对我来说很舒服 但显然不适合所有人 你当然可以 最好的事情就是给自己写一些好看的JavaScript 覆盖类型 http code google com webtoolkit doc latest DevGuide
  • Apache Thrift Java-Javascript 通信

    我正在编写一个基于 Apache Thrift 的 Java 服务器 它将从 Javascript 客户端接收数据 我已经完成了 Java 服务器 但问题是我可以获得 Javascript 客户端的工作示例 我无法找到一个好的示例 构建文档
  • 如何将一个数组中的所有项目复制到另一个数组中?

    如何将数组的每个元素 其中元素是对象 复制到另一个数组中 以便它们完全独立 我不想更改一个数组中的元素来影响另一个数组 这里的关键是 数组中的条目是对象 并且 您不希望对一个数组中的对象的修改显示在另一个数组中 这意味着我们不仅需要将对象复
  • 正则表达式中连字符的这种用法有效吗?

    NB I only想知道它是否是正则表达式定义中未转义连字符的有效应用 它是not关于匹配电子邮件 连字符或反斜杠的含义 量词或其他任何内容的问题 另外 请注意 链接的答案并没有真正讨论转义 未转义连字符之间的有效性问题 通常我会像这样声明
  • 使用javascript以编程方式触发iOS safari中的复制菜单?

    我正在尝试实现一种用户友好的方式 将一些文本从文本输入字段复制到 iOS Safari 上的剪贴板 我知道无法在这个平台上以编程方式完成此操作 但我希望能够尽可能地指导用户体验 在 iOS Safari 上 当用户手动突出显示某些文本时 会
  • 通过 JavaScript 单击按钮/页面提交

    我想了解 asp net 框架如何知道何时单击了按钮 因此一旦收到请求 就会在服务器上触发其单击事件 我需要了解它是如何工作的 因为我想从 JavaScript 触发按钮的服务器单击事件 我能够从 JavaScript 执行页面提交 doc
  • 如何显示接下来的三个图像单击加载更多按钮

    我需要一个加载更多按钮来显示图像 页面加载时 我显示 3 个图像 单击 加载更多 按钮后 接下来的 3 个图像将显示在屏幕上 我尝试了下面的代码 但它不起作用 你能帮我解决这个问题吗 function item slice 0 2 show
  • Firefox Addon 中的 JQuery 导致多个警告

    我在 Firefox 插件中使用 jquery 但我不断收到大量警告消息 如下所示 anonymous function does not always return a value System JS WARNING resource g
  • Angular2:动态同步http请求

    Goal 发出一系列同步 http 请求并能够将它们作为一个可观察流进行订阅 示例 不工作 let query arr test1 test2 test3 function make request query arr if query a
  • 在调试模式下,使用节点检查器时,mocha 不会停止在规范文件中的调试器语句上

    当我使用 debug brk 运行 mocha 并使用 node inspector 打开 chrome 开发工具时 调试器会跳过我放入规范文件中的任何调试器语句 I can如果我遵循 则让调试器语句在模块文件中工作这个伎俩 https g
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • 了解 Document.createElement()

    我在用着GWT及其底层DOM能力 我基本上想要实现的是 Have a div包含一些文本的元素 其中一些文本将被包围span元素 span 元素可相互拖动并提供上下文菜单 New span元素可以由最终用户动态创建 它可能是这样的 在应用程
  • React Redux - 在辅助函数中访问现有存储

    我试图在反应组件之外获取存储实例 存储状态 即在单独的辅助函数中 我有我的减速器 我的动作 我在最上面的组件中创建了一个商店 configStore js import createStore from redux import gener
  • 如何解决“消息端口在收到响应之前已关闭”的问题。在 JavaScript 中的 window.location.reload() 之后

    我遇到了 javascript 问题 从 chrome v73 0 3683 86 开始 每当我在 window location reload 函数之后运行 javascript 代码时 它总是给我错误 Unchecked runtime
  • 如何在 React Native 中使用相同的 Firebase 数据库在两个应用程序之间进行通信?

    我有两个不同的应用程序使用相同的实时数据库 在第一个应用程序中 我发送的订单包含一些要保存在数据库中的数据字段 在另一个应用程序中 我只添加一个侦听器 firebase database ref userOrder currentUser
  • Graphql 将多个查询合并(组合)为一个?

    我正在尝试使用 JavaScript 将多个 GraphQL 查询合并为一个查询 我正在寻找这样的东西 let query3 mergeQueries query1 query2 我们事先不知道哪些查询将被组合 假设我有这样的查询 输入查询
  • Vue - 调度完成后调用 store getter?

    我正在使用 Laravel 5 7 Vue2 Vuex 我在调度调用完成后让 Vue 返回存储值时遇到一些困难 我的申请流程如下 我单击一个提交按钮 该按钮调用组件上的 validate Validate 分派到我的 addLease 操作
  • 将引导程序弹出框保留在视口内

    我正在尝试使用带有按钮的侧边栏创建一个菜单 每个按钮都有一个指定的包含相关数据的弹出窗口 不幸的是 其中一个弹出窗口可能包含任意数量的行 并且在某些情况下它可能部分位于视口之外 See http jsfiddle net bfd9f 1 h

随机推荐

  • 电脑老是自动安装流氓软件的解决办法(详解)

    前言 我们老是被一些垃圾软件搞心态 那么这个时候怎么办呢 1 打开链接https free lanzoux com b0cpu1guf 2 点击下载合适版本 在这里我只演示以下这种的 3 解压之后可以看到以下界面 点击运行程序exe 扫描完
  • 集中式架构与分布式概念,大白话解释

    3分钟读懂系统架构演变 了解时下最火的微服务概念 本人将从大到小给你讲授系统架构的演变 此处的大小不是对比项目的大小 而是单个模块的大小 集中式架构 垂直拆分 分布式 服务治理 微服务 咱们先从最大的来 集中式架构 用我的话来讲它最大最笨重
  • 【iOS开发】生成Appicon图标、为iOS应用添加图标

    1 可以使用在线移动图标生成工具 图标工场http icon wuruihong com 网站自动生成iOS所需的所有对应格式的图标 2 如果直接选择iOS 会自动生成29pt 40pt 50pt 60pt 72pt 76pt 83 5pt
  • MinIO的安装与使用

    MinIO的安装与简单使用 简介 MinIO是一款基于Go语言发开的高性能 分布式的 开源的对象存储系统 兼容亚马逊的S3协议 对Kubernetes能够友好的支持 专为AI等云原生工作负载而设计 官网 中文官网 MinIO官网 官网中也有
  • log4j.properties 配置

    Logger级别 WARN 表明会出现潜在错误的情形 ERROR 指出虽然发生错误事件 但仍然不影响系统的继续运行 FATAL 指出每个严重的错误事件将会导致应用程序的退出 ALL 是最低等级的 用于打开所有日志记录 OFF 是最高等级的
  • 一文说清DC-DC BUCK电路(非常详细)

    目录 摘要 BUCK原理 DC DC芯片框图 自举电容 输出电感 输出电容和纹波 损耗 总结 摘要 DC DC BUCK 是硬件工程师工作中使用频率非常高的电路 可以这么说 只要板子不是迷你型的 十有八九都有DC DC 因此 对它的了解与学
  • 利用Python3做词频统计和词云图

    起源 因看到一篇满眼是字的文章 故希望能够快速的检索出关键字 所以尝试用Python3来实现 代码 import jieba import numpy import codecs import pandas import matplotli
  • Error-Java-IJ:Imported project refers to unknown jdks JavaSE-1.7

    ylbtech Error Java IJ Imported project refers to unknown jdks JavaSE 1 7 Import from EclipseImported project refers to u
  • uniapp 使用 axios

    1 先用npm install axios 这就不用说了吧 2 添加配置代码 App vue main js 引入封装后的axios import axios from utils http js 给Vue函数添加一个原型属性 axios
  • 【嵌入式实战】一文拿下 STM32 Lwip MQTT(超详细)

    文章目录 原创声明 前言 一 MQTT 是什么 二 Cube 配置 2 1 STM32 ETH 设置 2 2 修改 PHY 地址 2 3 LWIP 设置 在这里插入图片描述 三 生成工程的简单测试 3 1 手动修改 MAC 地址 3 2 P
  • 网络爬虫之xpath提取文本时的乱码

    问题如下大红框标注部分 解决方案 在请求获取后 加入转换即可解决 r encoding utf 8
  • 不懂技术,又不影响上班,网上的攒营汇适合做副业吗

    什么时候开始副业最好 铁饭碗 一工作就可以立即开始研究副业 社会人 毕业年后可以开始副业 最好是工资接近同龄人倍时 什么时候不适合开始副业 失业时 失业时主要任务是选对一个方向 先找一个稳定的工作发展 因为此时如果你开展副业 由于副业的不稳
  • STM32使用DMA接收串口数据

    目录 01 概述 02 DMA接收 03 中断 04 代码 01 概述 在之前的文章里 STM32串口详解 和 STM32 DMA详解 文章中 详细讲解了STM32的串口和DMA外设 本篇文章将不在细述串口和DMA的知识 在串口讲解的文章中
  • ajax的post请求数据为json格式相关设置

    平时用request封装axios习惯了突然用ajax传参时一直出问题 原来是配置设置错了 ajax type post contentType application json 必须项 dataType json 必须项 data JSO
  • 垃圾大学python小题

    Python程序设计 课程 实验报告四 字符串与正则表达式 文章如果太长请直接复制到sublime text 软件里进行关键字搜索 一 实验目的和要求 理解字符串编码格式 熟练掌握字符串的概念和各种用法 掌握Python标准库string的
  • 2020,会成为区块链在中国的元年吗?

    2020 会成为区块链在中国的元年吗 文章目录 2020 会成为区块链在中国的元年吗 区块链扫盲 区块链释义 区块链历史 区块链的特点 什么是中心化 什么是去中心化 程序员眼中的区块链 区块链的软分叉与硬分叉 以太坊与以太经典 金本位与银本
  • DDK下的Sleep函数KeDelayExecutionThread

    转载自 http www programlife net ddk kedelayexecutionthread like win32 sleep api html 许多读者一定使用过Sleep函数 这能使程序停下一段时间 许多需要连续 长期
  • TCP服务器/客户端实例(C/C++)

    本篇博客阅读有障碍请参阅 网络编程入门 1 1 Linux下的TCP服务器 include
  • Linux中find命令-path -prune用法详解(find命令如何只查找当前目录,而不查找当前目录下的子目录find . ! -name "." -type d -prune -o -type f -name "*.txt" -print)

    在Windows中可以在某些路径中查找文件 也可以设定不在某些路径中查找文件 下面用Linux中的find的命令结合其 path prune参数来看看在Linux中怎么实现此功能 假如在当前目录下查找文件 且当前目录下有很多文件及目录 多层
  • vue中的自定义指令

    一 什么是指令 指令系统是计算机硬件的语言系统 也叫机器语言 它是系统程序员看到的计算机的主要属性 因此指令系统表征了计算机的基本功能决定了机器所要求的能力 在vue中提供了一套为数据驱动视图更为方便的操作 这些操作被称为指令系统 我们看到