Vue自定義指令的使用詳細(xì)介紹
1. 概述
除了核心功能默認(rèn)內(nèi)置的指令,Vue也允許注冊(cè)自定義指令。有的情況下,對(duì)普通 DOM 元素進(jìn)行底層操作,這時(shí)候就會(huì)用到自定義指令綁定到元素上執(zhí)行相關(guān)操作。
自定義指令分為:
全局指令和局部指令,當(dāng)全局指令和局部指令同名時(shí)以局部指令為準(zhǔn)。
局部指令:只對(duì)當(dāng)前實(shí)例(或組件)生效
全局指令:對(duì)全部實(shí)例(或組件)都生效
2. 鉤子函數(shù)
自定義指令常用鉤子函數(shù):
- bind 第一次綁定到元素時(shí)調(diào)用(初始化)
- inserted 被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用 (僅保證父節(jié)點(diǎn)存在,但不一定已被插入文檔中)
- update 數(shù)據(jù)更新時(shí)調(diào)用
- componentUpdated 指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用。
- unbind 只調(diào)用一次,指令與元素解綁時(shí)調(diào)用。
指令的鉤子會(huì)傳遞以下幾種參數(shù):
el:指令綁定到的元素。這可以用于直接操作 DOM。
binding:一個(gè)對(duì)象,包含以下屬性。
value:傳遞給指令的值。例如在v-my-directive="1 + 1"中,值是 2。oldValue:之前的值,僅在beforeUpdate和updated中可用。無論值是否更改,它都可用。arg:傳遞給指令的參數(shù) (如果有的話)。例如在v-my-directive:foo中,參數(shù)是"foo"。modifiers:一個(gè)包含修飾符的對(duì)象 (如果有的話)。例如在v-my-directive.foo.bar中,修飾符對(duì)象是{ foo: true, bar: true }。instance:使用該指令的組件實(shí)例。dir:指令的定義對(duì)象。
vnode:代表綁定元素的底層 VNode。
prevNode:之前的渲染中代表指令所綁定元素的 VNode。僅在 beforeUpdate 和 updated 鉤子中可用。
鉤子函數(shù)可以理解為一個(gè)類,類中的構(gòu)造函數(shù)綁定了5個(gè)函數(shù)(即鉤子函數(shù)),當(dāng)我們自定義鉤子函數(shù)時(shí),就會(huì)初始化這個(gè)類,然后讓我們的相關(guān)代碼按順序執(zhí)行這5個(gè)函數(shù)。
有關(guān)鉤子函數(shù)更詳細(xì)的解釋,下面這篇文章中的前兩個(gè)教程寫得很通俗易懂,特此推薦:
鉤子函數(shù)的執(zhí)行順序:
<div id="app1">
<div v-red v-if="isShow">
<input type="text" v-model="title">
</div>
</div>
<script>
Vue.directive('red', {
// bind 第一次綁定到元素時(shí)調(diào)用
bind(el, bindings) {
console.log('bind');
},
// inserted
inserted(el, bindings) {
console.log('inserted');
},
// update
update(el, bindings) {
console.log('update');
},
// componentUpdate
componentUpdated(el, bindings) {
console.log('componentUpdated');
},
// unbind
unbind(el, bindings) {
console.log('unbind');
},
})
const vm1 = new Vue({
el: '#app1',
data: {
isShow: true,
title: '鉤子函數(shù)執(zhí)行順序'
}
})
</script>程序一執(zhí)行,當(dāng)數(shù)據(jù)源中的數(shù)據(jù)第一次綁定了元素就會(huì)執(zhí)行bind函數(shù),當(dāng)綁定元素插入到父元素中,即顯示到視圖中時(shí),會(huì)執(zhí)行inserted函數(shù):

當(dāng)我們改變視圖,使得數(shù)據(jù)發(fā)生改變時(shí),就會(huì)執(zhí)行update和componentUpdated函數(shù):

當(dāng)我們銷毀被綁定元素時(shí),即被綁定元素和數(shù)據(jù)源解綁,就會(huì)觸發(fā)unbind函數(shù):


3. 自定義全局指令
描述:
全局定義的指令,所有的組件或vue的實(shí)例都會(huì)生效。
語法:
Vue.directive('指令名稱,不需要寫v-開頭',對(duì)象或函數(shù))
Vue.directive('test',{
bind(el,bind){
console.log(el)
}
})
案例:
<div id="app1">
<div v-red>{{title}}</div>
</div>
<div id="app2">
<div v-red>標(biāo)題2</div>
</div>
<script>
//自定義全局指令
Vue.directive('red', {
// bind 第一次綁定到元素時(shí)調(diào)用
bind(el, bindings) {
el.style.cssText = `color:red;font-size:30px`
}
})
const vm1 = new Vue({
el: '#app1',
data: {
isShow: true,
title: '標(biāo)題1'
}
})
const vm2 = new Vue({
el: '#app2',
data: {
}
})
</script>
4. 自定義局部指令
描述:
定義局部指令,只有當(dāng)前的實(shí)例能用。
語法:
new Vue({
directives: {
test:{
bind(el,bind){}
},
// bind/update
test2(el,bind){}
}
})
案例:
<div id="app1">
<div v-red>{{title}}</div>
</div>
<div id="app2">
<div v-red>標(biāo)題2</div>
</div>
<script>
const vm1 = new Vue({
el: '#app1',
data: {
isShow: true,
title: '標(biāo)題1'
},
// 定義局部指令,只有當(dāng)前的實(shí)例能用
directives: {
red: {
// bind它還沒有綁定到父元素中,初始化
bind(el) {
el.style.cssText = `color:red;font-size:30px`
}
}
}
})
const vm2 = new Vue({
el: '#app2',
data: {
},
directives: {
red: {
bind(el) {
el.style.cssText = `color:blue;font-size:30px`
}
}
}
})
</script>
利用自定義局部指令操作Dom:
<div id="app1">
<div v-red>{{title}}</div>
</div>
<div id="app2">
<div v-red>標(biāo)題2</div>
</div>
<script>
const vm1 = new Vue({
el: '#app1',
data: {
isShow: true,
title: '標(biāo)題1'
},
directives: {
red: {
// bind表示被綁定元素還沒有插入到父元素中
bind(el) {
el.style.cssText = `color:red;font-size:30px`
const divDom = document.createElement('div')
divDom.innerHTML = '我是標(biāo)題1的孩子'
el.appendChild(divDom)
},
// 這時(shí)被綁定元素已經(jīng)插入到父元素中去了,所以可以打印出被綁定元元素的父節(jié)點(diǎn)
inserted(el) {
console.log(el.parentNode);
}
}
}
})
const vm2 = new Vue({
el: '#app2',
data: {
},
directives: {
red: {
bind(el) {
el.style.cssText = `color:blue;font-size:30px`
}
}
}
})
</script>
注意:在上面的代碼中,我們?cè)?code>bind函數(shù)中,不能獲取當(dāng)前被綁定元素的父節(jié)點(diǎn),因?yàn)榇藭r(shí)被綁定元素剛剛初始化,還沒有插入到父節(jié)點(diǎn)當(dāng)中。在inserted函數(shù)中才能獲取被綁定元素的父節(jié)點(diǎn),因?yàn)榇藭r(shí)元素已經(jīng)插入到父節(jié)點(diǎn)當(dāng)中去了。
5. 使用自定義指令實(shí)現(xiàn)權(quán)限管理
目標(biāo):
根據(jù)地址欄中的數(shù)據(jù),決定是否顯示 button 按鈕。如果地址欄中的 username 的值是 admin 時(shí),就顯示 button 按鈕,否則不顯示。
注意:目標(biāo)中的顯示與不顯示,是取決于該 Dom 元素(button 按鈕)是否存在,而不是通過 css 來進(jìn)行顯示與隱藏。
代碼:
<div id="app1">
<button v-auth>查看工資</button>
</div>
<script>
const vm1 = new Vue({
el: '#app1',
data: {
isShow: true,
title: '標(biāo)題1'
},
directives: {
auth: {
// 注意:是否刪除按鈕的操作,必須在被綁定元素(即當(dāng)前元素)已經(jīng)插入父節(jié)點(diǎn)(插入到視圖)當(dāng)中后進(jìn)行
inserted(el) {
// 這是一種比較粗暴的寫法,可維護(hù)性較低
// if (location.search != '?username=admin') {
// el.remove()
// }
// URLSearchParams它是html5提供的新的Api方法,用于獲取url地址中的search轉(zhuǎn)為對(duì)象
let urlSearch = new URLSearchParams(location.search)
// 這樣的寫法可維護(hù)性較高,假如顯示元素的權(quán)限還需要給到 張三 用戶,則直接修改判斷條件中的表達(dá)式即可
if (urlSearch.get('username') != 'admin') {
// 以前兼容性更好的寫法,但是現(xiàn)在可以不管
// el.parentNode.removeChild(el)
el.remove()
}
}
}
}
})
</script>

6. 使用自定義指令實(shí)現(xiàn)表單驗(yàn)證
首先我們先完成驗(yàn)證手機(jī)號(hào)的功能。
目標(biāo):
在初始化(在 bind 函數(shù)中進(jìn)行)和更新數(shù)據(jù)(在 update 函數(shù)中進(jìn)行)時(shí)都要進(jìn)行手機(jī)號(hào)的驗(yàn)證。
思路:
先獲取手機(jī)號(hào)(收集數(shù)據(jù)),再用正則表達(dá)式判斷輸入框中的手機(jī)號(hào)是否合法,如果合法則手機(jī)號(hào)顯示黑色,如果不合法則手機(jī)號(hào)顯示紅色。
代碼:
<div id="app">
<div>
<input type="text" v-phone="phone" v-model="phone">
</div>
</div>
<script>
Vue.directive('phone', {
// 方法1:直接通過dom來完成數(shù)據(jù)的收集
// update(el) {
// console.log(el.value);
// }
// 方法2:可以通過傳值的方式(鉤子函數(shù))完成數(shù)據(jù)收集
bind(el, { value }) {
// 手機(jī)號(hào)碼
let reg = /^1[3-9]\d{9}$/
if (!reg.test(value)) {
// 不合法
el.style.color = 'red'
} else {
el.style.color = 'black'
}
},
update(el, { value }) {
// 手機(jī)號(hào)碼
let reg = /^1[3-9]\d{9}$/
if (!reg.test(value)) {
// 不合法
el.style.color = 'red'
} else {
el.style.color = 'black'
}
}
})
const vm1 = new Vue({
el: '#app',
data: {
phone: '13525125121',
}
})
</script>
在上面代碼中,通過鉤子函數(shù)完成數(shù)據(jù)獲取與驗(yàn)證,代碼重復(fù)率高,所以在鉤子函數(shù)部分,我們可以簡(jiǎn)寫成下面這種方式:
Vue.directive('phone', (el, { value }) => {
// 手機(jī)號(hào)碼
let reg = /^1[3-9]\d{9}$/
if (!reg.test(phone)) {
// 不合法
el.style.color = 'red'
} else {
el.style.color = 'black'
}
})
注意:簡(jiǎn)寫方式就是自定義指令語法中,第二個(gè)參數(shù)是函數(shù)的寫法。自定義指令的簡(jiǎn)寫,指的是將 bind 函數(shù)和 update 函數(shù)封裝起來的寫法。
在上面的基礎(chǔ)上,我們?cè)偌由向?yàn)證錯(cuò)誤信息的顯示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue學(xué)習(xí)使用</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<input type="text" v-phone="phone" v-model="phone">
</div>
</div>
<script>
Vue.directive('phone', (el, { value }) => {
// 手機(jī)號(hào)碼
let reg = /^1[3-9]\d{9}$/
if (!reg.test(value)) {
// 不合法
el.style.color = 'red'
// 沒有 span 標(biāo)簽時(shí),就創(chuàng)建 span 標(biāo)簽
if (!el.nextSibling) {
const spanDom = document.createElement('span')
spanDom.innerHTML = '不合法,修改一下'
// 這里是防止初始化時(shí)數(shù)據(jù)就不合法,導(dǎo)致被綁定元素不能成功插入到父結(jié)點(diǎn)中
// el.parentNode?.appendChild(spanDom)
// 上面的寫法要求的瀏覽器版本較高,下面的寫法兼容性更好
el.parentNode && el.parentNode.appendChild(spanDom)
}
} else {// 輸入正確時(shí),移除 span 標(biāo)簽
el.style.color = 'black'
el.nextSibling && el.nextSibling.remove()
}
})
const vm1 = new Vue({
el: '#app',
data: {
phone: '13525125121',
phoneMsg: ''
}
})
</script>
</body>
</html>
最后,我們使用模塊化的的思路,將案例完善一下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue學(xué)習(xí)使用</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<div>
<!-- 這種寫法的 value 值直接就是 phone -->
<!-- <input type="text" v-validate="phone" v-model="phone"> -->
<input type="text" v-validate.phone v-model="phone">
</div>
<div>
<input type="text" v-validate.email v-model="email">
</div>
<div>
<!-- "{len:3,msg:'長(zhǎng)度過長(zhǎng)'}":v-validate指令的value值 -->
<input type="text" v-validate.str="{len:3,msg:'長(zhǎng)度過長(zhǎng)'}" v-model="str">
</div>
</div>
<script>
// 在對(duì)象里存方法
const validateMethod = {
phone(el) {
// 手機(jī)號(hào)碼
let reg = /^1[3-9]\d{9}$/
if (!reg.test(el.value)) {
// 不合法
el.style.color = 'red'
if (!el.nextSibling) {
const spanDom = document.createElement('span')
spanDom.innerHTML = '不合法,修改一下'
// el.parentNode?.appendChild(spanDom)
el.parentNode && el.parentNode.appendChild(spanDom)
}
} else {
el.style.color = 'black'
el.nextSibling && el.nextSibling.remove()
}
console.log('phone');
},
email(el, value) {
console.log('email')
},
str(el, value) {
// 這里這個(gè)判斷是容錯(cuò)處理,也可以不寫。因?yàn)槲覀兩厦娴拇a中給 value傳值了
// 如果當(dāng)前封裝好的代碼(當(dāng)作組件)給別人使用的話,使用者可能不穿值
if (value) {
if (el.value.length > value.len) {
if (!el.nextSibling) {
const spanDom = document.createElement('span')
spanDom.innerHTML = value.msg
// 防止初始化數(shù)據(jù)不合法,父節(jié)點(diǎn)不存在
el.parentNode?.appendChild(spanDom)
}
} else {
el.nextSibling?.remove()
}
}
}
}
Vue.directive('validate', (el, { value, modifiers }) => {
// modifiers:一個(gè)包含修飾符的對(duì)象 (如果有的話)。
// console.log(Object.keys(modifiers))===phone
Object.keys(modifiers).forEach(name => {
// 調(diào)用對(duì)象中的方法
validateMethod[name](el, value)
})
})
const vm1 = new Vue({
el: '#app',
data: {
phone: '13525125121',
email: 'aa@aa.com',
str: 'aaa'
},
methods: {
}
})
</script>
</body>
</html>
注意:
v-validate="phone"的 value 值是數(shù)據(jù)源中的 phone,v-validate.phone的 value 值是 undefined,v-validate.str="{len:3,msg:'長(zhǎng)度過長(zhǎng)'}"的 value 值是{len:3,msg:'長(zhǎng)度過長(zhǎng)'}。
到此這篇關(guān)于Vue自定義指令的使用詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Vue自定義指令內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue.js axios響應(yīng)攔截如何獲取返回狀態(tài)碼
這篇文章主要介紹了Vue.js axios響應(yīng)攔截如何獲取返回狀態(tài)碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
一個(gè)因@click.stop引發(fā)的bug的解決
這篇文章主要介紹了一個(gè)因@click.stop引發(fā)的bug的解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
vite+vue3+element-plus項(xiàng)目搭建的方法步驟
因?yàn)関ue3出了一段時(shí)間了,element也出了基于vue3.x版本的element-plus,vite打包聽說很快,嘗試一下,感興趣的可以了解一下2021-06-06
Vue中使用this.$set()如何新增數(shù)據(jù),更新視圖
這篇文章主要介紹了Vue中使用this.$set()實(shí)現(xiàn)新增數(shù)據(jù),更新視圖方式。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
vue修改數(shù)據(jù)的時(shí)候,表單值回顯不正確問題及解決
這篇文章主要介紹了vue修改數(shù)據(jù)的時(shí)候,表單值回顯不正確的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11

