Vue 學習筆記 - 深入瞭解組件

組件註冊

組件名

Vue.component('my-component-name', { /* ... */ })

該組件名就是 Vue.component 的第一個參數。
當直接在 DOM 中使用一個組件 (而不是在字符串模板單文件組件) 的時候,官方強烈推薦遵循W3C 規範中的自定義組件名 (字母全小寫且必須包含一個連字符)。這會幫助你避免和當前以及未來的 HTML 元素相沖突。
你可以在風格指南中查閱到關於組件名的其它建議。

組件名大小寫

命名方式 定義 使用
kebab-case 短橫線分隔 Vue.component(’my-component-name’, { /* … */ }) <my-component-name>
PascalCase首字母大寫 Vue.component(’MyComponentName’, { /* … */ }) <my-component-name> 和 <MyComponentName>

注意直接在 DOM (即非字符串的模板) 中使用時只有 kebab-case 是有效的

全局註冊

註冊之後新創建的任何根實例都可以用。

Vue.component('my-component-name', {
  // ... 選項 ...
})

局部註冊

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})
  1. 實例初始化時創建,只在實例內有效。
  2. components 中每個propertykey是組件名value是組件對象
  3. 局部註冊的組件在其子組件中不可用。如果想 ComponentAComponentB 中可用,則需要這樣寫:
var ComponentA = { /* ... */ }

var ComponentB = {
  components: {
    'ComponentA': ComponentA // 可以直接簡寫爲:ComponentA。組件名字和值都是 ComponentA
  },
  // ...
}

模塊系統

在模塊系統中局部註冊

  • src\components下爲每個組件創建一個目錄(同組件名)
  • 然後你需要在局部註冊之前導入每個你想使用的組件。例如,在一個假設的ComponentB.jsComponentB.vue 文件中:
import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
  components: {
    ComponentA,
    ComponentC
  },
  // ...
}

現在 ComponentAComponentC 都可以在 ComponentB 的模板中使用了。

基礎組件的自動化全局註冊

如果有很多基本的通用組件,如上的一個個註冊,太複雜。
如果你恰好使用了webpackVue CLI 3+(在內部使用了 webpack),那麼就可以使用 require.context 對想要的組件進行全局註冊。

  • 全局註冊要在new Vue 實例之前纔有意義。
  • 基本流程就是:
    1. 通過require.context獲取指定文件夾下所有文件,可以正則過濾文件名,可以控制是否查詢其子目錄
    2. 遍歷文件列表。拼出組件名字,逐個調用Vue.component進行註冊。
    3. 例子代碼如下:
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
  // 其組件目錄的相對路徑
  './components',
  // 是否查詢其子目錄
  false,
  // 匹配基礎組件文件名的正則表達式
  /Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
  // 獲取組件配置
  const componentConfig = requireComponent(fileName)

  // 獲取組件的 PascalCase 命名
  const componentName = upperFirst( //首字大寫
    camelCase( // 轉爲駝峯
      fileName
        .split('/') //把文件路徑拆分後最後一個就是文件名
        .pop() // 彈出最後一個
        .replace(/\.\w+$/, '') // 將後綴名去掉
    )
  )

  // 全局註冊組件
  Vue.component(
    componentName,
    // 如果這個組件選項是通過 `export default` 導出的,
    // 那麼就會優先使用 `.default`,
    // 否則回退到使用模塊的根。
    componentConfig.default || componentConfig
  )
})

Prop

Prop 的大小寫 (camelCase vs kebab-case)

prop中用駝峯,標籤屬性還是得寫成分隔線

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

重申一次,如果你使用字符串模板,那麼這個限制就不存在了。(這名我還沒理解)

Prop 類型

數組形式默認值爲字符串

props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

想定義類型用對象:

props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // or any other constructor
}

你會在這個頁面接下來的部分看到類型檢查和其它 prop 驗證

傳遞靜態或動態 Prop

前面已經學過:

傳值方式 寫法 備註
靜態字符串 <book title="三國演義"></book > 直接使用 title屬性,默認字符串
變量 <book v-bind:title="book.title"></book > 使用了v-bind:指令
此時值就跟着變量走了
表達式 <book v-bind:title="'《' + book.title + '》'"></book > 同上
對象 <book v-bind:mybook="bookOjb"></book > 同上
數字 <book v-bind:page="500"></book > 這裏 500沒有引號,是數字
布爾值 <book v-bind:hardback></book > 不賦值,存在就默認爲true
賦值時當變量看就好了
數組 <book v-bind:characters="['大哥','二第','三弟]"></book > 支持字面量,也支持變量
對象 <book v-bind:character="{name:'劉備'}"></book > 支持字面量,也支持變量

單向數據流

  1. 所有的 prop 只從父組件 =》子組件。父組件中的值更新,子也更新。
  2. 子組件不應該修改prop(邏輯上它表明你想這樣 子組件=》父組件但這是禁止的,你會收到錯誤提示)
  3. 數組對象是引用傳遞的,對它們內容的修父子之間是同步的。
  4. 子組件想父級數據,就觸發事件,讓父級監聽來處理吧。詳見:sync修飾符

兩個想編輯prop 的特殊場景:

  1. 初始值,這個應該在子組件中用一個變量來接收,再使用,不應該直接編輯prop
  2. 父傳進來的值需要格式化顯示,此時推薦使用計算屬性computed

Prop 驗證

自己編寫的組件給別人用時,需要明確prop的一些驗證規則,可以用對象形式定義:

Vue.component('my-component', {
  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: {
      validator: function (value) {
        // 這個值必須匹配下列字符串中的一個
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

注意順序:驗證實例化。 (如 data、computed 等 property ) 在 default 或 validator 函數中是不可用的。

類型檢查

type 可以是下列原生構造函數中的一個:
String、 Number、 Boolean、 Array、 Object、 Date、 Function、 Symbol
另外還支持自定義的構造函數,如下驗證author是否通過new Person創建的

function Person (firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}
Vue.component('blog-post', {
  props: {
    author: Person
  }
})

非 Prop 的 Attribute

  • 組件可以接受任意的attribute
  • 如果組件顯示的定義對應的prop,那就它就有着落了。
  • 如果如果組件沒有顯示的定義對應prop,那麼此attribute就會被添加到組件的根元素上。

替換/合併已有的 Attribute

絕大多數 attribute 會用外部提供給組件的值替換掉組件內部設置好的值。
所以如果傳入 type="text" 就會替換掉 type="date" 並把它破壞!
幸好classstyle稍微智能一些,會把兩部分值合併起來。

禁用 Attribute 繼承

設置 inheritAttrs: false 可以在組件中禁用 Attribute 繼承(不會影響 styleclass

Vue.component('my-component', {
  inheritAttrs: false,
  // ...
})

inheritAttrs: false 和 $attrs 配合的例子沒看懂

自定義事件

事件名

觸發:this.$emit('my-event')
監聽:v-on:my-event="clickHandler"
事件名會被自動轉換爲全小寫 (因爲 HTML 是大小寫不敏感的),所以 v-on:myEvent 將會變成 v-on:myevent
因此,官方推薦始終使用 kebab-case 的事件名,如:my-event

自定義組件的 v-model

一個組件上的 v-model 默認會利用名爲 value 的 prop 和名爲 input 的事件,但是像單選框、複選框等類型的輸入控件可能會將 value attribute 用於不同的目的。model 選項可以用來避免這樣的衝突:
2.2.0+ 新增的model

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
<base-checkbox v-model="lovingVue"></base-checkbox>

我們定義了一個叫checkedprop用來接收v-modellovingVue值。當 <base-checkbox>觸發 change事件並附帶一個新的值的時候,這個 lovingVue將會更新。

將原生事件綁定到組件

直接在自定義組件上監聽事件要在事件後.native,此事子組件中的input元素的focus事件能觸發

<div id="app">
	<base-input v-on:focus.native="onFocus"></base-input>
</div>

<script>
	Vue.component('base-input', {
		data: function(){
			return {label : '標籤:',value: '值123'}
		},
		template: `<input />`
	})
	new Vue({
		el: "#app",
		methods:{
			onFocus: function($event){console.info("獲得焦點");}
		}
	});
</script>

但如果子組件中根元素不是input元素。那麼.native也沒用了。
爲了解決這個問題,Vue 提供了一個 $listeners property,它是一個對象,包含了作用在這個組件上的所有監聽器。

<div id="app">
	<base-input v-on:focus="onFocus" v-model="myValue"></base-input> {{myValue}}
</div>

<script>
	Vue.component('base-input', {
	  inheritAttrs: false,
	  props: ['label', 'value'],
	  computed: {
	    inputListeners: function () {
	      var vm = this
	      // `Object.assign` 將所有的對象合併爲一個新對象
	      return Object.assign({},
	        // 我們從父級添加所有的監聽器
	        this.$listeners,
	        // 然後我們添加自定義監聽器,
			// 或者覆寫一些監聽器的行爲
	        {
	          // 這裏確保組件配合 `v-model` 的工作
	          input: function (event) {
	            vm.$emit('input', event.target.value)
	          }
	        }
	      )
	    }
	  },
	  template: `
	    <label>
	      {{ label }}
	      <input
	        v-bind="$attrs"
	        v-bind:value="value"
	        v-on="inputListeners"
	      >
	    </label>
	  `
	})
	
	new Vue({
		el: "#app",
		data: {myValue : "123"},
		methods:{
			onFocus: function($event){console.info("獲得焦點");}
		}
	});
</script>

現在 <base-input> 組件完全透明了,組件內部所有事件都傳出來了。
並且重寫了input事件,配合v-model="myValue"使用。

.sync 修飾符 (2.3.0+ 新增)

子組件想父級數據,就觸發事件,讓父級監聽來處理。 .sync 修飾符就是這種操作的縮寫形式。
注意:

  1. 帶有 .sync 修飾符的v-bind 不能和表達式一起使用 (例如 v-bind:title.sync="doc.title + '!'" 是無效的)。取而代之的是,你只能提供你想要綁定的 property 名,類似 v-model
  2. 用一個對象同時設置多個propv-bind.sync="doc"會把 doc 對象中的每個property (如 title) 都作爲一個獨立的prop傳進去,然後各自添加用於更新的v-on監聽器。
  3. v-bind.sync 用在一個字面量的對象上,例如 v-bind.sync="{ title: doc.title }"無法正常工作。

插槽

插槽內容

2.6.0中,我們爲具名插槽和作用域插槽引入了一個新的統一的語法 (即 v-slot 指令)。它取代了 slotslot-scope 這兩個目前已被廢棄但未被移除且仍在文檔中的 attribute。新語法的由來可查閱這份 RFC

它允許你像這樣合成組件:

<navigation-link url="/profile">
  Your Profile
</navigation-link>

然後你在 的模板中可能會寫爲:

<a> <slot></slot> </a>
  • 當組件渲染的時候<slot></slot>將會被替換爲“Your Profile”
  • 插槽內可以包含任何模板代碼,包括 HTML,甚至其它的組件
  • 如果沒有包含一個<slot>元素,則該組件兩個標籤之間的內容會被拋棄。

編譯作用域

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

<navigation-link url="/profile">
  {{ url }}  // 這裏其實是讀取不取 navigation-link 屬性 url的。因爲這句會先編譯好,再傳進去替換插槽。
</navigation-link>

後備內容

<slot>就是默認內容</slot> 如果沒有傳值進來就會使用它。

具名插槽

2.6.0起有所更新。已廢棄的使用 slot attribute 的語法在這裏

  1. <template> 上【v-slot】指令對應 <slot> 的【name】。
  2. 可以用一個不帶 name<slot>,來入所有沒定的部分。(默認隱含名字"default"也可以寫出來)
<div id="app">
	<my-component >
		<p>其它內容11111111111</p>
		<template v-slot:header>
			<h1>這裏對應頭部</h1>
		</template>
		<p>其它內容222222222222</p>	
		<p>正文內容正文內容正文內容正文內容正文內容正文內容</p>
		<p>其它內容333333333333</p>
		<template v-slot:footer>
			<p>這裏對應足部</p>
		</template>
		<p>其它內容444444444444</p>
	</my-component>
</div>

<script>
	Vue.component('my-component', {
		data: function(){
			return {label : '標籤:',value: '值123'}
		},
		template: `<div>
					<slot name="header"></slot>
					<slot ></slot>
					<slot name="footer"></slot> 
				 </div>`
	})
	new Vue({
		el: "#app",
		methods:{
			onFocus: function($event){console.info("獲得焦點");}
		}
	});
</script>
  • 效果:
    在這裏插入圖片描述
  1. 2.6.0中引入新語法 <template> 使用v-slot 指令
  2. 注意 v-slot 只能添加在 <template> 上 (只有一種例外情況)

注意 v-slot 只能添加在 <template> 上 (只有一種例外情況),這一點和已經廢棄的 slot attribute 不同。

作用域插槽

自 2.6.0 起有所更新。已廢棄的使用 slot-scope attribute 的語法在這裏
<current-user>組件:

<span>
  <slot>{{ user.lastName }}</slot>
</span>

如果想這樣換掉備用內容。是無效的

<current-user>
  {{ user.firstName }}
</current-user>

想要實現這個目標,模板使用時都要調整一下

  • 模板調整:
    爲了讓 user 在父級的插槽內容中可用,我們可以將user 作爲<slot>元素的一個 attribute 綁定上去,<current-user>組件如下調整:<slot v-bind:user="user">{{ user.lastName }}</slot>
  • 使用時調整
    綁定在<slot>元素上的 attribute 被稱爲插槽 prop
    現在在父級作用域中,我們可以使用帶值的 v-slot 來定義我們提供的插槽 prop 的名字:(爲包含所有default插槽prop的對象取名slotProps 這個名字可以自己喜歡怎麼取都行)
<div id="app">
	<current-user>
	  <template v-slot:default="slotProps">
		{{ slotProps.user.lastName }}{{ slotProps.user.firstName }}
	  </template>
	</current-user>
</div>

<script>
	Vue.component('current-user', {
		data: function(){
			return {user : {firstName:"jin", lastName:"jerry" }}
		},
		template: `<div><slot v-bind:user="user">{{ user.lastName }}</slot></div>`
	})
	new Vue({
		el: "#app"
	});
</script>

獨佔默認插槽的縮寫語法

當被提供的內容只有默認插槽時v-slot可以直接用在組件上。

<current-user v-slot:default="slotProps">
	{{ slotProps.user.lastName }}{{ slotProps.user.firstName }}
</current-user>

還可以再簡化,省掉:default

<current-user v-slot="slotProps">
	{{ slotProps.user.lastName }}{{ slotProps.user.firstName }}
</current-user>

注意默認插槽的縮寫語法不能具名插槽混用,因爲它會導致作用域不明確:

<!-- 無效,會導致警告 -->
<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
  <template v-slot:other="otherSlotProps">
    slotProps is NOT available here
  </template>
</current-user>

只要出現多個插槽,請始終爲所有的插槽使用完整的基於 <template>的語法:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>

解構插槽 Prop

作用域插槽的內部工作原理是將你的插槽內容包括在一個傳入單個參數的函數裏:

function (slotProps) {
  // 插槽內容
}

這意味着 v-slot 的值實際上可以是任何能夠作爲函數定義中的參數的 JavaScript 表達式。所以在支持的環境下 (單文件組件現代瀏覽器),你也可以使用 ES2015 解構來傳入具體的插槽 prop,如下:

<current-user v-slot="{ user }">
  {{ user.firstName }}
</current-user>

這樣可以使模板更簡潔,尤其是在該插槽提供了多個 prop 的時候。它同樣開啓了 prop 重命名等其它可能,例如將 user 重命名爲person

<current-user v-slot="{ user: person }">
  {{ person.firstName }}
</current-user>

你甚至可以定義後備內容,用於插槽 prop 是 undefined 的情形:

<current-user v-slot="{ user = { firstName: 'Guest' } }">
  {{ user.firstName }}
</current-user>

動態插槽名 2.6.0 新增

動態指令參數也可以用在 v-slot上,來定義動態的插槽名:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

具名插槽的縮寫 2.6.0 新增

  • v-slot:替換爲字符# 例如: v-slot:header 可以被重寫爲 #header
  • 縮寫只在其有參數的時候纔可用。如下省了 default 這樣會觸發一個警告。
<current-user #="{ user }">
  {{ user.firstName }}
</current-user>
  • 把默認插槽名寫上#default="{ user }"就可以了
<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

其它示例

插槽 prop 允許我們將插槽轉換爲可複用的模板,這些模板可以基於輸入的 prop 渲染出不同的內容。這在設計封裝數據邏輯同時允許父級組件自定義部分佈局的可複用組件時是最有用的。
例如,我們要實現一個 <todo-list>組件,它是一個列表且包含佈局和過濾邏輯:

<ul>
  <li v-for="todo in filteredTodos" v-bind:key="todo.id">
      {{ todo.text }}
  </li>
</ul>

我們可以將每個 todo 作爲父級組件的插槽,以此通過父級組件對其進行控制,然後將 todo 作爲一個插槽 prop 進行綁定:

<ul>
  <li v-for="todo in filteredTodos" v-bind:key="todo.id" >
    <!-- 我們爲每個 todo 準備了一個插槽, 將 `todo` 對象作爲一個插槽的 prop 傳入。 -->
    <slot name="todo" v-bind:todo="todo">
        {{ todo.text }} <!-- 後備內容 -->
    </slot>
  </li>
</ul>

現在當我們使用 <todo-list> 組件的時候,我們可以選擇爲 todo 定義一個不一樣的 <template> 作爲替代方案,並且可以從子組件獲取數據:

<todo-list v-bind:todos="todos">
  <template v-slot:todo="{ todo }">
    <span v-if="todo.isComplete"></span>
    {{ todo.text }}
  </template>
</todo-list>

這只是作用域插槽用武之地的冰山一角。想了解更多現實生活中的作用域插槽的用法,我們推薦瀏覽諸如 Vue Virtual ScrollerVue PromisedPortal Vue 等庫。

廢棄了的語法

v-slot 指令自 Vue 2.6.0 起被引入,提供更好的支持 slotslot-scope attribute 的 API 替代方案。v-slot 完整的由來參見這份 RFC。在接下來所有的 2.x 版本中 slotslot-scope attribute 仍會被支持,但已經被官方廢棄且不會出現在 Vue 3 中。

帶有 slot attribute 的具名插槽

2.6.0 起被廢棄。新推薦的語法請查閱這裏

<base-layout>
  <template slot="header">
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>

  <template slot="footer">
    <p>Here's some contact info</p>
  </template>
</base-layout>

或者直接把 slot attribute 用在一個普通元素上:

<base-layout>
  <h1 slot="header">Here might be a page title</h1>

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

  <p slot="footer">Here's some contact info</p>
</base-layout>

這裏其實還有一個未命名插槽,也就是默認插槽,捕獲所有未被匹配的內容。

帶有 slot-scope attribute 的作用域插槽

2.6.0 起被廢棄。新推薦的語法請查閱這裏
<template> 上使用特殊的 slot-scope attribute,可以接收傳遞給插槽的 prop (把這裏提到過的 <slot-example> 組件作爲示例):

<slot-example>
  <template slot="default" slot-scope="slotProps">
    {{ slotProps.msg }}
  </template>
</slot-example>

這裏的 slot-scope 聲明瞭被接收的 prop 對象會作爲 slotProps 變量存在於 <template> 作用域中。你可以像命名 JavaScript 函數參數一樣隨意命名 slotProps

  • 這裏的 slot="default"可以省略。
<slot-example>
  <template slot-scope="slotProps">
    {{ slotProps.msg }}
  </template>
</slot-example>

slot-scope attribute 也可以直接用於非 <template>元素 (包括組件):

<slot-example>
  <span slot-scope="slotProps">
    {{ slotProps.msg }}
  </span>
</slot-example>

slot-scope 的值可以接收任何有效的可以出現在函數定義的參數位置上的 JavaScript 表達式。這意味着在支持的環境下 (單文件組件現代瀏覽器),你也可以在表達式中使用 ES2015 解構,如下:

<slot-example>
  <span slot-scope="{ msg }">
    {{ msg }}
  </span>
</slot-example>

使用這裏描述過的 <todo-list> 作爲示例,與它等價的使用 slot-scope 的代碼是:

<todo-list v-bind:todos="todos">
  <template slot="todo" slot-scope="{ todo }">
    <span v-if="todo.isComplete"></span>
    {{ todo.text }}
  </template>
</todo-list>

動態組件 & 異步組件

在動態組件上使用 keep-alive

之前學過用 <component v-bind:is="currentTabComponent"></component> 實現標籤頁,但切換標籤時,組件都會重新渲染。
如果不想這樣可以用:keep-alive。 它包裹動態組件時,會緩存不活動的組件實例,而不是銷燬它們。。查看API文檔瞭解更多詳情

<!-- 失活的組件將會被緩存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

注意這個<keep-alive> 要求被切換到的組件都有自己的名字,不論是通過組件的name 選項還是局部/全局註冊。
你可以在這裏查看完整示例代碼

異步組件

爲了簡化分包懶加載。Vue 允許你以一個工廠函數的方式定義你的組件,這個工廠函數會異步解析你的組件定義。Vue 只有在這個組件需要被渲染的時候纔會觸發該工廠函數,且會把結果緩存起來供未來重渲染。例如:

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 向 `resolve` 回調傳遞組件定義
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

如你所見,這個工廠函數會收到一個 resolve 回調,這個回調函數會在你從服務器得到組件定義的時候被調用。你也可以調用 reject(reason) 來表示加載失敗。這裏的 setTimeout 是爲了演示用的,如何獲取組件取決於你自己。一個推薦的做法是將異步組件和 webpack 的 code-splitting 功能一起配合使用:

Vue.component('async-webpack-example', function (resolve) {
  // 這個特殊的 `require` 語法將會告訴 webpack
  // 自動將你的構建代碼切割成多個包,這些包
  // 會通過 Ajax 請求加載
  require(['./my-async-component'], resolve)
})

你也可以在工廠函數中返回一個Promise,所以把 webpack 2 和 ES2015 語法加在一起,我們可以這樣使用動態導入:

Vue.component(
  'async-webpack-example',
  // 這個動態導入會返回一個 `Promise` 對象。
  () => import('./my-async-component')
)

當使用局部註冊的時候,你也可以直接提供一個返回 Promise 的函數:

處理加載狀態 2.3.0+ 新增

這裏的異步組件工廠函數也可以返回一個如下格式的對象:

const AsyncComponent = () => ({
  // 需要加載的組件 (應該是一個 `Promise` 對象)
  component: import('./MyComponent.vue'),
  // 異步組件加載時使用的組件
  loading: LoadingComponent,
  // 加載失敗時使用的組件
  error: ErrorComponent,
  // 展示加載時組件的延時時間。默認值是 200 (毫秒)
  delay: 200,
  // 如果提供了超時時間且組件加載也超時了,
  // 則使用加載失敗時使用的組件。默認值是:`Infinity`
  timeout: 3000
})

注意如果你希望在Vue Router 的路由組件中使用上述語法的話,你必須使用 Vue Router 2.4.0+ 版本。

處理邊界情況

這裏記錄的都是和處理邊界情況有關的功能,即一些需要對 Vue 的規則做一些小調整的特殊情況。不過注意這些功能都是有劣勢或危險的場景的。我們會在每個案例中註明,所以當你使用每個功能的時候請稍加留意。

直接看官方教程

參考資料

Vue 官方教程基數篇 - 本筆記的學習對象
Vue 官方CLI 官方文檔
Vue 官方API 參考
Vue 官方API文檔 - 生命週期鉤子

vue-devtools 編譯安裝
我的 Vue CLI 學習筆記
Vue 學習筆記 - 基礎(上)
Vue 學習筆記 - 基礎(中)
Vue 學習筆記 - 基礎(下)組件基礎
Vue 學習筆記 - 深入瞭解組件

MDN 完整有效按鍵名 Key Values
千鋒教育-李衛民 Vue 漸進式 JavaScript 框架

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