前言

通常情况下,vue内置的指令并不能够满足我们日常开发的要求,我们则可以根据实际需要进行自定义指令,本篇博客将记录vue自定义指令模拟v-model的过程,有什么错误的地方欢迎批评指正。

创建自定义指令

// 全局创建
Vue.directive("slice",{
	bind(el,bindings,vnode){
		// 指令绑定上去的时候触发
	},
	update(el,bindings,vnode){
		// 数据更新的时候触发
	},
	inserted(el){   
		// 元素插入到页面的时候触发
	}
})

// 局部创建
new Vue({
    el: "#app",
    directives: {
        slice: {
            bind(el, bindings, vnode) {
				// 指令绑定上去的时候触发
            },
            update(el, bindings, vnode) {
				// 数据更新的时候触发
            },
            inserted(el) {
				// 元素插入到页面的时候触发
            }
        }
    }
})

创建自定义指令分为全局创建和局部创建,自定义指令有三个钩子函数( bind、update和inserted )

钩子函数

bind、update和inserted

钩子函数参数描述
bindel,bindingd,vnode绑定指令时触发
updateel,bindingd,vnode数据更新数触发
insertedel插入到页面时触发

其中el代表着当前元素,bindings为一个对象,vnode是虚拟DOM

比如说当我想要在页面加载完成后input框获取焦点,我们可以这样写

<div id="app">
    <input type="text" v-slice>
</div>

<script>
    Vue.directive("slice", {
        bind(el, bindings, vnode) {},
        update(el, bindings, vnode) {},
        inserted(el, bindings, vnode) {
            el.focus();
        }
    })

    new Vue({
        el: "#app"
    })
</script>

参数 bindings

指令可以传递变量,我们可以通过bindings对象中的expression获取参数值的变量名。

<div id="app">
    <input type="text" v-slice="content">
</div>

<script>
    Vue.directive("slice", {
        bind(el, bindings, vnode) {
            console.log(bindings.expression)
        },
        update(el, bindings, vnode) {},
        inserted(el, bindings, vnode) {
            el.focus();
        }
    })

    new Vue({
        el: "#app",
        data: {
            content: 'hello vue'
        }
    })
</script>

在这里插入图片描述

参数 vnode

有了自定义的参数值的变量名,我们就可以在vnode中获取到变量的数据

<div id="app">
    <input type="text" v-slice="content">
</div>

<script>
    Vue.directive("slice", {
        bind(el, bindings, vnode) {
            var context = vnode.context;
            console.log(vnode.context);
            console.log(vnode.context[bindings.expression]);
        },
        update(el, bindings, vnode) {},
        inserted(el, bindings, vnode) {
            el.focus();
        }
    })

    new Vue({
        el: "#app",
        data: {
            content: 'hello vue'
        }
    })
</script>

在这里插入图片描述

参数 el

有了变量的数据,我们可以将数据设置为input框的value值。

<div id="app">
    <input type="text" v-slice="content"> {{content}}
</div>

<script>
    Vue.directive("slice", {
        bind(el, bindings, vnode) {
            var context = vnode.context;
            el.value = context[bindings.expression];
        },
        update(el, bindings, vnode) {},
        inserted(el, bindings, vnode) {
            el.focus();
        }
    })

    new Vue({
        el: "#app",
        data: {
            content: 'hello vue'
        }
    })
</script>

在这里插入图片描述

数据双向绑定

我们为元素绑定输入事件,每次输入时将数据更新到data中。

 <div id="app">
     <input type="text" v-slice="content"> {{content}}
 </div>

 <script>
     Vue.directive("slice", {
         bind(el, bindings, vnode) {
             var context = vnode.context;
             el.value = context[bindings.expression];

             el.oninput = e => {
                 var value = e.target.value;
                 context[bindings.expression] = value;
             }
         },
         update(el, bindings, vnode) {},
         inserted(el, bindings, vnode) {
             el.focus();
         }
     })

     new Vue({
         el: "#app",
         data: {
             content: 'hello vue'
         }
     })
 </script>

指令参数属性

指令可以添加参数和一些指令,这些都被保存在bindings中。

<div id="app">
    <input type="text" v-slice:11.number="content"> {{content}}
</div>

在这里插入图片描述

限制数据的长度

<div id="app">
    <input type="text" v-slice:11.number="content"> {{content}}
</div>

<script>
    Vue.directive("slice", {
        bind(el, bindings, vnode) {
            var context = vnode.context;
            el.value = context[bindings.expression];

            // 数据双向绑定
            el.oninput = e => {
                var value = e.target.value;
                context[bindings.expression] = value;
            }

            // 限制长度
            var length = bindings.arg;
            if (length) {
                var initval = context[bindings.expression].slice(0, length);
                context[bindings.expression] = initval;
                el.value = initval;
            }
        },
        update(el, bindings, vnode) {
            var context = vnode.context;

            // 限制长度
            var length = bindings.arg;
            if (length) {
                var initval = context[bindings.expression].slice(0, length);
                context[bindings.expression] = initval;
                el.value = initval;
            }
        },
        inserted(el, bindings, vnode) {
            el.focus();
        }
    })

    new Vue({
        el: "#app",
        data: {
            content: 'hello vue123213213123213213safsadqwewqeqweqwe'
        }
    })
</script>

限制数据内容

<div id="app">
    <input type="text" v-slice:11.number="content"> {{content}}
</div>

<script>
    Vue.directive("slice", {
        bind(el, bindings, vnode) {
            var context = vnode.context;
            el.value = context[bindings.expression];

            // 数据双向绑定
            el.oninput = e => {
                var value = e.target.value;
                context[bindings.expression] = value;
            }

            // 限制长度
            var length = bindings.arg;
            if (length) {
                var initval = context[bindings.expression].slice(0, length);
                context[bindings.expression] = initval;
                el.value = initval;
            }

            // 设置为number
            var IsNumber = bindings.modifiers.number;
            if (IsNumber) {
                var initval = context[bindings.expression].replace(/[^0-9]/g, '');
                context[bindings.expression] = initval;
                el.value = initval;
            }
        },
        update(el, bindings, vnode) {
            var context = vnode.context;

            // 限制长度
            var length = bindings.arg;
            if (length) {
                var initval = context[bindings.expression].slice(0, length);
                context[bindings.expression] = initval;
                el.value = initval;
            }

            // 设置为number
            var IsNumber = bindings.modifiers.number;
            if (IsNumber) {
                var initval = context[bindings.expression].replace(/[^0-9]/g, '');
                context[bindings.expression] = initval;
                el.value = initval;
            }
        },
        inserted(el, bindings, vnode) {
            el.focus();
        }
    })

    new Vue({
        el: "#app",
        data: {
            content: 'hello vue123213213123213213safsadqwewqeqweqwe'
        }
    })
</script>

总结

就这样,一个自定义的指令完成了,我们从以上的自定义中简化的模拟了v-model的指令,当然也可以你自定义其他的指令,快去试一下吧~

Logo

前往低代码交流专区

更多推荐