vue自定義指令模擬v-model指令

前言

通常情況下,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

鉤子函數 參數 描述
bind el,bindingd,vnode 綁定指令時觸發
update el,bindingd,vnode 數據更新數觸發
inserted el 插入到頁面時觸發

其中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的指令,當然也可以你自定義其他的指令,快去試一下吧~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章