自定义指令
文档
Vue2 自定义指令
js
/*
Vue2.x 自定义指令生命周期钩子
bind : 只调用一次,指令第一次绑定到元素时调用
inserted : 被绑定元素插入父节点时调用
update : 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
componentUpdated : 指令所在组件的 VNode 及其子 VNode 全部更新后调用
unbind : 只调用一次,指令与元素解绑时调用
自定义指令生命周期钩子的参数
el : 被绑定指令的元素 DOM 对象
bindings : 是一个对象
name : 不包括 v- 前缀的指令名称 my-show
oldValue : 更新前的指令绑定的值
value : 当前指令绑定的值
expression : 指令表达式的值 v-my-show="1 + 1" -> 表达式为: "1 + 1"
arg : 指令的参数, 一个字符串 v-my-show:abc -> abc
modifiers : 指令的修饰符集合 v-my-show.trim.number -> { trim: true, number: true }
vNode : 绑定指令的元素的 虚拟节点
prevNode : 上一个虚拟节点
*/
// 全局指令
Vue.directive('my-show', myShow);
Vue.directive('my-if', myIf);
// 局部/实例指令
export default {
directives: {
myShow,
myIf,
},
};
Vue3 自定义指令
js
/*
Vue3.x 自定义指令生命周期钩子
beforeMount : 指令绑定的元素挂载前调用
mounted : 指令绑定的元素挂载后调用
beforeUpdate : 指令绑定的组件数据更新前调用
updated : 指令绑定的组件数据更新后调用
beforeUnmount : 指令绑定的组件卸载前调用
unmounted : 指令绑定的组件卸载后调用
自定义指令生命周期钩子的参数
el : 被绑定指令的元素 DOM 对象
bindings : 是一个对象
arg : 指令的参数, 一个字符串 v-my-show:abc -> abc
dir : 指令对象的所有属性
instance : 使用这个指令的实例
modifiers : 指令的修饰符集合 v-my-show.trim.number -> { trim:true, number: true }
oldValue : 更新前的指令绑定的值
value : 当前指令绑定的值
vNode : 绑定指令的元素的 虚拟节点
prevNode : 上一个虚拟节点, beforeUpdate & upated 可用
*/
// 全局指令
app.directive('my-show', myShow);
app.directive('my-if', myIf);
// 局部/实例指令
export default {
directives: {
myShow,
myIf,
},
};
Vue2 手动实现 v-if 和 v-show
html
<template>
<div>
<div>
<button @click="toggleShow">toggleShow</button>
<button @click="toggleIf">toggleIf</button>
</div>
<!--
<div class="box box1" v-show="showBox1">show</div>
<div class="box box2" v-if="showBox2">if</div>
-->
<div class="box box1" v-my-show="showBox1">show</div>
<div class="box box2" v-my-if="showBox2">if</div>
</div>
</template>
<script>
const myShow = function (el, bindings) {
el.style.display = bindings.value ? '' : 'none';
};
const myIf = {
inserted(el, bindings) {
// 插入到父元素的时候判断, 是渲染注释节点还是 el
// 由于需要在更新的时候获取到 commentNode 所以
// 需要将 commentNode 挂到 el 上, 因为更新的时候
// 也会传入这个 el, 因为是同一个引用, 所以在更新时候
// 就能获取到 commentNode
el.commentNode = document.createComment('v-if');
if (bindings.value) {
el.parentNode.replaceChild(el, el.commentNode);
} else {
el.parentNode.replaceChild(el.commentNode, el);
}
},
componentUpdated(el, bindings) {
// 只有指令绑定的值变化了才执行
if (bindings.value === bindings.oldValue) {
return;
}
if (bindings.value) {
el.commentNode.parentNode.replaceChild(el, el.commentNode);
} else {
el.parentNode.replaceChild(el.commentNode, el);
}
},
};
export default {
directives: {
myShow,
myIf,
},
data: () => ({
showBox1: false,
showBox2: false,
}),
methods: {
toggleShow() {
this.showBox1 = !this.showBox1;
},
toggleIf() {
this.showBox2 = !this.showBox2;
},
},
};
</script>
<style scoped>
.box {
width: 100px;
height: 100px;
}
.box1 {
background: #f00;
}
.box2 {
background: #0f0;
}
</style>
Vue3 手动实现 v-if 和 v-show
html
<template>
<div>
<div>
<button @click="toggleShow">toggleShow</button>
<button @click="toggleIf">toggleIf</button>
</div>
<!--
<div class="box box1" v-show="showBox1">show</div>
<div class="box box2" v-if="showBox2">if</div>
-->
<div v-my-show="showBox1" class="box box1">v-my-if</div>
<div v-my-if="showBox2" class="box box2">v-my-show</div>
</div>
</template>
<script>
const myShow = function (el, bindings) {
// 因为 mounted 和 updated 是一样的操作, 所以可以直接赋值一个方法
// 这个方法在 mounted 和 updated 时, 都会执行
el.style.display = bindings.value ? '' : 'none';
};
const myIf = {
mounted(el, bindings) {
// 要想在update中获取到 commentNode, 所以需要将 commentNode
// 挂到 el 上, 然后在 updated 钩子中获取到 el.commentNode
// 因为是同一个引用, 所以可以获取到
el.commentNode = document.createComment('v-if');
if (bindings.value) {
el.parentNode.replaceChild(el, el.commentNode);
} else {
el.parentNode.replaceChild(el.commentNode, el);
}
},
updated(el, bindings) {
if (bindings.value !== bindings.oldValue) {
// 当 v-my-if 绑定的值更新了才更新
if (bindings.value) {
el.commentNode.parentNode.replaceChild(el, el.commentNode);
} else {
el.parentNode.replaceChild(el.commentNode, el);
}
}
},
};
export default {
directives: {
myIf,
myShow,
},
data: () => ({
showBox1: false,
showBox2: false,
}),
methods: {
toggleShow() {
this.showBox1 = !this.showBox1;
},
toggleIf() {
this.showBox2 = !this.showBox2;
},
},
};
</script>
<style lang="css" scoped>
.box {
width: 100px;
height: 100px;
}
.box1 {
background: #f00;
}
.box2 {
background: #0f0;
}
</style>