盡管Vue推崇數(shù)據(jù)驅(qū)動(dòng)視圖的理念,然而有的情況,你仍然需要對(duì)普通 DOM 元素進(jìn)行底層操作,這時(shí)候就會(huì)用到自定義指令。
1、 鉤子函數(shù)
一個(gè)指令定義對(duì)象可以提供如下幾個(gè)鉤子函數(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)忽略不必要的模板更新 (詳細(xì)的鉤子函數(shù)參數(shù)見下)。componentUpdated:指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用。unbind:只調(diào)用一次,指令與元素解綁時(shí)調(diào)用
2、鉤子函數(shù)參數(shù)
指令鉤子函數(shù)會(huì)被傳入以下參數(shù):el:指令所綁定的元素,可以用來(lái)直接操作 DOM 。-
binding:一個(gè)對(duì)象,包含以下屬性:-
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)。移步 VNode API 來(lái)了解更多詳情。oldVnode:上一個(gè)虛擬節(jié)點(diǎn),僅在update和componentUpdated鉤子中可用。
自定義指令可以很優(yōu)雅的修改dom對(duì)象,也可以用于集成第三方插件。
接下來(lái)讓我們看看element-ui封裝的自定義指令
//mousewheel.js
//normalize-wheel是由facebook針對(duì)滾輪事件在不同瀏覽器在兼容性、滾動(dòng)距離和滾動(dòng)速度做的優(yōu)化代碼
import normalizeWheel from 'normalize-wheel';
const isFirefox = typeof navigator !== 'undefined' && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
const mousewheel = function(element, callback) {
if (element && element.addEventListener) {
element.addEventListener(isFirefox ? 'DOMMouseScroll' : 'mousewheel', function(event) {
const normalized = normalizeWheel(event);
callback && callback.apply(this, [event, normalized]);
});
}
};
//模塊暴露一個(gè)對(duì)象
export default {
bind(el, binding) {
//通過(guò)table.vue可看出binding.value是一個(gè)function,執(zhí)行mousewheel 方法將結(jié)果回調(diào)回調(diào)用方。
mousewheel(el, binding.value);
}
};
//packages/table.vue
<div
v-if="showHeader"
v-mousewheel="handleHeaderFooterMousewheel"
class="el-table__header-wrapper"
ref="headerWrapper">
<table-header
ref="tableHeader"
:store="store"
:border="border"
:default-sort="defaultSort"
:style="{
width: layout.bodyWidth ? layout.bodyWidth + 'px' : ''
}">
</table-header>
</div>
...
handleHeaderFooterMousewheel(event, data) {
const { pixelX, pixelY } = data;
if (Math.abs(pixelX) >= Math.abs(pixelY)) {
event.preventDefault();
this.bodyWrapper.scrollLeft += data.pixelX / 5;
}
},
...
import Mousewheel from 'element-ui/src/directives/mousewheel';
...
//組件內(nèi)局部注冊(cè)
directives: {
Mousewheel
},