携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,点击查看活动详情
什么是自定义指令?
常用的一些内置指令有 v-model、v-show、v-if等,除了这些内置指令,Vue也允许注册自定义指令。
举个栗子,当页面在加载出来时,就让搜索框获得焦点,用自定义指令来实现这个功能:
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
如果想注册局部指令,在实例中写入 directives选项:
new Vue({
el:"#app",
directives:{
focus:{
// 当被绑定的元素插入到 DOM 中时
inserted: function (el) {
// 聚焦元素
el.focus()
}
}
}
})
然后就可以在页面元素中使用自定义的 v-focus 指令了:
<input v-focus>
钩子函数
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
- bind: 只调用一次,指令第一次绑定到元素时调用,可以定义一个在绑定时执行一次的初始化动作。
- inserted: 被绑定元素插入父节点时调用。
- update: 所在组件的任意
VNode更新就会被调用,不论绑定值是否发生变化,可以通过对比更新前后的值来忽略不必要的更新。 - componentUpdated: 指令所在组件的 VNode 及其子VNode全部更新后调用。
- unbind: 只调用一次, 指令与元素解绑时调用。
钩子函数参数
指令钩子函数会被传入以下参数:
-
el:指令所绑定的元素,可以用来直接操作 DOM。
-
binding
:一个对象,包含以下 property:
- name:指令名,不包括
v-前缀。 - value:指令的绑定值,例如:
v-button="submit"中,绑定值为submit。 - oldValue:指令绑定的前一个值,仅在
update和componentUpdated钩子中可用。无论值是否改变都可用。 - expression:字符串形式的指令表达式。例如
v-button="‘submit’,2"中,表达式为"‘submit’,2"。 - arg:传给指令的参数,可选。例如
v-button.debounce:foo中,参数为"foo"。 - modifiers:一个包含修饰符的对象。例如:
v-button.debounce:foo中,修饰符对象为{ debounce: true }。
- name:指令名,不包括
-
vnode:Vue 编译生成的虚拟节点。
-
oldVnode:上一个虚拟节点,仅在
update和componentUpdated钩子中可用。
input框的防抖和节流
<div id="app">
<input type="text" v-model="debounce" v-debounce="{event:'input',fn:fn,delay:1000}">
<input type="text" v-model="throttle" v-throttle="{event:'input',fn:fn,delay:1000}">
</div>
//防抖
Vue.directive("debounce", {
inserted: function (el, binding) {
//事件名、执行的函数、延迟时间
let { event, fn, delay } = binding.value;
let timer
let flag = true;
//中文输入法下不触发input事件
if (event === "input") {
el.addEventListener("compositionstart", () => {
flag = false;
})
el.addEventListener("compositionend", () => {
flag = true;
})
}
el.addEventListener(event, () => {
timer && clearTimeout(timer)
timer = setTimeout(() => {
if (flag) fn("debounce");
}, delay)
})
}
});
//节流
let last;
Vue.directive("throttle", {
bind(el, binding, vnode) {
last = Date.now();
},
inserted: function (el, binding) {
let { event, fn, delay } = binding.value;
let flag = true;
if (event === "input") {
el.addEventListener("compositionstart", () => {
flag = false;
})
el.addEventListener("compositionend", () => {
flag = true;
})
}
el.addEventListener(event, () => {
let now = Date.now();
let { event, fn, delay } = binding.value
if (now - last >= delay) {
last = now;
if (flag) fn("throttle");
}
})
},
});
new Vue({
el: '#app',
data: {
debounce: 'debounce!',
throttle: 'throttle!',
},
methods: {
fn: function (val) {
console.log(val + "执行了");
}
},
})