Vue學(xué)習(xí)——指令(四)

本文承接上文,繼續(xù)對Vue的指令進(jìn)行介紹,同時也是指令系列的終章。建議讀者先閱讀上篇文章卦方,以免有不解之處。前文請參考“Vue學(xué)習(xí)——指令(三)”

自定義指令

前文已經(jīng)介紹了Vue所有的內(nèi)置指令泰佳,這些指令可以滿足大多數(shù)業(yè)務(wù)需求盼砍,然而,在某些特殊情況下逝她,我們希望可以對普通的DOM元素進(jìn)行底層操作浇坐,這時我們就需要用到自定義指令了。

自定義指令的注冊

自定義指令需要注冊后才能使用汽绢,Vue提供了兩種注冊方式:全局注冊和局部注冊吗跋。全局注冊使用Vue.directive()方法來注冊一個全局自定義指令,該方法接收兩個參數(shù)宁昭,第一個參數(shù)是指令的ID跌宛;第二個參數(shù)是一個定義對象或者函數(shù)對象,指令要實現(xiàn)的功能在這個對象中定義积仗。

語法形式如下:

Vue.directive(id, [definition])

例如疆拘,要編寫一個讓元素自動獲取焦點的全局指令,代碼示例如下:

Vue.directive('focus', {...})

全局指令可以在任何Vue實例的模版中使用,代碼示例如下:

<div id="app">
    <input v-focus>
</div>

<div id="app2">
    <input v-focus>
</div>

<script>
    Vue.directive('focus', {
        // ...
    })
    new Vue({
        el: '#app'
    })

    new Vue({
        el: '#app2'
    })
</script>

v-focus是一個全局自定義指令寂曹,因此可以在任何Vue實例的模版中使用哎迄。

局部注冊是在Vue實例的選項對象中使用directives選項進(jìn)行注冊,代碼示例如下:

new Vue({
    el: '#app',
    directives: {
        // 注冊一個局部的自定義指令
        focus: {
            // ...
        }
    }
})
  • 局部注冊的自定義指令只能在該實例綁定的視圖中使隆圆。

看下面的示例:

<div id="app">
    <input v-focus>
</div>

<div id="app2">
    <input v-focus>
</div>

<script>
    new Vue({
        el: '#app'
        directives: {
            // 注冊一個局部的自定義指令
            focus: {
                // ...
            }
        }
    })

    new Vue({
        el: '#app2'
    })
</script>

在瀏覽器打開該頁面時漱挚,Vue會給出一個警告信息:[Vue warn]: Failed to resolve directive: focus

鉤子函數(shù)

自定義指令的功能是在定義對象中實現(xiàn)的,而定義對象則是由鉤子函數(shù)組成的渺氧,Vue提供了下面幾個鉤子函數(shù)旨涝,這些鉤子函數(shù)都是可選的。

  • bind: 只調(diào)用一次侣背,指令第一次綁定到元素時調(diào)用白华。指令如果需要一些一次性的初始化設(shè)置,可以放到這個鉤子函數(shù)中贩耐。
  • inserted: 被綁定元素插入父節(jié)點時調(diào)用(父節(jié)點存在即可調(diào)用弧腥,不必存在于document對象中)
  • update: 所在組件的VNode更新時調(diào)用(無論指令的值是否發(fā)生了變化),但是可能發(fā)生在其子VNode更新之前潮太」芴拢可以通過比較更新前后的值來忽略不必要的模版更新。
  • componentUpdated: 指令所在組件的VNode及其子VNode全部更新后調(diào)用。
  • unbind: 只調(diào)用一次抛蚤,指令與元素解綁時調(diào)用台谢。

根據(jù)指令要實現(xiàn)功能的不同寻狂,選擇相應(yīng)的鉤子函數(shù)來編寫代碼岁经。

例:在元素插入父節(jié)點時自動獲得焦點,代碼示例如下:

<div id="app">
    <input v-focus>
</div>

<script>
    // 注冊一個全局自定義指令
    Vue.directive('focus', {
        // 當(dāng)綁定元素插入父節(jié)點時
        inserted: function(el) {
            el.focus()
        }
    })

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

指令的鉤子函數(shù)可以帶有一些參數(shù)蛇券,例如上述代碼中的el參數(shù)缀壤,具體的參數(shù)列表如下所示:

  1. el:指令所綁定的元素,可以用來直接操作DOM纠亚。
  2. binding:一個對象塘慕,包括以下屬性:
    • name:指令名,不包括v-前綴蒂胞。
    • value:指令的綁定值图呢。
    • oldValue:指令綁定的前一個值,僅在update和componentUpdated鉤子中可用骗随。無論值是否改變都可用蛤织。
    • expression:字符串形式的指令表達(dá)式。
    • arg:傳給指令的參數(shù)鸿染,可選指蚜。
    • modifiers:一個包含修飾符的對象。
  3. vonde:Vue編譯生成的虛擬節(jié)點涨椒。
  4. oldVonde:上一個虛擬節(jié)點摊鸡,僅在update和componentUpdated鉤子中可用。

要注意的是蚕冬,除了el參數(shù)外免猾,其他參數(shù)都應(yīng)該時只讀的,切勿進(jìn)行修改囤热。

下面編寫一個自定義指令猎提,在其鉤子函數(shù)中將各個參數(shù)輸出,代碼示例如下:

<div id="app" v-demo:foo.a.b="message"></div>

<script>
    Vue.directive('demo', {
        bind: function(el, binding, vnode) {
            var s = JSON.stringify
            el.innerHTML = 
                'name: ' + s(binding.name) + '<br>' +
                'value: ' + s(binding.value) + '<br>' +
                'expression: ' + s(binding.expression) + '<br>' +
                'argument: ' + s(binding.arg) + '<br>' +
                'modifiers: ' + s(binding.modifiers) + '<br>' +
                'vnode keys: ' + Object.keys(vnode).join(',') 
        }
    })

    new Vue({
        el: '#app',
        data: {
            message: 'Hello'
        }
    })
</script>

我們將bind鉤子函數(shù)的所有參數(shù)信息取出來拼接成字符串赢乓,賦值給<div>元素的innerHTML屬性忧侧。渲染結(jié)果如下:

name: "demo"
value: "Hello"
expression: "message"
argument: "foo"
modifiers: {"a": true, "b": true}
vnode keys: tag, data, children, text, elm, ns, context, fnContext, fnOptions, fnScopeId, key, componentOptions, componentInstance, parent, ra, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholder

動態(tài)指令參數(shù)

在之前的文章中已經(jīng)介紹過,指令的參數(shù)可以是動態(tài)參數(shù)牌芋,同樣地蚓炬,自定義的指令也可以使用動態(tài)參數(shù)。

例:我們想讓某個元素固定在頁面中的某個位置躺屁,在出現(xiàn)滾動條時肯夏,元素也不會隨著滾動。這可以通過設(shè)置CSS樣式屬性position為fixed來實現(xiàn),同時使用top驯击、right烁兰、botton、left等屬性以窗口為參考點來進(jìn)行定位徊都。下面通過自定義指令來實現(xiàn)這個功能沪斟。代碼示例如下:

<div id="app">
    <!--  直接給出指令的參數(shù)  -->
    <p v-pin:top="100">
        Vue學(xué)習(xí)
    </p>
    <!--  使用動態(tài)參數(shù)  -->
    <p v-pin:[direction]="100">
        Vue學(xué)習(xí)
    </p>
</div>

<script>
    Vue.directive('pin', {
        bind: function(el, binding, vnode) {
            el.style.position = 'fixed';
            let s = binding.arg || 'left';
            el.style[s] = binding.value + 'px'
        }
    })

    new Vue({
        el: '#app',
        data: {
            direction: 'left'
        }
    })
</script>

函數(shù)簡寫

如果自定義指令在bind和update鉤子函數(shù)中的行為一致,且只需要用到這兩個鉤子函數(shù)暇矫,那么可以在注冊時傳遞一個函數(shù)對象作為參數(shù)主之。

代碼示例如下:

Vue.directive('color-swatch', function(el, binding) {
    el.style.backgroundColor = binding.value
})

對象字面量

如果指令需要多個值,可以傳入一個JavaScript對象字面量李根。要記住的是槽奕,指令可以接收所有合法的JavaScript表達(dá)式。

<div v-demo="{color: 'white', text: 'hello'}"></div>
<!--  省略非關(guān)鍵代碼  -->
Vue.directive('demo', function(el, binding) {
    console.log(binding.value.color)
    console.log(binding.value.text)
})

以上便是Vue指令這一系列的全部內(nèi)容房轿,應(yīng)該說最常用的指令就是v-if粤攒、v-for、v-on囱持、v-bind和v-model夯接,只要熟練掌握這五個指令的用法即可完成大部分工作。

此外洪唐,在指令系列還介紹了自定義指令的開發(fā)钻蹬。需要注意的是,自定義指令只應(yīng)該用于封裝對DOM的操作凭需,不要將其用作別的用途问欠。在某些特殊需求下,通過自定義指令來封裝DOM操作粒蜈,可以簡化代碼的編寫顺献,提高代碼的重用型。

在下篇文章中枯怖,打算寫幾個實際場景中用得到的示例注整,敬請期待!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末度硝,一起剝皮案震驚了整個濱河市肿轨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蕊程,老刑警劉巖椒袍,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異藻茂,居然都是意外死亡驹暑,警方通過查閱死者的電腦和手機(jī)玫恳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來优俘,“玉大人京办,你說我怎么就攤上這事》溃” “怎么了惭婿?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長视搏。 經(jīng)常有香客問我审孽,道長县袱,這世上最難降的妖魔是什么浑娜? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮式散,結(jié)果婚禮上筋遭,老公的妹妹穿的比我還像新娘。我一直安慰自己暴拄,他們只是感情好漓滔,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乖篷,像睡著了一般响驴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上撕蔼,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天豁鲤,我揣著相機(jī)與錄音,去河邊找鬼鲸沮。 笑死琳骡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的讼溺。 我是一名探鬼主播楣号,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼怒坯!你這毒婦竟也來了炫狱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤剔猿,失蹤者是張志新(化名)和其女友劉穎视译,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艳馒,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡憎亚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年员寇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片第美。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡蝶锋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出什往,到底是詐尸還是另有隱情扳缕,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布别威,位于F島的核電站躯舔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏省古。R本人自食惡果不足惜粥庄,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望豺妓。 院中可真熱鬧惜互,春花似錦、人聲如沸琳拭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽白嘁。三九已至坑鱼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間絮缅,已是汗流浹背鲁沥。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留盟蚣,地道東北人黍析。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像屎开,于是被迫代替她去往敵國和親阐枣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355