Vue 自定义指令详解

 更新时间:2025年01月03日 09:34:25   作者:北巷`  
本文介绍了如何在Vue中定义和使用自定义指令,包括指令的注册、钩子函数、参数以及常见指令的封装,如v-copy、v-longpress等,自定义指令在处理某些底层DOM操作时非常便捷,感兴趣的朋友一起看看吧

首先,我们知道vue中有很多自带指令,v-bind、v-on、v-model等。但在业务开发中,我们常见一些自定义指令如:v-copy、v-longpress等。那么如何定义自己所需的指令呢?
接下来我们分别从指令注册、指令的钩子函数、指令的参数以及常见指令的封装进行介绍

为什么要自定义指令

在使用vue的时候 我们某些场景下仍然需要对普通 DOM 元素进行底层操作,
在vue中、组件渲染需要时间,获取DOM常需要搭配setTimeout、$nextTick使用
而自定义指令在使用时,更便捷。

指令注册

指令的注册命令:Vue.directive(key, directives[key])
使用:Vue.use()

全局注册

在我们常见的项目结构中、directives文件夹下,定义的index.js文件中,我们会对指令进行全局注册。

import MyDirective from './directive/myDirective' 
const directives = { 
  MyDirective 
}
export default { 
  install(app) {
    // 遍历、注册
   Object.keys(directives).forEach((key) => {    
    app.directive(key, directives[key])  
   })
  }
}

局部注册

在你自己组件或页面中,使用directives选项自定义指令

export default {
  directives: {
    myDirective: {
      inserted: function (el) {
        //
      }
    }
  }
}

使用

<input v-myDirective>

添加参数
v-myDirective="data" 传递数值给指令,这里的data可以是组件中的data数据,也可以是methods方法。

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

v-myDirective:click="clickHandle",传递参数click,这里可以通过[xx]的格式动态传递参数。
v-myDirective:click.top.bar="clickHandle" 传递修饰符top和bar。

注意:不推荐在组件上使用自定义指令、它会应用于组件的根结点、和透传 attributes 类似。

指令的钩子和参数

const myDirective = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode) {}
}
  • bind: 只调用一次,指令第一次绑定到HTML元素时调用,可以定义一个在绑定时执行一次的初始化动作,此时获取父节点为null。
  • bind: function (el, {value:{fn,time}}) {}
  • el:指令绑定的元素、用来操作DOM
  • value:指令的绑定值inserted: 被绑定元素插入父节点时调用,此时可以获取到父节点。
  • update: 所在组件的VNode更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新componentUpdated: 指令所在组件的 VNode 及其子 VNode 全部更新后调用。

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

常见指令的封装

v-copy

内容复制到剪切板中

const copy = {
  bind(el, { value }) {
    el.$value = value
    el.handler = () => {
      if (!el.$value) {
        // 值为空的时候,给出提示。可根据项目UI仔细设计
        console.log('无复制内容')
        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()
      const result = document.execCommand('Copy')
      if (result) {
        console.log('复制成功') 
      }
      document.body.removeChild(textarea)
    }
    // 绑定点击事件
    el.addEventListener('click', el.handler)
  },
  // 当传进来的值更新的时候触发
  componentUpdated(el, { value }) {
    el.$value = value
  },
  // 指令与元素解绑的时候,移除事件绑定
  unbind(el) {
    el.removeEventListener('click', el.handler)
  },
}
export default copy

v-longpress

实现一个用户长按鼠标左键或移动端单指长按,触发的事件

const longpress = {
  bind(el, binding) {
    if (typeof binding.value!== 'function') {
      throw new Error('Callback must be a function');
    }
    let pressTimer = null;
    // 鼠标(左键)按下、移动端按下 且 按下持续时间超过 1s 时,触发
    const start = (e) => {
      if (
        (e.type === 'mousedown' && e.button!== 0) ||
        (e.type === 'touchstart' && e.touches.length > 1)
      ) {
        return;
      }
      pressTimer = setTimeout(() => {
        binding.value(e);
      }, 1000);
    };
    // 鼠标(左键)抬起、移动端抬起 或 按下时间小于 1s 时,移除定时器
    const cancel = () => {
      if (pressTimer!== null) {
        clearTimeout(pressTimer);
        pressTimer = null;
      }
    };
    // 事件监听
    el.addEventListener('mousedown', start);
    el.addEventListener('touchstart', start);
    el.addEventListener('click', cancel);
    el.addEventListener('mouseout', cancel);
    el.addEventListener('touchend', cancel);
    el.addEventListener('touchcancel', cancel);
  },
  // 指令与元素解绑的时候,移除事件绑定
  unbind(el) {
    el.removeEventListener('mousedown', start);
    el.removeEventListener('touchstart', start);
    el.removeEventListener('click', cancel);
    el.removeEventListener('mouseout', cancel);
    el.removeEventListener('touchend', cancel);
    el.removeEventListener('touchcancel', cancel);
  },
};
export default longpress

v-waterMarker

页面增加水印

function addWaterMarker(str, parentNode, font, textColor) {
  // 水印文字,父元素,字体,文字颜色
  var can = document.createElement('canvas')
  parentNode.appendChild(can)
  can.width = 200
  can.height = 150
  can.style.display = 'none'
  var cans = can.getContext('2d')
  cans.rotate((-20 * Math.PI) / 180)
  cans.font = font || '16px Microsoft JhengHei'
  cans.fillStyle = textColor || 'rgba(180, 180, 180, 0.3)'
  cans.textAlign = 'left'
  cans.textBaseline = 'Middle'
  cans.fillText(str, can.width / 10, can.height / 2)
  parentNode.style.backgroundImage = 'url(' + can.toDataURL('image/png') + ')'
}
const waterMarker = {
  bind: function (el, binding) {
    addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor)
  },
}
export default waterMarker

到此这篇关于Vue 自定义指令的文章就介绍到这了,更多相关Vue 自定义指令内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue 计算属性之姓名案例的三种实现方法

    Vue 计算属性之姓名案例的三种实现方法

    这篇文章主要介绍了Vue 计算属性之姓名案例的三种实现方法,计算属性实现、methods实现和插值语法实现,下面文章具体介绍,需要的小伙伴可以参考一下
    2022-05-05
  • 4种方案带你探索Vue代码复用的前世今生

    4种方案带你探索Vue代码复用的前世今生

    我们所熟知的Vue.js也在如何提取公共代码复用方面也一直在探索优化,本文小编就来和各位聊聊Vue.js代码复用的前世今生,希望对大家学习Vue有一定的帮助
    2023-05-05
  • Vue3实现转盘抽奖效果的示例详解

    Vue3实现转盘抽奖效果的示例详解

    这篇文章主要为大家详细介绍了如何通过Vue3实现简单的转盘抽奖效果,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的可以了解一下
    2023-10-10
  • vue3 setup语法糖中获取slot插槽的dom对象代码示例

    vue3 setup语法糖中获取slot插槽的dom对象代码示例

    slot元素是一个插槽出口,标示了父元素提供的插槽内容将在哪里被渲染,这篇文章主要给大家介绍了关于vue3 setup语法糖中获取slot插槽的dom对象的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-04-04
  • vue在自定义组件上使用v-model和.sync的方法实例

    vue在自定义组件上使用v-model和.sync的方法实例

    自定义组件的v-model和.sync修饰符其实本质上都是vue的语法糖,用于实现父子组件的"数据"双向绑定,下面这篇文章主要给大家介绍了关于vue在自定义组件上使用v-model和.sync的相关资料,需要的朋友可以参考下
    2022-07-07
  • 详解vue mint-ui源码解析之loadmore组件

    详解vue mint-ui源码解析之loadmore组件

    本篇文章主要介绍了vue mint-ui源码解析之loadmore组件,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • vue中解决拖拽改变存在iframe的div大小时卡顿问题

    vue中解决拖拽改变存在iframe的div大小时卡顿问题

    这篇文章主要介绍了vue中解决拖拽改变存在iframe的div大小时卡顿问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • 使用vscode添加vue模板步骤示例

    使用vscode添加vue模板步骤示例

    这篇文章主要为大家介绍了vscode添加vue模板步骤示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Element plus 表单中下拉框的空值问题解决

    Element plus 表单中下拉框的空值问题解决

    有时候会碰到查询条件需要用下拉框来区分的时候,比如需要区分全部 | 启用 | 停用三个状态,这时一般会给全部的value值设置为'',但是这样会导致下拉框无法选中对应的全部选项,本文就来介绍一下这个问题解决,感兴趣的可以了解一下
    2024-11-11
  • vite项目vite.config.js详细配置

    vite项目vite.config.js详细配置

    vite.config.js是Vite框架中的配置文件,用于配置项目的构建和运行时的行为,下面这篇文章主要给大家介绍了关于vite项目vite.config.js详细配置的相关资料,需要的朋友可以参考下
    2023-05-05

最新评论