【譯】vue 自定義指令的魅力

富途web開發團隊發表於2017-11-06

本文同步發表在富途web開發團隊部落格 futu.im/article/vue…

在你初次接觸一個新的Javascript框架時,會像第一次進糖果店的孩子一樣。給啥拿啥,而更直接點,有些東西可以讓你更容易成為一個開發者。不可避免的是,我們在用框架時都會有一個同感,就是總有些場景是框架不能幫我們完成的。

Vue框架的漂亮之處在於它的功能非常強大,雖然這個框架的指令不夠面面俱到,但也能在開發上助你一臂之力了,因為建立一個自定義指令是很輕鬆的。

什麼是指令?

我在Vue.js guide中寫過指令的一篇文章,現在再一起復習下。

指令是可以寫在DOM元素的小命令,他們以v-為字首,vue就能識別這是一個指令並保持語法的一致性。如果你需要對HTML進行底層操作的話,這種方式是非常有用的。

如果你已經用過vue或者angular的話,對於v-if,v-else,v-show等指令就會比較熟悉了,但是我還是要介紹一些基礎的知識,如果你更想直接看例子,可以直接看後文就好了。

以下是使用指令的幾種方法,以及示例,這些例子並不規範,它們只是示例。這裡的example代替了實際的指令。

v-example - 會例項化一個指令,但這個指令沒有引數。如果不傳引數會比較不靈活,但是這樣就已經操作DOM元素的能力了。

v-example="value" - 這樣可以傳值到指令中,指令會根據value值來操作html。

<div v-if="stateExample">stateExample為true時會顯示</div>
複製程式碼

v-example="'string'" - 使用字串作為表示式。

<p v-html="'<strong>this is an example of a string in some text<strong> '"></p>
複製程式碼

v-example:arg="value" - 這裡可以傳引數(arg),在下面的例子中,我們繫結一個class,然後給這個class設定樣式。

<div v-bind:class="someClassObject"></div>
複製程式碼

v-example:arg.modifier="value" - 使用修飾符(modifier),下面的例子可以在click事件上呼叫preventDefault();

<button v-on:submit.prevent="onSubmit"></button>
複製程式碼

瞭解自定義指令

現在對指令有了大概的瞭解後,我們再來學習下如何建立一個自定義指令。自定義指令的典型例子就是建立一個scroll事件的指令,下面讓我們一起來看一下。

首先建立一個單純的全域性指令(它還沒有做任何事情)。

vue.directive('tack');
複製程式碼

根據這個指令HTML就是這樣的:

<p v-tack>This element has a directive on it</p>
複製程式碼

指令定義函式提供了幾個鉤子函式 (可選):

  1. bind-只呼叫一次,指令第一次繫結到元素時呼叫。
  2. insert-被繫結元素插入父節點時呼叫。
  3. update-所在元件的 VNode 更新時呼叫,但是可能發生在其子元素的 VNode 更新之前。
  4. componentUpdated-所在元件的 VNode 及其子元素的 VNode 全部更新時呼叫。
  5. unbind-只呼叫一次,指令與元素解綁時呼叫。

hookArguments

我認為這五個鉤子函式中bindupdate是最有用的。

他們中的每一個都有可以用的el,bindingvnode引數,除了updatecomponentUpdated之外,還會暴露oldVnode,以區分傳遞的舊值和新值。

  • el 指令所繫結的元素,可以用來直接操作 DOM 。
  • binding 一個物件,包含以下屬性:name,value,oldValue,expression,argmodifiers
  • vnode Vue 編譯生成的虛擬節點。

bindingvnode都是隻讀。

建立一個自定義指令

瞭解了自定義指令概念後,來看下如何使用一個自定義指令,下面用一個例子來實現我們剛才所說的:

Vue.directive('tack',{
    bind(el,binding,vnode){
        el.style.position = 'fixed'
    }
})
複製程式碼

相對應的HTML就是:

<p v-tack>I will now be tacked onto the page</p>
複製程式碼

這樣就可以了,但是還不夠靈活。如果能接受引數以便後續更新它的表現或者進行復用的話就會更加靈活。讓我們看下如何實現讓這個元素離頁面頂部有一定的距離:

Vue.directive('tack',{
    bind(el,binding,vnode){
        el.style.position = 'fixed';
        el.style.top = binding.value + 'px';
    }
})
複製程式碼
<div id="app">
    <p>向下滾動頁面</p>
    <p v-tack="70">我固定在離頂部70px的地方</p>
</div>
複製程式碼

完成後的CodePen展示:(如無法展示效果,點選連結檢視)

假設我們想要區分偏離的70px是在頂部還是左側,可以通過傳遞一個引數來實現:

<p v-tack:left="70">現在我會在距離左側70px的地方</p>
複製程式碼
Vue.directive('tack',{
    bind(el,binding,vnode){
        el.style.position = 'fixed';
        const s = (binding.arg == 'left'?'left':top);
        el.style[s] = binding.value + 'px';
    }
})
複製程式碼

完成後的CodePen展示:(如無法展示效果,點選連結檢視)

你也可以使用多個值,像自帶指令一樣用:

<p v-tack="{top:'40',left:'100'}">我固定在離頂部40px、左側100px的地方</p>
複製程式碼

然後這兩個值將會在指令上同時生效:

Vue.directive('tack',{
    bind(el,binding,vnode){
        el.style.position = 'fixed';
        el.style.top = binding.value.top+'px';
        el.style.left = binding.value.left+'px';
    }
})
複製程式碼

完成後的CodePen展示:(如無法展示效果,點選連結檢視)

我們還可以編寫更復雜的東西,我們可以根據自定義指令來建立和修改方法。這裡,我們簡單建立一個滾動動畫小例子:

Vue.directive('scroll',{
    inserted:function(el,binding){
        let f = function(evt){
            if(binding.value(evt,el)){
                 window.removeEventListener('scroll',f);
            }
        }
        window.addEventListener('scroll',f);
    }
});

//main app

new Vue({
    el:'#app',
    methods:{
        handleScroll:function(evt,el){
            if(window.scrollY>50){
                TweenMax.to(el,1.5,{
                    y:-10,
                    opacity:1,
                    ease:sine.easeOut
                })
            }
            return window.scrollY>100;
        }
    }
});
複製程式碼
<div class="box" v-scroll="handleScroll">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque amet harum aut ab veritatis earum porro praesentium ut corporis. Quasi provident dolorem officia iure fugiat, eius mollitia sequi quisquam.</p>
</div>
複製程式碼

完成後的CodePen展示:(如無法展示效果,點選連結檢視)

以上都是很簡單的程式碼來實現效果,在實際的開發中,你可以建立更高階靈活的自定義指令。

在一個實際構建過程中,我會將指令程式碼放在main.js中,這個檔案位於src目錄下(如果你使用的是vue-cli這樣的工具的話),這樣App.vue及以.vue字尾名的檔案都可以引入使用。你當然也可以使用其他的方式,但這是我認為在實現整個App過程中最靈活的方式。

如果你想了解有關Vue框架的更多知識,請檢視guide.

原文:The Power of Custom Directives in Vue

作者:SARAH DRASNER

譯者:Diandian

相關文章