Vue自定義指令

Vue自定義指令

1、Vue自定義指令

本文主要講述的是Vue自定義指令內容,爲後續實現級聯組件做鋪墊。vue

① 指令簡介

首先以經常使用的v-model指令的使用爲例:node

<input type="text" v-model.lazy="age"/>{{age}}
Vue指令主要用於 須要進行一些DOM操做的時候,經過Vue指令 將DOM操做進行封裝
使用指令的時候分爲 左右兩部分,等號左邊是 指令名(v-model)修飾符(.lazy),等號右邊是 指令表達式(age),指令表達式雖然是一個單純的字符串,可是指令表達式的值倒是 當前組件上的同名屬性對應的值,上面input輸入框中顯示的將是 this.age的值

這裏補充一下v-model指令的三個修飾符的用法:express

  • .lazy修飾符,v-model指令默認監聽的是input事件,即隨用戶的輸入實時更新的,可是使用.lazy修飾符後,監聽的事件則變成了change事件,也就是說觸發條件變成了用戶輸入完成後輸入框失去焦點或者用戶按了Enter鍵以後值纔會發生改變。
  • .number修飾符,當input輸入框的類型爲text的時候,其做用不是限制用戶只能輸入數字,而是將用戶的輸入嘗試轉換爲數字類型以後再綁定到Vue實例上,即,能轉換爲數字就轉換爲數字,不能轉換爲數字的則仍然使用字符串的形式,好比:
<input type="text" v-model.number="age"/>{{age}}
當用戶在輸入框中輸入"18a"後,最右側顯示的age的值 仍然爲18,由於其會將"18a"先轉換爲數字類型,因此值仍然爲 數字18;當用戶輸入"a18"後,最右側顯示的age值就會變爲"a18",由於"a18"沒法轉換爲數字,因此仍然顯示 字符串"a18"
  • .trim修飾符,會將用戶的輸入去除左右兩邊空格後再綁定到Vue實例上

② 自定義指令的建立與使用

指令 實際上是一個對象。若是想在Vue組件中建立自定義的指令,那麼能夠在組件上添加 directives屬性,其 屬性值爲一個對象,而後將自定義指令註冊到directives屬性值上,對象的 屬性名指令名稱,對象的 屬性值自定義指令對象。須要注意的是,指令名稱採用的駝峯命名法, 不包括v-部分,使用的時候 駝峯命名大寫部分轉換爲小寫並用-隔開,如:

// 某個組件ide

export default {
    directives: { // 在當前組件上註冊一個指令
        clickOutside: { // 指令名稱爲clickOutside,使用的時候使用v-click-outside
            // 指令對象
        }
    }
}
<!--使用指令-->
 <div v-click-outside:bar.foo="close"></div>
指令對象內部主要是一些鉤子函數,如: bindinsertedupdatecomponentUpdatedunbind,比較經常使用的是inserted, 在使用了該指令的元素被插入到父元素內時候執行,固然最重要的就是傳遞給鉤子函數處理的參數,由於指令最重要的做用就是 操做DOM,因此其

① 第一個參數就是el,是綁定了指令的DOM元素對象,若是綁定指令的是一個組件,也就是說指令用在了組件上,那麼el就表明這個組件渲染後的整個DOM元素對象。函數

② 第二個參數就是binding,是一個對象,包含了當前指令的一些屬性,好比: binding.name值爲click-outside,不包含v-部分,binding.expression值爲close,binding.value值就是this.close的值,即當前組件上close屬性對應的值,能夠是一個單純的數據,也能夠是一個方法名,這裏close就是一個組件上的close()方法,binding. modifiers值爲{foo:true}就是當前指令的修飾符,是一個對象,若是沒有修飾符則是一個空的對象{},binding.arg值爲bar,是傳遞給指令的參數,即冒號修飾的部分this

注意: 指令的參數必須寫在修飾符的前面,即冒號必須在點號前雙向綁定

③第三個參數爲vnode,即Vue編譯生成的虛擬節點,這個參數很是有用,能夠獲取到很是多Vue實例相關的東西,vnode.context能夠獲取到當前vue組件實例,vnode.componentInstance,若是指令是用在某個組件上,那麼componentInstance獲取的就是使用了該指令的那個Vue組件實例code

export default {
    directives: { // 在當前組件上註冊一個指令
        clickOutside: { // 指令名稱爲clickOutside,使用的時候使用v-click-outside
            inserted(el, binding) {
                document.addEventListener("click", (e) => { // 給整個document添加click事件
                    if (e.target === el || el.contains(e.target)) { // 若是點擊的區域是使用了該指令的DOM元素的內部,那麼不作任何處理
                        return;
                    }
                    binding.value(); // 即調用close()方法
                });
            }
        }
    }
}
該指令實現的是點擊了 綁定指令的元素的外面後,執行指令綁定的方法

2、模擬實現v-model指令

實現一個 v-my-model指令,具備v-model的大部分功能,如下指令代碼並非源碼的實現,僅僅是簡單模擬一下v-model指令的功能,包括v-model的雙向綁定功能、lazy修飾符、number修飾符、trim修飾符。
export default {
    directives: { // 註冊v-my-model到組件上
         myModel: { // 指令名稱採用駝峯命名法
             inserted(el, binding, vnode) { // 在綁定元素插入父元素後執行
               el.value = binding.value; // 獲取指令表達式的值做爲input元素的value值
               const eventName = binding.modifiers.lazy ? "change": "input"; // 處理lazy修飾符,若是有lazy屬性則換成change事件
               el.addEventListener(eventName, (e) => { // input元素監聽input或者change事件
                   let result = e.target.value; // 獲取用戶輸入
                   if (binding.modifiers.number && !Number.isNaN(parseInt(e.target.value))) { // 若是指令帶有number修飾符,而且用戶的輸入可以轉換爲number
                       result = parseInt(e.target.value); // 將用戶的輸入轉換爲對應的數字
                   }
                   if (binding.modifiers.trim) { // 若是指令帶有trim修飾符
                       result = result.trim(); // 去除用戶輸入的首尾空格
                   }
                   vnode.context[binding.expression] = result; // 將最終的結果保存到當前組件實例上即view --> model中
               });
               
               vnode.context.$watch(binding.expression, (newValue, oldValue) => { // 獲取組件實例並監聽其中的綁定的值變化
                   el.value = newValue; // 若是組件實例上數據發生變化,那麼更新view數據
               });
             }
         }   
    }
}
v-my-model指令主要就是監聽 input或者 change事件,同時經過 監聽組件實例中指定數據的變化實現數據的 雙向綁定。大致上實現了v-model指令的功能。
相關文章
相關標籤/搜索