# Vue自定义指令
有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。
# 指令注册
以一个input元素自动获得焦点为例,当页面加载时,使用autofocus可以让元素将获得焦点 。但是autofocus在移动版Safari上不工作。现在注册一个使元素自动获取焦点的指令
# 全局指令
使用Vue.diretive()来全局注册指令
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
# 局部指令
var vm = new Vue({
el: '#app',
// 指令选项与data methods 等选项同级
directives:{
focus:{
inserted: function (el) {
el.focus()
}
}
}
})
# 使用注册的指令
可以在模板中任何元素上使用新的 v-focus 属性
<div id="example">
<input v-focus>
</div>
# 钩子函数详解
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
==bind==:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
==inserted==:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
==update==:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
==componentUpdated==:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
==unbind==:只调用一次,指令与元素解绑时调用。
# 钩子函数参数
- 【el】
- 指令所绑定的元素,可以用来直接操作 DOM
- 【binding】
- 一个对象,包含以下属性:
- name: 指令名,不包括
v-
前缀。 - value: 指令的绑定值, 例如:
"v-my-directive="1 + 1"
, value 的值是 2。 - oldValue: 指令绑定的前一个值,仅在
update 和 componentUpdated
钩子中可用。无论值是否改变都可用。 - expression: 绑定值的字符串形式。 例如
v-my-directive="1 + 1"
, expression 的值是 "1 + 1"。 - arg: 传给指令的参数。例如
v-my-directive:foo
,"arg 的值是 "foo
"。 - modifiers: 一个包含修饰符的对象。 例如:
v-my-directive.foo.bar
, 修饰符对象modifiers
的值是{ foo: true, bar: true }
。
- name: 指令名,不包括
- 一个对象,包含以下属性:
- 【vnode】
- Vue 编译生成的虚拟节点
- 【oldVnode】
- 上一个虚拟节点,仅在
update
和componentUpdated
钩子中可用
- 上一个虚拟节点,仅在
DANGER
除了 el
之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset
来进行。
# 代码示例
<div id="example" v-demo:foo.a.b="message"></div>
<script>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})
new Vue({
el: '#example',
data: {
message: 'hello!'
}
})
</script>
# 【函数简写】
在很多时候,你可能想在 bind
和 update
时触发相同行为,而不关心其它的钩子。比如这样写:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
# 【对象字面量】
如果指令需要多个值,可以传入一个JS对象字面量。指令函数能够接受所有合法类型的JS表达式
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
# v-permission
参考于 vue-element-admin-master
import store from "@/store";
function checkPermission(el, binding) {
const { value } = binding;
const roles = store.getters && store.getters.roles;
if (value && value instanceof Array) {
if (value.length > 0) {
const permissionRoles = value;
const hasPermission = roles.some((role) => {
return permissionRoles.includes(role);
});
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el);
}
}
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`);
}
}
export default {
inserted(el, binding) {
checkPermission(el, binding);
},
update(el, binding) {
checkPermission(el, binding);
},
};
← Vue 生命周期的理解 Vue2响应式原理 →