擼一個 Vue 自定義指令實現一鍵 Copy的功能

話很少說先看效果,這個效果是用在真實項目中的實際效果哈: javascript

在這裏插入圖片描述

指令是啥?

按照慣例,先請出官方的解釋:html

指令 (Directives) 是帶有 v- 前綴的特殊特性。指令特性的值預期是單個 JavaScript 表達式 (v-for 是例外狀況,稍後咱們再討論)。指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地做用於 DOM。vue

再按照慣例,你們 ( 僞裝 ) 看不懂,而後我來舉個栗子解釋一番。。。好,仍是不知所云,本文結束 ( Ctrl + F4 ) ,下一篇。java

爲了不上述狀況出現,就不解釋了。實際上官方提供了不少內置指令,如:v-ifv-forv-bind and so on。每個指令都有本身特定的功能。node

自定義指令

顧名思義就是本身定義的指令啦,能夠實現咱們想要的功能。下面就實現一個 一鍵 Copy 的功能吧。express

生命週期

首先簡單瞟一下指令的語法,每一個指令都有本身的生命週期,看到生命週期,確定會想到鉤子函數,沒錯,指令也提供了鉤子函數:api

  • bind:指令第一次綁定到元素時調用,此鉤子只會調用一次。在這裏能夠進行一次性的初始化設置。
  • inserted:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。
  • update:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。
  • componentUpdated:指令所在組件的 VNode 及其子 VNode 所有更新後調用。
  • unbind:只調用一次,指令與元素解綁時調用。

下面再簡單瞟一眼上述鉤子函數的參數哈:瀏覽器

  • el:指令所綁定的元素,能夠用來直接操做 DOM
  • binding:一個對象,包含如下屬性:
  • name:指令名,不包括 v- 前綴。
  • value:指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值爲 2
  • oldValue:指令綁定的前一個值,僅在 updatecomponentUpdated 鉤子中可用。不管值是否改變均可用。
  • expression:字符串形式的指令表達式。例如 v-my-directive="1 + 1" 中,表達式爲 "1 + 1"。
  • arg:傳給指令的參數,可選。例如 v-my-directive:foo 中,參數爲 "foo"。
  • modifiers:一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象爲 { foo: true, bar: true }
  • vnodeVue 編譯生成的虛擬節點。移步 VNode API 來了解更多詳情。
  • oldVnode:上一個虛擬節點,僅在 updatecomponentUpdated 鉤子中可用。

看起來還挺多的,不過別方,其實經常使用的就幾個。好了下面要開始表演了:app

等等,仍是再捋一下思路吧:dom

  • 怎麼 copy :實際上瀏覽器提供了原生 api,可是隻能 copy 選中的值(就是鼠標選中的那種)。
  • 那怎麼用代碼實現選中的效果呢?這就要用到輸入控件(input、textarea..)了,該控件提供了選中的 api,選中的就是當前控件的 value 值。
  • 那思路就有了:
    • 動態建立 input 標籤
    • 把要複製的值賦給 input.value
    • 調用 api 選中 input.value
    • 最後調用 api 複製選中的值
  1. 首先建一個 js 文件(v-copy.js)。定義一個對象。( 指令實際就是一個對象 )
    import { Message } from 'ant-design-vue';
    
    const vCopy = { // 名字愛取啥取啥
      /* bind 鉤子函數,第一次綁定時調用,能夠在這裏作初始化設置 el: 做用的 dom 對象 value: 傳給指令的值,也就是咱們要 copy 的值 */
      bind(el, { value }) {
        el.$value = value; // 用一個全局屬性來存傳進來的值,由於這個值在別的鉤子函數裏還會用到
        el.handler = () => {
          if (!el.$value) {
          // 值爲空的時候,給出提示,我這裏的提示是用的 ant-design-vue 的提示,大家隨意
            Message.warning('無複製內容');
            return;
          }
          // 動態建立 textarea 標籤
          const textarea = document.createElement('textarea');
          // 將該 textarea 設爲 readonly 防止 iOS 下自動喚起鍵盤,同時將 textarea 移出可視區域
          textarea.readOnly = 'readonly';
          textarea.style.position = 'absolute';
          textarea.style.left = '-9999px';
          // 將要 copy 的值賦給 textarea 標籤的 value 屬性
          textarea.value = el.$value;
          // 將 textarea 插入到 body 中
          document.body.appendChild(textarea);
          // 選中值並複製
          textarea.select();
          // textarea.setSelectionRange(0, textarea.value.length);
          const result = document.execCommand('Copy');
          if (result) {
            Message.success('複製成功');
          }
          document.body.removeChild(textarea);
        };
        // 綁定點擊事件,就是所謂的一鍵 copy 啦
        el.addEventListener('click', el.handler);
      },
      // 當傳進來的值更新的時候觸發
      componentUpdated(el, { value }) {
        el.$value = value;
      },
      // 指令與元素解綁的時候,移除事件綁定
      unbind(el) {
        el.removeEventListener('click', el.handler);
      },
    };
    
    export default vCopy;
    複製代碼
  2. 到這裏,一鍵 Copy 的功能就實現了,最後再說一嘴怎麼將自定義指令註冊到全局:再新建一個 js ( directives.js )文件來註冊全部的全局指令。
    import copy from './v-copy';
    // 自定義指令
    const directives = {
      copy,
    };
    // 這種寫法能夠批量註冊指令
    export default {
      install(Vue) {
        Object.keys(directives).forEach((key) => {
          Vue.directive(key, directives[key]);
        });
      },
    };
    複製代碼
  3. 最後,在 main.js 中這樣引入:
    import Vue from 'vue';
    import Directives from './directives';
    
    Vue.use(Directives);
    複製代碼
  4. 最後的最後,說一下怎麼用吧。。
    <template>
      <button v-copy="copyText">copy</button>
    </template>
    
    <script> export default { data() { return { copyText: '要 Copy 的內容', }; }, }; </script>
    複製代碼

OK 所有搞完了,撒花。

相關文章
相關標籤/搜索