完全搞懂vue之自定義指令

一. 基本用法

1.鉤子函數:

bind:只調用一次,指令第一次綁定到元素時調用,用這個鉤子函數能夠定義一個綁定時執行一次的初始化動做。inserted:被綁定元素插入父節點時調用(父節點存在便可調用,沒必要存在於document中)。update:被綁定於元素所在的模板更新時調用,而不管綁定值是否變化。經過比較更新先後的綁定值,能夠忽略沒必要要的模板更新。componentUpdated:被綁定元素所在模板完成一次更新週期時調用。unbind:只調用一次,指令與元素解綁時調用。

2.參數

指令鉤子函數會被傳入如下參數:javascript

  • el:指令所綁定的元素,能夠用來直接操做 DOM 。html

  • bindingvue

    :一個對象,包含如下屬性:java

    • name:指令名,不包括 v- 前綴。bingding.namenode

    • value:指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值爲 2vuex

    • oldValue:指令綁定的前一個值,僅在 updatecomponentUpdated 鉤子中可用。不管值是否改變均可用。express

    • expression:字符串形式的指令表達式。例如 v-my-directive="1 + 1"中,表達式爲 "1 + 1"api

    • arg:傳給指令的參數,可選。例如 v-my-directive:foo 中,參數爲 "foo"數組

    • modifiers:一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象爲 { foo: true, bar: true }cookie

  • vnode:Vue 編譯生成的虛擬節點。移步 VNode API 來了解更多詳情。

  • oldVnode:上一個虛擬節點,僅在 updatecomponentUpdated 鉤子中可用。

ex1:

<div v-color="color"></div> 
//值能夠是數字,數組,對象
//若是傳字符串要加單引號,不然會認爲是data中的變量
data(){
    return {
        color:"red"
    }  
},
directives:{
     talk: {
      bind(el, binding) {
        el.style.color = bingding.value;////color爲動態綁定的data中color的值
      }
    }
}

<div v-color:color="'red'"></div>
directives:{
     talk: {
      bind(el, binding) {
        console.log(bing.arg);//綁定的參數名爲color
        el.style.color = bingding.value;//value就是綁定的值,是字符串red
      }
    }
}複製代碼

具體看官方文檔

二. 兩種使用方式

1.全局自定義組件

index.js

import Vue from "vue"
Vue.directive("color",{
    bind(el, binding) {
    	el.style.color=binding.value
    }
})複製代碼

main.js中引入

import "@/directive"複製代碼

2.組件中使用

import auth from '@/directive/auth'
export default {
  directives: { 
  	color:{
            bind(el, binding) {
    		el.style.color=binding.value
  	    }
        }
  }
}
複製代碼

三. 一些應用

1.auth

作權限驗證時,咱們須要根據用戶身份來斷定是否顯示一些元素的顯示,好比後臺管理只有管理員才能修改文章,那麼只有用戶角色是管理員時,修改按鈕纔會顯示,這時候就可使用自定的指令(固然其餘方法也能夠)。

  • 自定義指令傳入一個字符串好比<div v-auth="admin"></div>

  • 從cookie中取出用戶的身份,並和傳入的字符串作比較(固然也可將用戶信息存入vuex從store中取)

  • 若是不相同,將元素的樣式設置爲display:none

export default {
  directives: {
    auth: (el, binding) => {
      if (!getCookie("userName")) {
        el.style.display = "none";//先判斷是否登錄,沒登錄都不顯示
      } else {
        let roleName = getCookie("roleName");//用來區分用戶角色
        if (roleName === binding.value) {
          el.style.display = "block"; //判斷當前用戶角色和傳入的角色是否相等,相等則顯示
        } else {
          el.style.display = "none";
        }
      }
    }
  }
}複製代碼

注:上面這種寫法是一種簡寫,由於bind和update的方法一致。

2. Sticky吸頂

這個效果相信你們都不陌生,使用場景也不勝枚舉,好比掘金文章詳情頁的目錄就是一個經典的吸頂效果。廢話很少說,先來分析下如何吸頂的邏輯

  • 在什麼環境下觸發——頁面滾動

  • 在何時觸發——滾動到元素距離頂部小於一段距離時

這樣一分析就很簡單了,頁面滾動那無非就是監聽下頁面滾動事件,滾動獲取元素距離頂部那就更簡單了,一個API直接丟給你

mdn中getBoundingClientRect速查

export default {
  directives:{
    sticky:{
      bind(el,binding,vnode){
        function handler(e){
          let top=el.getBoundingClientRect().top
          if(top<=10){
            el.children[0].style.position="fixed"
            el.children[0].style.top="10px"
          }else{
            el.children[0].style.position="static"
            el.children[0].style.top="0"
          }
        }
        el._sticky={
          handler
        }
        document.addEventListener("scroll",handler,false)
      },
      unbind(el,binding){
        document.removeEventListener("scroll",el._sticky.handler,false)
        delete el._sticky.handler
      }
    }
}複製代碼

3. clickOutSide

這個效果實際上是借鑑餓了麼ui當中的實現,可是簡化了其實現的思路,由於最近作到一個相似的使用場景因此就用自定義指令秀了一波操做。若是你們還想不到在哪會用到,去知乎點擊top欄的通知(不是給知乎打廣告)就一目瞭然了

很少bibi,實現原理也很簡單,點擊別處得到點擊的dom元素,而後判斷下拉框的元素是否包含該元素,包含該元素說明是在下拉框內點擊的,因此不用隱藏下拉框;若是不包含該元素說明是在下拉框以外,故須要隱藏下拉框。

包含?這怎麼判斷,很簡單一個API——contains搞定,不會的看這裏已幫你服務到位

mdn中contains速查

固然作的時候也遇到幾個小坑?

1.下拉框有個控制隱藏顯示的按鈕,可是這個按鈕確定是在下拉框外,因此如何避免點擊按鈕的時候強制隱藏下拉框(由於有時候點擊按鈕是爲了顯示下拉框)

很簡單,在元素上加一個修飾符@click.stop就能夠了

2.當下拉框隱藏後如何去掉這個點擊事件?

咱們都知道確定使用removeEventListener這個API可是,如何確保和當初addEventListener時公用一個方法,不一致也無法移除啊!原本準備想在methods裏定義一個方法,可是發如今自定義指令中訪問不到this,頭疼的丫匹,後來一想既然bind和unbind裏都有el,那何不在el上新加個屬性,而後在unbind中調用這個屬性,調用完就當即將他刪除,美滋滋迎刃而解!

export default {
  directives: {
    clickOutSide: {
      bind(el, binding, vnode) {
        function handler(e) {
          if (el.contains(e.target)) {
            return;
          } else {
            binding.value();
          }
        }
        el._clickOutSide = {
          handler
        };
        document.addEventListener("click", handler, false);
      },
      unbind(el, binding) {
        document.removeEventListener("click", el._clickOutSide.handler, false);
        delete el._clickOutSide;
      }
    }
  }
}複製代碼

最後

固然自定義指令還有不少應用場景,好比圖片的懶加載,小夥伴們感興趣能夠本身作下噢,思路以下:

  • 先給圖片一個默認的圖片背景

  • 待加載完畢以後替換圖片的src

相關文章
相關標籤/搜索