1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > VUE ---- 自定义指令的理解和应用

VUE ---- 自定义指令的理解和应用

时间:2022-07-05 05:12:37

相关推荐

VUE ---- 自定义指令的理解和应用

VUE ---- 自定义指令的理解和应用

前段时间在项目当中有一个需求要操作到DOM层面。尽管Vue框架推崇数据驱动视图的理念,但并非所有情况都适合数据驱动。考虑到上面提到的业务场景,Vue官方提供了自定义指令。因为指令的颗粒度比较细能够直击要害(DOM),而且具备有高度的灵活性,运用起来非常的方便。

一、概念

Vue中内置了很多的指令,如v-model、v-show、v-html等,但是有时候这些指令并不能满足我们,或者说我们想为底层元素(DOM)附加一些特别的功能,这时候,我们就需要用到vue中一个很强大的功能了—自定义指令(Vue.directive)。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。

这里敲黑板了!重要的事情上面已经说三遍了!自定义指令解决的问题或者说使用场景是对普通 DOM 元素进行底层操作,所以我们不能盲目的胡乱的使用自定义指令。

二、使用方式

tips:除了el对象之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行,以避免在开发过程中带来不必要的麻烦。

a. Vue2.0:

// 1.注册全局自定义指令Vue.directive('xxx', {// 指令第一次绑定到元素时「初始化」……bind(el, binding, vnode, oldVnode) {// el:绑定指令的DOM元素对象// binding:数据对象// + name:不带“v-”的指令名字// + rawName:带“v-”的指令名字「含值和修饰符」// + value:指令绑定的值 v-xxx="1+1" -> value:2// + expression:指令表达式 v-xxx="1+1" -> expression:"1+1"// + arg:传给指令的参数 v-xxx:n -> arg:"n"// + modifiers:修饰符对象 v-xxx.stop.finish -> modifiers:{stop:true,finish:true}// vnode:Vue编译生成的虚拟节点// oldVnode:上一个虚拟节点},// 被绑定元素插入父节点时「父节点不一定非要插入到文档中,一般是插入到DOM中」……inserted() {},// 所在组件的VNode更新时「指令的值可能发生了改变,也可能没有」……update(el, binding, vnode, oldVnode) {// binding:数据对象// + oldArg// + oldValue// + ...},// 所在组件的VNode及其子VNode全部更新后……componentUpdated() {},// 指令与元素解绑时……unbind() {}});// or// 2.注册局部自定义指令(组件内)directives:{xxx:{bind(el, binding, vnode, oldVnode) {},inserted() {},update(el, binding, vnode, oldVnode) {},unbind() {}}}

i:列举官方实例

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>Vue.directive('demo', {bind: function (el, binding, vnode) {var s = JSON.stringifyel.innerHTML ='name: ' + s(binding.name) + '<br>' +'rawName:' + s(binding.rawName) + '<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: '#hook-arguments-example',data: {message: 'hello!'}})// name: "demo" 不带“v-”的指令名字// rawName: "v-demo" 带“v-”的指令名字「含值和修饰符」// value: "hello!" 指令绑定的值 v-demo="message" -> value:hello!// expression: "message" 指令表达式 v-demo="message" -> expression:"message"// argument: "foo" 传给指令的参数 v-demo:foo -> arg:"foo"// modifiers: {"a":true, "b":true} 修饰符对象 v-demo.a.b -> modifiers:{a:true,b:true}// vnode keys: Vue编译生成的虚拟节点 -> tag,data,children,text,elm,ns,context,fnContext,fnScopeId,key,componentOptions,componentInstance,parent,raw,isStatic,isRootInsert,isComment,isCloned,isOnce,asyncFactory,asyncMeta,isAsyncPlaceholder

ii:动态指令参数

<div id="dynamicexample"><h3>Scroll down inside this section ↓</h3><p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p></div>Vue.directive('pin', {bind: function (el, binding, vnode) {el.style.position = 'fixed'var s = (binding.arg == 'left' ? 'left' : 'top') // s => leftel.style[s] = binding.value + 'px'}})new Vue({el: '#dynamicexample',data: function () {return {direction: 'left'}}})

iii:函数简写方式

在很多时候,你可能想在 bind 和 update 时触发相同行为,而不关心其它的钩子的时候,就可以采取函数简写的方式:

<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!"})

iiii:对象字面量

如果指令需要多个值,可以传入一个 JavaScript 对象字面量。记住,指令函数能够接受所有合法的 JavaScript 表达式。

<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!"})

b. Vue3.0,和Vue2.0有了一些钩子的区别:

import {createApp} from 'vue';const app = createApp(App);// 1.注册全局自定义指令app.directive('xxx', {// 绑定元素之前created() {},// 指令首次绑定到元素且在安装父组件之前...「等同于bind」beforeMount(el, binding, vnode, prevVnode) {// binding:数据对象// + instance: 使用指令的组件实例// + arg:传给指令的参数 v-xxx:n -> arg:"n"// + modifiers:修饰符对象 v-xxx.stop -> modifiers:{stop:true}// + value:指令绑定的值 v-xxx="1+1" -> value:2// + oldValue:之前绑定的值// + dir: 一个对象,在注册指令时作为参数传递},// 安装绑定元素的父组件时...「等同于inserted」mounted() {},// 在包含组件的VNode更新之前...beforeUpdate() {},// 在包含组件的VNode及其子VNode更新后...「等同于componentUpdated」updated() {},// 在卸载绑定元素的父组件之前...beforeUnmount() {},// 指令与元素解除绑定且父组件已卸载时...「等同于unbind」unmounted() {}});app.mount('#app');// or// 2.注册局部自定义指令(组件内)directives:{xxx:{beforeMount(el, binding, vnode, prevVnode) {},mounted() {},beforeUpdate() {},update() {},beforeUnmount() {},unmounted() {}}}

i:官方提供实例

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>const app = Vue.createApp({data() {return {message: 'hello!'}}})app.directive('demo', {bind: function (el, binding, vnode) {var s = JSON.stringifyel.innerHTML ='value: '+ s(binding.value) + '<br>' +'arg: ' + s(binding.arg) + '<br>' +'modifiers: ' + s(binding.modifiers) + '<br>' +'vnode keys: ' + Object.keys(vnode).join(', ')}})app.mount('#hook-arguments-example')// value: "hello!" 指令绑定的值 v-demo="message" -> value:hello!// arg: "foo" 传给指令的参数 v-demo:foo -> arg:"foo"// modifiers: {"a":true, "b":true} 修饰符对象 v-demo.a.b -> modifiers:{a:true,b:true}// vnode keys: Vue编译生成的虚拟节点 -> tag,data,children,text,elm,ns,context,fnContext,fnScopeId,key,componentOptions,componentInstance,parent,raw,isStatic,isRootInsert,isComment,isCloned,isOnce,asyncFactory,asyncMeta,isAsyncPlaceholder

ii:动态指令参数

基本上和Vue2.0版本的例子一样,各位看官自行参考。

iii:函数简写方式

基本上和Vue2.0版本的例子一样,各位看官自行参考。

const app = Vue.createApp()app.directive('pin', (el, binding) => {el.style.position = 'fixed'const s = binding.arg || 'top'el.style[s] = binding.value + 'px'})

iiii:对象字面量

这种情况用来应付接收多个指令值,记住,指令函数能够接受所有合法的 JavaScript 表达式。

<div v-demo="{ color: 'white', text: 'hello!' }"></div>app.directive('demo', (el, binding) => {console.log(binding.value.color) // => "white"console.log(binding.value.text) // => "hello!"})

三、弊端

vue的自定义指令是一个比较容易引起内存泄漏的地方,原因就在于指令通常给元素绑定了事件,但是如果忘记了解绑,就会产生内存泄漏的问题。

所以在unbind也好在unmounted也好,都要针对绑定的事件进行消除,否则就会产生内存泄漏。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。