欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > Vue 自定义指令

Vue 自定义指令

2025/6/27 11:44:56 来源:https://blog.csdn.net/weixin_44717486/article/details/144886928  浏览:    关键词:Vue 自定义指令

首先,我们知道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 = valueel.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 = 200can.height = 150can.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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词