目錄
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 這兩個生命週期鉤子函數將會被對應執行。 主要用於保留組件狀態或避免重新渲染。
詳細見:
3. 異步組件
vue項目實現按需加載的3種方式:vue異步組件、es提案的import()、webpack的require.ensure()