vue自定義指令使用~以仿寫v-show和實現v-copy為例講解

語言: CN / TW / HK

highlight: a11y-dark theme: simplicity-green


vue自定義指令產生的背景

  • 我們知道前端程式設計師,寫的各種程式碼,最終是要作用於頁面上的DOM元素的。比如用HTML固定好DOM的基礎結構,用CSS設定DOM的樣式,用JS去做一些DOM的互動。因為DOM元素相當於“物理層”,要呈現給使用者看的。DOM相當於積木一樣,我們去操作這個積木,最終“搭建”成各式各樣的效果出來。 > 所以一切花裡胡哨的前端框架都是,基於前端三件套HTML、CSS、JS封裝出來的
  • 所以jQuery中就通過$符,直接操作DOM就挺方便的,方便是方便了,但是直接操作DOM會引起頁面的迴流重繪,又會略為有點浪費瀏覽器的效能,容易出現頁面卡頓的情況,造成使用者體驗不太好。 > 萬事皆有利弊,直接操作DOM,有時候,也可能,會是一個簡單方便快捷的選擇。
  • 所以vue和react就閃亮登場了,用資料驅動的思想,並不是直接操作DOM,通過虛擬DOM做一個緩衝,虛擬DOM會蒐集誰需要操作DOM,操作了DOM的哪些東西,統一先記錄好,最終全部一塊操作DOM。有點像js文件碎片的感覺。這樣的話,瀏覽器效能就會優化提升不少。所以,vue中並不提倡直接操作DOM,因為有虛擬DOM在呢,你還直接操作真實DOM幹啥啊。用vue指令啊 > 虛擬DOM確實是個好東西,給大佬點贊。我們知道vue提供的內建指令很方便,能解決大多數的DOM操作問題,但是,並不能解決所有的問題。
  • 所以某些情況下,vue內建指令不能滿足我們的需求,咋辦呢。當然Vue創始人也想到了這個問題,所以,就搞了vue自定義指令,封裝了一套鉤子函式和對應引數的規則、以供我們使用去,從而更方便解決相應問題 > vue自定義指令就是直接操作DOM了,某些場景下,vue自定義指令是一個很好的選擇

vue自定義指令的分類

vue自定義指令有兩種 - 1. 全域性自定義指令(需要全域性註冊) - 2. 元件自定義指令(需要元件內部註冊)

以下案例一是後者,案例二是前者

自定義指令其實就是一個物件,物件身上有一些鉤子函式,自定義指令物件身上的鉤子函式和vue元件的生命週期鉤子函式類似,後續會通過案例闡述

一般使用全域性自定義指令會多一些,畢竟複用方便

vue自定義指令使用講解

案例一 el-input初始獲取焦點(元件自定義指令 )

這個案例其實官網的案例,這裡我們修改一下,更加便於我們理解之。

假設我們需要這樣一個效果:頁面載入完畢以後,el-input輸入框自動獲取焦點,類似開啟百度一下頁面以後,輸入框自動獲取焦點一樣。

```js

```

演示的話,直接複製貼上程式碼即可

案例二 仿寫v-show功能(全域性自定義指令)

效果圖如下

1.gif

看了效果圖,功能其實和v-show沒啥區別,舉這樣一個例子是方便更加好理解vue自定義指令

第一步,新建utils資料夾中存放index.js檔案,此檔案用於書寫全域性自定義指令

js // 引入vue並使用vue的directive方法去註冊一個自定義指令 import Vue from 'vue' Vue.directive('showshow', { // 指令的名字叫做showshow // bind函式一般用來做初始化資料,也可以繫結事件什麼的 bind(el, binding, vnode) { console.log(el, binding.value, vnode); // el引數是當前使用指令的元素,bind引數是指令繫結的資料,vnode是虛擬dom const flag = binding.value // 找到元件中繫結的標識 if (flag == false) { el.style.display = 'none' } else { el.style.display = 'inline-block' } }, // inserted函式是在元素插入dom節點呼叫 inserted(el, binding, vnode) { }, // update和componentUpdated都是更新使用,但是前者更加常用些,oldVnode引數只有在這兩個鉤子中才會有 componentUpdated(el, binding, vnode, oldVnode) { }, update(el, binding, vnode, oldVnode) { const flag = binding.value if (flag == false) { el.style.display = 'none' } else { el.style.display = 'inline-block' } }, // unbind解綁時候使用,比如用來移除第一個bind函式中繫結的事件 unbind(el, binding, vnode) { } });

第二步,在main.js中引入這個書寫全域性自定義指令的檔案(表示使用之)

```js import Vue from 'vue' import App from './App.vue' import router from "@/router/index.js" //引入路由表 import store from './store/index' // 引入vuex // ...

// 引入就可以使用全域性自定義指令啦 ^_^ import './views/utils/index.js'

let vvvue = new Vue({ render: h => h(App), router, store // 掛載上去 }).$mount('#app') ```

第三步,在元件中使用全域性自定義指令

```js

```

有的道友說,蛤?這不是多此一舉嘛?其實不是,因為還沒遇到特定的場景。上述兩個例子主要是學習自定義指令的思想。接下來我們舉一個小例子,點選文字一鍵複製功能。

案例三 實現v-copy自定義指令

效果圖

121212.gif

點選就複製成功了,然後在電腦的相應位置就可以執行 Ctrl V 就可以直接貼上這個點選的文字了

第一步,寫自定義指令程式碼

```js import Vue from 'vue' Vue.directive('copy', { // 指令的名字叫做v-copy // bind函式初始化 bind(el, binding, vnode) { }, // inserted函式是在元素插入dom節點呼叫 inserted(el, binding, vnode) { // el引數是當前使用指令的元素,bind引數是指令繫結的資料,vnode是虛擬dom // 將copyFn函式掛在el身上方便使用 el.copyFn = () => { console.log('點選的是哪個DOM', el); //建立選中範圍 var range = document.createRange();

        // 選擇點選的這個dom
        range.selectNode(el);

        //移除剪下板中內容,不新增這個語句的話,在ie和Edge中複製不到
        window.getSelection().removeAllRanges();

        //將el中的文字內容複製到剪下板
        window.getSelection().addRange(range);

        // 開啟複製貼上功能
        let flag = document.execCommand('copy');

        // 需注意相容性問題
        flag ? alert('複製成功,可以貼上啦') : alert('當前瀏覽器不支援一鍵複製功能,請手動複製貼上')
    }
    el.addEventListener('click', el.copyFn)
},
// update和componentUpdated都是更新使用,但是前者更加常用些
// oldVnode引數只有在這兩個鉤子中才會有,更新以後才會有更新前和更新後的DOM
componentUpdated(el, binding, vnode, oldVnode) {
    console.log('componentUpdated');
},
update(el, binding, vnode, oldVnode) {
    console.log('update');
},
// unbind解綁時候使用,比如用來移除第一個bind函式中繫結的事件
unbind(el, binding, vnode) {
    el.removeEventListener('click', el.copyFn)
}

});

/* * 為了快速上手自定義指令鉤子,我們可以這樣簡單理解。 * * bind和inserted鉤子 --> 類似created和mounted鉤子 * componentUpdated和update鉤子 --> 類似updated鉤子 * unbind鉤子類似 --> destroyed鉤子 * * 具體順序大家可以拷貝程式碼執行以後列印看一下,這樣更加方便精準理解 * / ```

第二步,在.vue檔案中使用

```js

```

補充案例中知識

  • Range物件:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/createRange
  • Selection物件:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/getSelection
  • execCommand方法:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand

關於MDN說,execCommand方法將來可能被刪除的這個問題,思否上有一個回答挺好的,也順帶貼上:https://segmentfault.com/q/1010000022841994?utm_source=tag-newest

總結

在什麼時候需要用自定義指令?

當內建指令不夠用的時候,當需要做一些特殊的效果的時候,當需要對普通DOM元素進行底層操作的時候

自定義指令就是貼近原生js書寫方式,我們合理使用其鉤子函式以及相應引數,可以實現更加靈活的效果功能。畢竟vue雖然提供了很多的內建指令,方便我們直接使用,上手快,但是也是限制了程式設計師的一些發散思維。各有利弊,所以需要權衡 ^_^