vue中自定義指令directive的詳細(xì)指南
一、 什么是自定義指令
我們看到的v-開(kāi)頭的行內(nèi)屬性,都是指令,不同的指令可以完成或?qū)崿F(xiàn)不同的功能,對(duì)普通 DOM元素進(jìn)行底層操作,這時(shí)候就會(huì)用到自定義指令。除了核心功能默認(rèn)內(nèi)置的指令 (v-model 和 v-show),Vue 也允許注冊(cè)自定義指令
指令使用的幾種方式:
//會(huì)實(shí)例化一個(gè)指令,但這個(gè)指令沒(méi)有參數(shù) `v-xxx` // -- 將值傳到指令中 `v-xxx="value"` // -- 將字符串傳入到指令中,如`v-html="'<p>內(nèi)容</p>'"` `v-xxx="'string'"` // -- 傳參數(shù)(`arg`),如`v-bind:class="className"` `v-xxx:arg="value"` // -- 使用修飾符(`modifier`) `v-xxx:arg.modifier="value"`
二、 如何自定義指令
注冊(cè)一個(gè)自定義指令有全局注冊(cè)與局部注冊(cè)
全局注冊(cè)注冊(cè)主要是用過(guò)Vue.directive方法進(jìn)行注冊(cè)
Vue.directive第一個(gè)參數(shù)是指令的名字(不需要寫(xiě)上v-前綴),第二個(gè)參數(shù)可以是對(duì)象數(shù)據(jù),也可以是一個(gè)指令函數(shù)
// 注冊(cè)一個(gè)全局自定義指令 `v-focus` Vue.directive('focus', { // 當(dāng)被綁定的元素插入到 DOM 中時(shí)…… inserted: function (el) { // 聚焦元素 el.focus() // 頁(yè)面加載完成之后自動(dòng)讓輸入框獲取到焦點(diǎn)的小功能 } })
局部注冊(cè)通過(guò)在組件options選項(xiàng)中設(shè)置directive屬性
directives: { focus: { // 指令的定義 inserted: function (el) { el.focus() // 頁(yè)面加載完成之后自動(dòng)讓輸入框獲取到焦點(diǎn)的小功能 } } }
然后你可以在模板中任何元素上使用新的 v-focus property,如下:
<input v-focus />
鉤子函數(shù)
自定義指令也像組件那樣存在鉤子函數(shù):
- bind:只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用。在這里可以進(jìn)行一次性的初始化設(shè)置
- inserted:被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用 (僅保證父節(jié)點(diǎn)存在,但不一定已被插入文檔中)
- update:所在組件的 VNode 更新時(shí)調(diào)用,但是可能發(fā)生在其子 VNode更新之前。指令的值可能發(fā)生了改變,也可能沒(méi)有。但是你可以通過(guò)比較更新前后的值來(lái)忽略不必要的模板更新
- componentUpdated:指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用
- unbind:只調(diào)用一次,指令與元素解綁時(shí)調(diào)用
所有的鉤子函數(shù)的參數(shù)都有以下:
- el:指令所綁定的元素,可以用來(lái)直接操作 DOM
- binding:一個(gè)對(duì)象,包含以下 property:
`name`:指令名,不包括 v- 前綴。
`value`:指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值為 2。
`oldValue`:指令綁定的前一個(gè)值,僅在 update 和 componentUpdated 鉤子中可用。無(wú)論值是否改變都可用。
`expression`:字符串形式的指令表達(dá)式。例如 v-my-directive="1 + 1" 中,表達(dá)式為 "1 + 1"。
`arg`:傳給指令的參數(shù),可選。例如 v-my-directive:foo 中,參數(shù)為 "foo"。
`modifiers`:一個(gè)包含修飾符的對(duì)象。例如:v-my-directive.foo.bar 中,修飾符對(duì)象為 { foo: true, bar: true }
`vnode`:Vue 編譯生成的虛擬節(jié)點(diǎn)
`oldVnode`:上一個(gè)虛擬節(jié)點(diǎn),僅在 update 和 componentUpdated 鉤子中可用
除了 el 之外,其它參數(shù)都應(yīng)該是只讀的,切勿進(jìn)行修改。如果需要在鉤子之間共享數(shù)據(jù),建議通過(guò)元素的 dataset 來(lái)進(jìn)行
舉個(gè)例子:
<div v-demo="{ color: 'white', text: 'hello!' }"></div> <script> Vue.directive('demo', function (el, binding) { console.log(binding.value.color) // "white" console.log(binding.value.text) // "hello!" }) </script>
三、應(yīng)用場(chǎng)景
使用自定義組件組件可以滿足我們?nèi)粘R恍﹫?chǎng)景,這里給出幾個(gè)自定義組件的案例:
- 防抖
- 圖片懶加載
- 一鍵 Copy的功能
輸入框防抖
防抖這種情況設(shè)置一個(gè)v-throttle自定義指令來(lái)實(shí)現(xiàn)
舉個(gè)例子:
// 1.設(shè)置v-throttle自定義指令 Vue.directive('throttle', { bind: (el, binding) => { let throttleTime = binding.value; // 防抖時(shí)間 if (!throttleTime) { // 用戶若不設(shè)置防抖時(shí)間,則默認(rèn)2s throttleTime = 2000; } let cbFun; el.addEventListener('click', event => { if (!cbFun) { // 第一次執(zhí)行 cbFun = setTimeout(() => { cbFun = null; }, throttleTime); } else { event && event.stopImmediatePropagation(); } }, true); }, }); // 2.為button標(biāo)簽設(shè)置v-throttle自定義指令 <button @click="sayHello" v-throttle>提交</button>
圖片懶加載
設(shè)置一個(gè)v-lazy自定義組件完成圖片懶加載
const LazyLoad = { // install方法 install(Vue,options){ // 代替圖片的loading圖 let defaultSrc = options.default; Vue.directive('lazy',{ bind(el,binding){ LazyLoad.init(el,binding.value,defaultSrc); }, inserted(el){ // 兼容處理 if('InterpObserver' in window){ LazyLoad.observe(el); }else{ LazyLoad.listenerScroll(el); } }, }) }, // 初始化 init(el,val,def){ // src 儲(chǔ)存真實(shí)src el.setAttribute('src',val); // 設(shè)置src為loading圖 el.setAttribute('src',def); }, // 利用InterpObserver監(jiān)聽(tīng)el observe(el){ let io = new InterpObserver(entries => { let realSrc = el.dataset.src; if(entries[0].isIntersecting){ if(realSrc){ el.src = realSrc; el.removeAttribute('src'); } } }); io.observe(el); }, // 監(jiān)聽(tīng)scroll事件 listenerScroll(el){ let handler = LazyLoad.throttle(LazyLoad.load,300); LazyLoad.load(el); window.addEventListener('scroll',() => { handler(el); }); }, // 加載真實(shí)圖片 load(el){ let windowHeight = document.documentElement.clientHeight let elTop = el.getBoundingClientRect().top; let elBtm = el.getBoundingClientRect().bottom; let realSrc = el.dataset.src; if(elTop - windowHeight<0&&elBtm > 0){ if(realSrc){ el.src = realSrc; el.removeAttribute('src'); } } }, // 節(jié)流 throttle(fn,delay){ let timer; let prevTime; return function(...args){ let currTime = Date.now(); let context = this; if(!prevTime) prevTime = currTime; clearTimeout(timer); if(currTime - prevTime > delay){ prevTime = currTime; fn.apply(context,args); clearTimeout(timer); return; } timer = setTimeout(function(){ prevTime = Date.now(); timer = null; fn.apply(context,args); },delay); } } } export default LazyLoad;
一鍵 Copy的功能
import { Message } from 'ant-design-vue'; const vCopy = { // /* bind 鉤子函數(shù),第一次綁定時(shí)調(diào)用,可以在這里做初始化設(shè)置 el: 作用的 dom 對(duì)象 value: 傳給指令的值,也就是我們要 copy 的值 */ bind(el, { value }) { el.$value = value; // 用一個(gè)全局屬性來(lái)存?zhèn)鬟M(jìn)來(lái)的值,因?yàn)檫@個(gè)值在別的鉤子函數(shù)里還會(huì)用到 el.handler = () => { if (!el.$value) { // 值為空的時(shí)候,給出提示,我這里的提示是用的 ant-design-vue 的提示,你們隨意 Message.warning('無(wú)復(fù)制內(nèi)容'); return; } // 動(dòng)態(tài)創(chuàng)建 textarea 標(biāo)簽 const textarea = document.createElement('textarea'); // 將該 textarea 設(shè)為 readonly 防止 iOS 下自動(dòng)喚起鍵盤(pán),同時(shí)將 textarea 移出可視區(qū)域 textarea.readOnly = 'readonly'; textarea.style.position = 'absolute'; textarea.style.left = '-9999px'; // 將要 copy 的值賦給 textarea 標(biāo)簽的 value 屬性 textarea.value = el.$value; // 將 textarea 插入到 body 中 document.body.appendChild(textarea); // 選中值并復(fù)制 textarea.select(); // textarea.setSelectionRange(0, textarea.value.length); const result = document.execCommand('Copy'); if (result) { Message.success('復(fù)制成功'); } document.body.removeChild(textarea); }; // 綁定點(diǎn)擊事件,就是所謂的一鍵 copy 啦 el.addEventListener('click', el.handler); }, // 當(dāng)傳進(jìn)來(lái)的值更新的時(shí)候觸發(fā) componentUpdated(el, { value }) { el.$value = value; }, // 指令與元素解綁的時(shí)候,移除事件綁定 unbind(el) { el.removeEventListener('click', el.handler); }, }; export default vCopy;
拖拽
<div ref="a" id="bg" v-drag></div> directives: { drag: { bind() {}, inserted(el) { el.onmousedown = (e) => { let x = e.clientX - el.offsetLeft; let y = e.clientY - el.offsetTop; document.onmousemove = (e) => { let xx = e.clientX - x + "px"; let yy = e.clientY - y + "px"; el.style.left = xx; el.style.top = yy; }; el.onmouseup = (e) => { document.onmousemove = null; }; }; }, }, },
關(guān)于自定義組件還有很多應(yīng)用場(chǎng)景,如:拖拽指令、頁(yè)面水印、權(quán)限校驗(yàn)等等應(yīng)用場(chǎng)景
總結(jié)
到此這篇關(guān)于vue中自定義指令directive的文章就介紹到這了,更多相關(guān)vue自定義指令directive內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue開(kāi)發(fā)中常見(jiàn)的套路和技巧總結(jié)
這篇文章主要給大家介紹了關(guān)于Vue開(kāi)發(fā)中常見(jiàn)的套路和技巧的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11解決在vue的mounted中獲取對(duì)象為null問(wèn)題
這篇文章主要介紹了解決在vue的mounted中獲取對(duì)象為null問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03Vue自定義表單驗(yàn)證(rule,value,callback)使用詳解
這篇文章主要介紹了Vue自定義表單驗(yàn)證(rule,value,callback)使用詳解,今天我們講一講自定義驗(yàn)證規(guī)則具體使用場(chǎng)景和它的三個(gè)參數(shù)意思和使用,需要的朋友可以參考下2023-07-07vue中$emit傳遞多個(gè)參(arguments和$event)
本文主要介紹了vue中$emit傳遞多個(gè)參(arguments和$event),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02vue如何設(shè)置定時(shí)器和清理定時(shí)器
這篇文章主要介紹了vue如何設(shè)置定時(shí)器和清理定時(shí)器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Vue.js學(xué)習(xí)記錄之在元素與template中使用v-if指令實(shí)例
這篇文章主要給大家介紹了關(guān)于Vue.js學(xué)習(xí)記錄之在元素與template中使用v-if指令的相關(guān)資料,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),相信對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-06-06