Vue:深入理解組件

目錄

1. 組件註冊

2. Prop

3. 插槽

4. 動態組件 & 異步組件

(一)組件註冊

兩種組件的註冊類型:全局註冊局部註冊

1. 全局註冊

全局註冊的組件可以用在其被註冊之後的任何 (通過 new Vue) 新創建的 Vue 根實例,也包括其組件樹中的所有子組件的模板中。

// 定義一個名爲 button-counter
//當直接在 DOM 中使用一個組件 (而不是在字符串模板或單文件組件) 的時候,強烈推薦遵循 W3C 規範中的自定義組件名 (字母全小寫且必須包含一個連字符)。這會避免和當前以及未來的 HTML 元素相沖突。
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

2. 局部註冊

//模塊系統中局部註冊
import ComponentA from './ComponentA.vue'
export default {
  components: {
    ComponentA
  },
  // ...
}

(二)Prop

1. Prop的大小寫

HTML 中的 attribute 名是大小寫不敏感的,所以瀏覽器會把所有大寫字符解釋爲小寫字符。這意味着當你使用 DOM 中的模板時,camelCase (駝峯命名法) 的 prop 名需要使用其等價的 kebab-case (短橫線分隔命名) 命名:

Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<!--HTML 中是 kebab-case-->
<blog-post post-title="hello!"></blog-post>

重申一次,如果你使用字符串模板,那麼這個限制就不存在了。

2. Prop驗證

不推薦使用數組的方式,對系統後續維護不利。

props:['name', 'type', 'list', 'isVisible']

推薦以下寫法:定製 prop 的驗證方式。

 props: {
    // 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
    propA: Number,
    // 多個可能的類型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 帶有默認值的數字
    propD: {
      type: Number,
      default: 100
    },
    // 帶有默認值的對象
    propE: {
      type: Object,
      // 對象或數組默認值必須從一個工廠函數獲取
      default: function () {
        return { message: 'hello' }
      }
    },
    propF: {
        type:Array,
//對象或數組默認值必須從一個工廠函數獲取
            default: () => []
    },
    propG: {
        type:Function,
        default: () => {}
    } 
    // 自定義驗證函數
    propH: {
      validator: function (value) {
        // 這個值必須匹配下列字符串中的一個
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    },
    propI: {
        type:Boolean,
         default:false
    },
  }

3. 傳遞Prop

<!-- 1. 傳遞靜態Prop -->
<blog-post title="My journey with Vue"></blog-post> 
<!-- (1)傳入一個數字 -->
<blog-post v-bind:likes="42"></blog-post>
<!-- (2)傳入布爾值 -->
<blog-post v-bind:is-published="false"></blog-post>
<!-- (3)傳入數組 -->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<!-- (4)傳入對象 -->
<blog-post
  v-bind:author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
></blog-post>

<!-- 2. 傳遞動態Prop -->  
<!-- (1)動態賦予一個變量的值 -->
<blog-post v-bind:likes="post.likes"></blog-post>
<blog-post v-bind:author="post.author"></blog-post>
<!-- (2)動態賦予一個複雜表達式的值 -->
<blog-post v-bind:title="post.title + ' by ' + post.author.name"></blog-post>
<!-- (3)傳入對象的所有屬性 -->
<blog-post v-bind="post"></blog-post>
<!--
post: {
  id: 1,
  title: 'My Journey with Vue'
}
等效於下面代碼:
-->
<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

(三)插槽

1. 基本使用

<!-- 在 <navigation-link> 的模板中寫爲 -->
<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>

<!-- 在使用<navigation-link>模板時: -->
<navigation-link url="/profile">Your Profile</navigation-link>

<navigation-link url="/profile">
  <span class="fa fa-user"></span>
  Your Profile
</navigation-link
    
<navigation-link url="/profile">
  <font-awesome-icon name="user"></font-awesome-icon>
  Your Profile
</navigation-link>

如果 <navigation-link> 沒有包含一個 <slot> 元素,則該組件起始標籤和結束標籤之間的任何內容都會被拋棄。

2. 後備內容

爲一個插槽設置具體的後備 (也就是默認的) 內容,它只會在沒有提供內容的時候被渲染。而如果我們提供內容,則這個提供的內容將會被渲染從而取代後備內容。

<!-- 在 <submit-button> 的模板中寫爲 -->
<button type="submit">
  <slot>Submit</slot>
</button>

<!-- 在使用<submit-button>模板時: -->
<submit-button></submit-button>
<!-- 將被渲染爲: -->
<button type="submit">
  Submit
</button>

3. 具名插槽

使用場景:需要多個插槽。

對於這樣的情況,<slot> 元素有一個特殊的 attribute:name。這個 attribute 可以用來定義額外的插槽。一個不帶 name<slot> 出口會帶有隱含的名字“default”。

在向具名插槽提供內容的時候,我們可以在一個 <template> 元素上使用 v-slot 指令,並以 v-slot 的參數的形式提供其名稱。

<!-- 在 <base-layout> 的模板中寫爲 -->
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

<!-- 在使用<base-layout>模板時: -->
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>
<!-- 上面兩行代碼等效爲:  
  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>
 -->   
  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

具名插槽縮寫

<base-layout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

3. 作用域插槽

編譯作用域

父級模板裏的所有內容都是在父級作用域中編譯的;子模板裏的所有內容都是在子作用域中編譯的。

我們在父級模板裏使用帶有插槽的子組件。當想在一個插槽中使用數據時,該插槽跟父級模板的其它地方一樣可以訪問父級的實例屬性 (也就是相同的“作用域”),而不能訪問子組件的作用域。

而當我們想讓插槽內容能夠訪問子組件中才有的數據時,可以使用作用域插槽。 <slot> 元素上的 attribute 被稱爲插槽 prop

<!-- 在<current-user>的模板中寫爲: -->
<!-- 爲了讓 user 在父級的插槽內容中可用,我們可以將 user 作爲 <slot> 元素的一個 attribute 綁定上去 -->
<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

<!-- 在使用<current-user>模板時: -->
<!-- 可以使用帶值的 v-slot 來定義我們提供的插槽 prop 的名字 -->
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

(四)動態組件 & 異步組件

1. 動態組件

通過 Vue 的 <component> 元素加一個特殊的 is attribute 來實現:

<!-- 組件會在 `currentTabComponent` 改變時改變 -->
<component v-bind:is="currentTabComponent"></component>

在上述示例中,currentTabComponent 可以包括

  • 已註冊組件的名字,或
  • 一個組件的選項對象

例子

<template>
  <p id="app">
   <component :is="currentView"></component>
   <button @click="changeView('A')">切換到A</button>
   <button @click="changeView('B')">切換到B</button>
   <button @click="changeView('C')">切換到C</button>
  </p>
</template>

<script>
var app = new Vue({
 el: '#app',
 data: {
  currentView: 'comA'
 },
 methods: {
  changeView: function(data){
   this.currentView = 'com'+ data  //動態地改變currentView的值就可以動態掛載組件了。
  }
 },
 components: {
  comA: {
   template: '<p>組件A</p>'
  },
  comB: {
   template: '<p>組件B</p>'
  },
  comC: {
   template: '<p>組件C</p>'
  }
 }
});
</script>

2. 在動態組件上使用 keep-alive

<keep-alive>包裹動態組件時,會緩存不活動的組件實例,而不是銷燬它們。和 <transition>相似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現在父組件鏈中。

當組件在<keep-alive> 內被切換,它的 activated 和 deactivated 這兩個生命週期鉤子函數將會被對應執行。 主要用於保留組件狀態或避免重新渲染。

詳細見

利用Vue中keep-alive,快速實現頁面緩存

Vue keep-alive詳解

3. 異步組件

vue項目實現按需加載的3種方式:vue異步組件、es提案的import()、webpack的require.ensure()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章