vue元件封裝指南

阿飛飛飛發表於2019-04-30

目錄

vue元件封裝指南

vue元件三要素

  1. props引數
  2. slot定製插槽
  3. event自定義事件

基本用法

在使用 vue-cli 建立的專案中,元件的建立非常方便,只需要新建一個 .vue 檔案,然後在 template 中寫好 HTML 程式碼,一個簡單的元件就完成了 一個完整的元件,除了 template 以外,還有 script和 style

<template>
  <div class="headComponent">
    子元件{{{myData}}
  </div>
</template>

<script>
export default {
    props:['data','type'],
    inheritAttrs: false,
    data(){
        return{
            myData:'',
        }
    },
    mounted(){

    },
    methods:{
       
    }
}
</script>
<style scoped>

</style>
複製程式碼

然後在其他檔案的 js 裡面引入並註冊,就能直接使用這個元件了

import list from '../components/headComponent.vue'
複製程式碼

一、props:資料父元件傳入子元件

父對子傳參,就需要用到 props,通常的 props 是這樣的:

props:['data','type']
複製程式碼

但是通用元件的的應用場景比較複雜,對 props 傳遞的引數應該新增一些驗證規則,常用格式如下:

 props: {
    // 基礎型別檢測 (`null` 意思是任何型別都可以)
    propA: Number,
    // 多種型別
    propB: [String, Number],
    // 必傳且是字串
    propC: {
      type: String,
      required: true
    },
    // 數字,有預設值
    propD: {
      type: Number,
      default: 100
    },
    // 陣列/物件的預設值應當由一個工廠函式返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函式
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
複製程式碼

對於通過 props 傳入的引數,不建議對其進行操作,因為會同時修改父元件裡面的資料 // vue2.5已經針對 props 做出優化,這個問題已經不存在了 如果一定需要有這樣的操作,可以這麼寫:

let copyData = JSON.parse(JSON.stringify(this.data))
複製程式碼

為什麼不直接寫 let myData = this.data 呢? 因為直接賦值,對於物件和陣列而言只是淺拷貝,指向的是同一個記憶體地址,其中一個改變另一個也會改變。而通過 JSON顛倒轉換之後,實現了深拷貝,則可以互不影響。

二、子元件觸發父元件事件

在通用元件中,通常會需要有各種事件,比如核取方塊的 change 事件,或者元件中某個按鈕的 click 事件,有時子元件需要觸發一個事件,並傳遞給父元件

// 子元件方法:觸發父元件方法,並傳遞引數data到父元件
handleSubmit(data){
    this.$emit('submitToParent', data)
}
複製程式碼
// 父元件呼叫子元件
<child-component @submitToParent="parentSubmit"></child-component>
... ...
// 父元件中被觸發的方法,接受到子元件傳來的引數
parentSubmit(data){
    // 父元件的邏輯處理
}
複製程式碼

父元件中的邏輯要放在父元件處理,子元件基於父元件的資料做的邏輯放在子元件中處理; 這樣既降低了耦合性,也保證了各自的資料不被汙染。

三、記得留一個 slot

一個通用元件,往往不能夠完美的適應所有應用場景 所以在封裝元件的時候,只需要完成元件 80% 的功能,剩下的 20% 讓父元件通過 solt 解決

vue元件封裝指南

上面是一個通用元件,在某些場景中,右側的按鈕是 “處理” 和 “委託”。在另外的場景中,按鈕需要換成 “檢視” 或者 “刪除” 在封裝元件的時候,就不用寫按鈕,只需要在合適的位置留一個 slot,將按鈕的位置留出來,然後在父元件寫入按鈕

子元件
<div class="child-btn">
    <!-- 具名插槽 -->
    <slot name="button"></slot>
    <!-- 匿名插槽(每個元件只能有一個) -->
    <slot><slot>
</div>

父元件
<child>
    <!-- 對應子元件中button的插槽 -->
    <button slot="button">slot按鈕</button>
</child>
複製程式碼

開發通用元件的時候,只要不是獨立性很高的元件,建議都留一個 slot,即使還沒想好用來幹什麼。

再來個例子:

開發過程中,常常需要在子元件內新增新的內容,這時候可以在子元件內部留一個或者多個插口

vue元件封裝指南

然後在呼叫這個子元件的時候加入內容

新增的內容就會分發到對應的 slot 中

vue元件封裝指南

slot 中還可以作為一個作用域,在子元件中定義變數,然後在父元件中自定義渲染的方式 子元件:

vue元件封裝指南
父元件:

vue元件封裝指南

這個示例中,首先在子元件中新增 slot,並在子元件中定義了陣列變數 navs 然後在父元件中以作用域 template 新增內容,其中 scope 是固有屬性,它的值對應一個臨時變數 props 而 props 將接收從父元件傳遞給子元件的引數 navs

關於slot的用法還可檢視:juejin.im/post/5cc856…

四、Vuex:巧用但不要濫用

子元件向子元件傳遞資料

Vue 沒有直接子對子傳參的方法,建議將需要傳遞資料的子元件,都合併為一個元件。如果一定需要子對子傳參,可以先從傳到父元件,再傳到子元件。 父子元件之間是通過 props 和 自定義事件來傳參,非父子元件通常會採用 Vuex 傳參 Vuex設計初衷是用來管理元件狀態,也可以用於複雜元件的引數傳遞

但是 Vuex 的雖然可以用來傳參,但並不推薦;因為 Vuex 類似於一個全域性變數,會一直佔用記憶體 在寫入資料龐大的 state 的時候,就會產生記憶體洩露(人是活的,不能因為事物有弊端就不使用,合理利用即可)。 Tips: 當頁面重新整理的時候,Vuex 會初始化,同時也會丟失編輯過的資料 如果重新整理頁面時需要保留資料,可以通過 url 或者 sessionstorage 儲存 id,然後 ajax 請求資料

五、元件的css:合理運用 scoped 控制樣式作用域

在編寫元件的時候,可以在 style 標籤中新增 scoped,讓標籤中的樣式只對當前元件生效 但是一味的使用 scoped,肯定會產生大量的重複程式碼 所以在開發的時候,應該避免在元件中寫樣式 當全域性樣式寫好之後,再針對每個元件,通過 scoped 屬性新增元件樣式

六、動態元件

Vue 還可以將多個子元件,都掛載在同一個位置,通過變數來切換元件,實現 tab 選單這樣的效果

vue元件封裝指南
這樣的功能可以通過路由 vue-router 實現,但路由更適合較大的元件,而且 url 會有相應的改變 Vue 自身保留的 元素,可以將元件動態繫結到 is 特性上,從而很方便的實現動態元件切換
vue元件封裝指南
上例中,當 tabView 的值改變,component 就會渲染對應的元件,和路由的效果十分類似,但是位址列並沒有發生改變,但這樣一來,每次切換元件都會重新渲染,無法保留元件上的資料。這時可以使用 ** keep-alive ** 將元件保留在記憶體中,避免重新渲染

七、遞迴元件

當元件擁有 name 屬性的時候,就可以在它的模板內遞迴的呼叫自己,這在開發樹形元件的時候十分有效

vue元件封裝指南
上面是一個子元件,定義了 name 為 simple03,然後在模板中呼叫自身,結合 v-for 實現遞迴 為了防止出現死迴圈,在呼叫自身的時候,加入了 v-if 作為判定條件 父元件中呼叫的時候,需要通過 props 傳入一個 tree:

vue元件封裝指南

vue元件封裝指南

最終渲染結果:

vue元件封裝指南

其他情況

子元件改變父元件的資料

在vue2.0之後的版本中,不允許子元件直接改變父元件的資料,在1.0的版本中可以這樣操作的,但是往往專案需求需要改變父元件的資料,那我們如何變通呢? 當我們把父元素的資料給子元件時,要傳一個非基礎型別,即傳遞物件or陣列,子元件通過訪問物件中的屬性運算元據,因為物件和陣列是傳引用,所以在子元件中修改的時候,父元件也會同步改變,如下:

// 父元件要props傳遞給子元件的資料
myData:{
    info:'父元件資訊'
}

// 子元件
 <template id="tpl">
    <div>
        <button @click="change">change</button>
        <p>{{data.info}}</p>
    </div>
</template>
... 省略部分無關程式碼 ...
props:['data'],
methods:{
    change(){
        this.data.info = 'change info'
    }
}
複製程式碼

當子元件點選change按鈕改變資料的時候,父元件也會同步改變

如果不想影響父元件的值,我們也可以用文章開頭講的JSON顛倒轉換的方式,在mounted方法中進行深拷貝,在data中初始化資料時用另一個變數作為承載,這樣才承載變數改變,就不會影響父元件該變數的值了。

參考部落格: www.cnblogs.com/wisewrong/p… www.cnblogs.com/yesyes/p/66…

相關文章