阿勒泰地区网站建设_网站建设公司_搜索功能_seo优化
2025/12/27 22:26:00 网站建设 项目流程

Vue官方提供很多指令,比如:v-model,v-show,v-if,v-on等,他们都以v-开头。当这些指令不能满足实际开发需求时,我们可以自定义指令,包括全局自定义指令和局部自定义指令。聚焦于底层DOM操作,用于修改元素的样式、操作DOM、处理事件等。

一、指令封装

1、 v-dialogDragWidth: 拖拽 el-dialog 弹窗宽度拖大、 拖小

import Vue from 'vue' // v-dialogDragWidth: 弹窗宽度拖大 拖小 Vue.directive('dialogDragWidth', { bind(el, binding, vnode, oldVnode) { const dragDom = binding.value.$el.querySelector('.el-dialog') el.onmousedown = (e) => { // 鼠标按下,计算当前元素距离可视区的距离 const disX = e.clientX - el.offsetLeft document.onmousemove = function(e) { e.preventDefault() // 移动时禁用默认事件 // 通过事件委托,计算移动的距离 const l = e.clientX - disX dragDom.style.width = `${l}px` } document.onmouseup = function(e) { document.onmousemove = null document.onmouseup = null } } } })

2、v-lazy :图片懒加载,监听scroll事件并计算元素位置

import Vue from 'vue' // v-lazy: 图片懒加载 Vue.directive('lazy', { inserted(el, binding) { const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { el.src = binding.value observer.unobserve(el) } }) observer.observe(el) } })
二、指令使用

1、在 utils 中新建 directives.js 文件
2、main.js中导入:import ‘./utils/directives.js’
3、使用指令的地方加入 dialogDragWidth 、v-lazy

<el-dialog :visible.sync="dialogVisible" v-dialogDragWidth> // ...... </el-dialog> <img v-lazy="detail.imageUrl">
三、指令扩展
1. 指令钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):

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

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

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

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

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

每个钩子函数有以下参数:
  1. el:指令所绑定的元素,可以用来直接操作 DOM。
  2. 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 }。
vnode:Vue 编译生成的虚拟节点。
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

代码实现:
import Vue from 'vue' Vue.directive('tooltip',{ bind(el, binding) { // 当指令绑定到 HTML 元素上时触发.**只调用一次,适合进行一次性初始化** console.log('bind triggerd') el.style.position = 'relative' const tooltip = document.createElement('div') tooltip.className = 'tooltip' tooltip.textContent = binding.value el._tooltip = tooltip document.body.appendChild(tooltip) }, inserted(el, binding) { // 当绑定了指令的这个HTML元素插入到父元素上时触发(在这里父元素是 `div#app`)**.但不保证,父元素已经插入了 DOM 文档.**。若父元素初始为 display:none,获取的尺寸可能不准确,需结合MutationObserver监听显示状态变化。 console.log('inserted triggerd') const rect = el.getBoundingClientRect() el._tooltip.style.cssText = ` position: absolute; left: ${rect.left + rect.width/2}px; top: ${rect.top - 30}px; ` }, updated(el, binding) { // 所在组件的`VNode`更新时调用. 但会忽略首次绑定 console.log('updated triggerd') if (binding.value !== binding.oldValue) { el._tooltip.textContent = binding.value } }, componentUpdated(el, binding) { // 指令所在组件的 VNode 及其子 VNode 全部更新后调用。 console.log('componentUpdated triggerd') // 适合在子组件更新后重新计算位置 const rect = el.getBoundingClientRect() // 更新tooltip位置... }, unbind(el, binding) { // 只调用一次,指令与元素解绑时调用. 必须进行资源释放,若忘记移除事件监听器或全局对象,会导致内存泄漏 console.log('unbind triggerd') if (el._tooltip) { document.body.removeChild(el._tooltip) delete el._tooltip } } })
四、指令参数传参
1、传递静态参数

在自定义指令中传递静态参数,静态参数是指在指令绑定时已知的参数值。在HTML标签上使用指令时,使用冒号(:)来传递静态参数。例如,自定义指令叫做”v-dialogDragWidth”,我们可以通过这样的方式传递一个静态参数:

<div v-dialogDragWidth:arg="value"></div>

给 v-dialogDragWidth 指令传递了一个名为”arg”的静态参数,它的值为”value”。

我们可以在自定义指令的定义中通过”bind”钩子函数获取传入的参数,并在绑定元素上进行相应的操作:

Vue.directive('dialogDragWidth', {
bind: function(el, binding) {
console.log(binding.arg); // 输出:arg
console.log(binding.value); // 输出:value
// 在这里可以对绑定元素进行操作
}
});

2、传递动态参数

动态参数是指在指令绑定时不确定的参数值,根据不同的情况动态改变。在Vue中,我们可以使用方括号([])来传递动态参数:

<div v-dialogDragWidth:[arg]="value"></div>

或者

<div v-dialogDragWidth:[arg1,arg2,arg3]="value"></div>

我们给” v-dialogDragWidth ”指令传递了一个动态参数,它的值为”value”。在Vue实例中我们可以在数据中定义”arg”的值,并在渲染的时候动态改变它。例如:

data: {
arg: 'dynamicArg'
}

当数据中的”arg”发生变化时,指令中的动态参数也会相应地改变。在自定义指令的定义中,我们可以通过表达式来获取动态参数的值。

Vue.directive('dialogDragWidth', {
bind: function(el, binding) {
console.log(binding.arg); // 输出:dynamicArg
console.log(binding.value); // 输出:value
// 在这里可以对绑定元素进行操作
}
});

3、传参场景使用

通过对象形式动态传递参数,实现更灵活的权限控制:

// 使用方式:

<el-button v-permission:{"您没有删除权限"}="'delete'">删除</el-button>

// 数据处理:

Vue.directive('permission', {
bind(el, binding) {
const { value, arg } = binding // value:权限字符串,arg:错误提示
if (!checkPermission(value)) {
el.style.display = 'none'
el._permissionDenied = arg || '无权限访问'
}
}
})

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询