大家好,我是小杨,一个写了6年前端的老司机。今天咱们聊聊Vue里一个既强大又容易被忽视的功能------自定义指令。
说实话,刚开始用Vue的时候,我也觉得内置的v-model
、v-if
这些已经够用了,直到有一次产品经理提了个需求:"小杨啊,这个输入框能不能在获取焦点时自动全选文本?还有,这个按钮能不能根据权限动态显示?"
我第一反应是写个组件封装,但转念一想------这不正是自定义指令的用武之地吗?
一、什么是自定义指令?
简单来说,自定义指令就是给DOM元素添加特殊行为。比如:
- 自动聚焦输入框(
v-focus
) - 权限控制(
v-permission
) - 防抖点击(
v-debounce-click
) - 拖拽功能(
v-draggable
)
Vue提供了v-directive
的方式,让我们可以像用v-model
一样,轻松扩展DOM的能力。
二、自定义指令的两种写法
1. 全局注册(适合复用)
在main.js
或单独的文件里定义:
javascript
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
inserted: function (el) {
el.focus(); // 元素插入DOM时自动聚焦
}
});
然后在任何组件里都能用:
html
<input v-focus placeholder="我会自动聚焦!">
2. 局部注册(适合组件专用)
在组件内部定义:
javascript
export default {
directives: {
highlight: {
bind(el, binding) {
el.style.backgroundColor = binding.value || 'yellow';
}
}
}
};
使用:
html
<p v-highlight="'#ff0000'">这段文字会被高亮!</p>
三、自定义指令的5个核心钩子
Vue给了我们5个钩子函数,可以在不同阶段操作DOM:
钩子名 | 调用时机 | 典型用途 |
---|---|---|
bind |
指令第一次绑定到元素时 | 初始化样式、事件监听 |
inserted |
元素插入DOM后 | 操作DOM(如聚焦) |
update |
所在组件更新时 | 根据新值更新DOM |
componentUpdated |
组件及子组件更新后 | 需要等DOM稳定后再操作 |
unbind |
指令解绑时 | 清理定时器、移除事件监听 |
举个完整例子:
javascript
Vue.directive('pin', {
bind(el, binding) {
el.style.position = 'fixed';
const position = binding.value || 'top';
el.style[position] = '10px';
},
unbind(el) {
console.log('指令解绑,清理工作');
}
});
使用:
html
<div v-pin="'left'">我会固定在左侧!</div>
四、我实际用过的几个骚操作
1. 权限控制指令
javascript
Vue.directive('permission', {
inserted(el, binding) {
const userRole = 我.store.state.user.role;
if (!binding.value.includes(userRole)) {
el.style.display = 'none'; // 或者直接移除 el.remove()
}
}
});
用法:
html
<button v-permission="['admin', 'editor']">只有管理员和编辑能看到我</button>
2. 防抖点击指令
javascript
Vue.directive('debounce-click', {
inserted(el, binding) {
let timer;
el.addEventListener('click', () => {
clearTimeout(timer);
timer = setTimeout(() => {
binding.value();
}, 500);
});
},
unbind(el) {
el.removeEventListener('click'); // 记得解绑!
}
});
用法:
html
<button v-debounce-click="submitForm">500ms防抖提交</button>
3. 文本高亮指令(支持动态更新)
javascript
Vue.directive('highlight', {
bind(el, binding) {
updateColor(el, binding.value);
},
update(el, binding) {
updateColor(el, binding.value); // 值变化时重新渲染
}
});
function updateColor(el, color) {
el.style.backgroundColor = color || 'yellow';
}
五、你可能遇到的坑
-
bind
vsinserted
:- 如果操作依赖DOM位置(比如
el.offsetWidth
),一定要用inserted
,因为bind
时DOM还没插入页面!
- 如果操作依赖DOM位置(比如
-
指令值可以是动态的:
html<div v-demo="dynamicValue"></div>
在
update
钩子里可以拿到新值。 -
指令名不要用驼峰 :
Vue会自动转换
vMyDirective
为v-my-directive
,但建议统一用小写短横线命名。
六、总结
自定义指令特别适合封装DOM操作 ,比如:
✅ 自动聚焦
✅ 权限控制
✅ 防抖/节流
✅ 动画触发
✅ 拖拽/滚动监听
如果你的项目里有重复的DOM操作逻辑,不妨试试用自定义指令封装,代码会更干净!
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!