[TOC]
# 指令
## 內置指令
| 指令 | 描述 |
| --- | --- |
| v-text |主要用來更新 textContent,可以等同于 JS 的 text 屬性。|
| v-html |雙大括號的方式會將數據解釋為純文本,而非 HTML。為了輸出真正的HTML,可以用 v-html 指令。它等同于 JS 的 innerHtml 屬性。|
| v-pre |想顯示 {{ }} 標簽而不進行替換時使用,跳過該元素和它的子元素的編譯過程|
| v-cloak | 這個指令保持在元素上直到關聯實例結束編譯。和 CSS 規則如 [v-cloak] { display: none } 一起用時,這個指令可以隱藏未編譯的 Mustache 標簽直到實例準備完畢。|
| v-once |v-once 關聯的實例,只會渲染一次。之后的重新渲染,實例及其所有的子節點將被視為靜態內容跳過,這可以用于優化更新性能。|
| v-if| 實現條件渲染,Vue 會根據表達式的值的真假條件來渲染元素。|
| v-else| v-else 是搭配 v-if 使用的,它必須緊跟在 v-if 或者 v-else-if 后面,否則不起作用。|
| v-else-if| v-else-if 充當 v-if 的 else-if 塊,可以鏈式的使用多次。可以更加方便的實現 switch 語句。|
| v-show |也是用于根據條件展示元素。和 v-if 不同的是,如果 v-if 的值是 false,則這個元素被銷毀,不在 dom 中。但是 v-show 的元素會始終被渲染并保存在 dom 中|
| v-for |遍歷數組 / 對象來進行渲染|
| v-bind| 用來動態的綁定一個或者多個特性。沒有參數時,可以綁定到一個包含鍵值對的對象。常用于動態綁定 class 和 style。簡寫為:【 :】|
| v-model |用于在表單上創建雙向數據綁定。 v-model 會忽略所有表單元素的 value、checked、selected 特性的初始值。因為它選擇 Vue 實例數據做為具體的值。|
| v-on| 主要用來監聽 dom 事件(或父子組件通信),以便執行一些代碼塊。表達式可以是一個方法名。簡寫為:【 @ 】|
## Class 與 Style 的綁定
⑴ 傳遞一個對象,實現動態切換 class
```html
<div v-bind:class="{ 'active': isActive }"></div>
```
⑵ 與普通的 class 屬性共存
```html
<div
class="static"
v-bind:class="{ 'active': isActive, 'text-danger': hasError }"
></div>
```
⑶ 用在組件上時,這些類將被添加到該組件的根元素上面。這個元素上已經存在的類不會被覆蓋。
例如,如果你聲明了這個組件:
```js
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})
```
然后在使用它的時候添加一些 class:
```js
<my-component class="baz boo"></my-component>
```
HTML 將被渲染為:
```html
<p class="foo bar baz boo">Hi</p>
```
⑷ 綁定內聯樣式
```html
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
```
或者綁定到一個樣式對象:
```html
<div v-bind:style="styleObject"></div>
```
```js
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
```
## 條件渲染 v-if 與 v-show
`v-if`是“真正”的條件渲染,因為它會確保在切換過程中條件塊內的事件監聽器和子組件適當地被銷毀和重建。
`v-if`也是**惰性的**:如果在初始渲染時條件為假,則什么也不做——直到條件第一次變為真時,才會開始渲染條件塊。
相比之下,`v-show`就簡單得多——不管初始條件是什么,元素總是會被渲染,并且只是簡單地基于 CSS 進行切換。
一般來說,`v-if`有更高的切換開銷,而`v-show`有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用`v-show`較好;如果在運行時條件很少改變,則使用`v-if`較好。
## 列表渲染
⑴ 只使用 1 個參數
```html
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
```
```js
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
})
```
⑵ 使用 2 個參數,第二個參數表示當前項的索引
```html
<ul id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
```
⑶ 遍歷一個對象的屬性,第二個參數(可選)為鍵名,第三個參數(可選)為索引;遍歷對象時,是按 Object.keys() 的結果進行遍歷的。
```html
<div v-for="(value, name, index) in object">
{{ index }}. {{ name }}: {{ value }}
</div>
```
```js
new Vue({
el: '#v-for-object',
data: {
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
})
```
⑷ 需要為每項提供一個唯一的 key 屬性,數組下標不行(不合理)
```html
<div v-for="item in items" v-bind:key="item.id">
<!-- 內容 -->
</div>
```
⑸ `v-for` 也可以接受整數。在這種情況下,它會把模板重復對應次數
```html
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
```
⑹ 數組更新檢測
Vue 將被偵聽的數組的變異方法進行了包裹,所以它們也將會觸發視圖更新。這些被包裹過的方法包括:
* `push()`
* `pop()`
* `shift()`
* `unshift()`
* `splice()`
* `sort()`
* `reverse()`
Vue**不能**檢測以下數組的變動:
1. 當你利用索引直接設置一個數組項時,例如:`vm.items[indexOfItem] = newValue`
2. 當你修改數組的長度時,例如:`vm.items.length = newLength`
```js
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是響應性的
vm.items.length = 2 // 不是響應性的
```
為了解決第一類問題,以下兩種方式都可以實現和`vm.items[indexOfItem] = newValue`相同的效果,同時也將在響應式系統內觸發狀態更新:
```js
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
```
```js
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
```
你也可以使用 `vm.$set` 實例方法,該方法是全局方法 `Vue.set` 的一個別名:
```js
vm.$set(vm.items, indexOfItem, newValue)
```
為了解決第二類問題,你可以使用 `splice`:
```js
vm.items.splice(newLength)
```
## 事件處理
事件修飾符
* .stop - 調用 event.stopPropagation()。
* .prevent - 調用 event.preventDefault()。
* .capture - 添加事件偵聽器時使用 capture 模式。
* .self - 只當事件是從偵聽器綁定的元素本身觸發時才觸發回調。
* .{keyCode | keyAlias} - 只當事件是從特定鍵觸發時才觸發回調。
* .native - 監聽組件根元素的原生事件。
* .once - 只觸發一次回調。
* .left - (2.2.0) 只當點擊鼠標左鍵時觸發。
* .right - (2.2.0) 只當點擊鼠標右鍵時觸發。
* .middle - (2.2.0) 只當點擊鼠標中鍵時觸發。
* .passive - (2.3.0) 對應于 addEventListener 中的 passive 選項
例如:
`@click.stop.prevent`:禁止事件冒泡和預設行為,移動端下拉事件經常使用
`@click.prevent`:不處理任何的點擊事件,可以給 Toast 的蒙版添加該行為
`@keyup.enter.exact` 或者 `@keyup.13.exact`:keyup 是按下按鍵抬起后觸發 exact 精確要求回車, 不加的話按 shift+enter 也會觸發
```html
<!-- 阻止單擊事件繼續傳播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修飾符可以串聯 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件監聽器時使用事件捕獲模式 -->
<!-- 即元素自身觸發的事件先在此處理,然后才交由內部元素進行處理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只當在 event.target 是當前元素自身時觸發處理函數 -->
<!-- 即事件不是從內部元素觸發的 -->
<div v-on:click.self="doThat">...</div>
```
`v-on`用在普通元素上時,只能監聽原生 DOM 事件。用在自定義元素組件上時,也可以監聽子組件觸發的 **自定義事件**。
## 表單輸入綁定
`v-model`其實是一種簡寫:
```html
<input v-model="searchText">
等價于:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
```
`v-model`在內部為不同的輸入元素使用不同的屬性并拋出不同的事件:
* text 和 textarea 元素使用`value`屬性和`input`事件;
* checkbox 和 radio 使用`checked`屬性和`change`事件;
* select 字段將`value`作為 prop 并將`change`作為事件。
>[danger]v-model 會忽略所有表單元素的 value、checked、selected 特性的初始值而總是將 Vue 實例的數據作為數據來源。你應該通過 JavaScript 在組件的 data 選項中聲明初始值。
*****
當用在組件上時,`v-model`則會這樣:
``` html
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
```
為了讓它正常工作,這個組件內的 \<input\> 必須:
? 將其 value 特性綁定到一個名叫 value 的 prop 上
? 在其 input 事件被觸發時,將新的值通過自定義的 input 事件拋出
```html
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
```
現在 v-model 就應該可以在這個組件上完美地工作起來了:
```html
<custom-input v-model="searchText"></custom-input>
```
## 自定義指令
```js
// 注冊一個全局自定義指令 `v-focus`
Vue.directive('focus', {
// 當被綁定的元素插入到 DOM 中時……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
```
如果想注冊局部指令,組件中也接受一個`directives`的選項:
```js
directives: {
focus: {
// 指令的定義
inserted: function (el) {
el.focus()
}
}
}
```
然后你可以在模板中任何元素上使用新的`v-focus`屬性,如下:
```html
<input v-focus>
```
# 計算屬性與偵聽器
## computed
對于模板中的復雜邏輯,應該將其設置為計算屬性
```js
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
```
```js
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 計算屬性的 getter
reversedMessage: function () {
// `this` 指向 vm 實例
return this.message.split('').reverse().join('')
}
}
})
```
當 vm.message 發生改變時,vm.reversedMessage 會自動更新。
調用方法也可以實現同樣的效果:
```html
<p>Reversed message: "{{ reversedMessage() }}"</p>
```
```js
// 在組件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
```
區別是:**計算屬性是基于它們的響應式依賴進行緩存的**。只在相關響應式依賴發生改變時它們才會重新求值。這就意味著只要`message`還沒有發生改變,多次訪問`reversedMessage`計算屬性會立即返回之前的計算結果,而不必再次執行函數。
## watch
偵聽器 watch 是一種通用的用于觀察和響應 Vue 實例上的數據變動的方式,使用方式如下:
```html
<div id="demo">{{ fullName }}</div>
```
```js
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
},
watch: {
// 監聽的屬性和其發生變化后觸發的回調
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
}
}
})
```
# 組件
## 模板
.vue 文件的模板大致是這樣的:(將由 vue-loader 進行解析)
```html
<template>
<div class="component-class"></div>
</template>
<script>
import { } from ...
export default {
mixins: [], // 混入(組合)
components: {}, // 子組件(模板內使用的資源)
props: { title: { type: Boolean, default: true} }, // 接口
data () {}, // 本地狀態-實例的數據對象
computed: {}, // 本地狀態-計算屬性
watch: {}, // 偵聽屬性
methods: { plus: function () { this.a++ } }, // 方法
// 生命周期鉤子
created () {},
mounted () {}
}
</script>
<style lang="scss" scoped>
@import "../../mixin.scss"
</style>
```
## 組件通信
組件間的通信可分為父子組件通信、兄弟組件通信、跨級組件通信。
**1.父子組件通信**
- props 選項:子組件可以通過 props 選項來接收父組件的數據,數據流的傳輸是單向的。
- $emit 與 v-on:子組件通過調用內置的 $emit 方法并傳入事件名稱來觸發一個事件,父組件使用 v-on 監聽子組件實例的任何事件。
- $children 與 $parent(不推薦使用):在子組件中,使用 `this.$parent` 可以直接訪問該組件的父實例或組件,父組件也可以通過 `this.$children` 訪問它所有的子組件,而且可以遞歸向上或向下無限訪問,直到根實例或最內層的組件。
- ref:父組件可以用特殊的屬性 ref 來為子組件(或者DOM)指定一個索引名稱。通過`this.$refs.xxx`可以訪問到這個子組件。
**2.兄弟組件通信與跨級組件通信**
- 中央事件總線 bus:創建一個名為 bus 的空 Vue 實例。其他組件都通過 bus 來發送事件并且監聽來自 bus 的事件。
- vuex:如果業務邏輯復雜,很多組件之間需要同時處理一些公共的數據,就需要使用 vuex,vuex 的做法就是將這一些公共的數據抽離出來,然后其他組件就可以對這個公共數據進行讀寫操作,這樣達到了解耦的目的。
## 插槽
1.作用域:父級模板里的所有內容都是在父級作用域中編譯的;子模板里的所有內容都是在子作用域中編譯的。
```html
<navigation-link url="/profile">
Clicking here will send you to: {{ url }}
<!--
這里的 `url` 會是 undefined,因為 "/profile" 是
傳遞給 <navigation-link> 的而不是
在 <navigation-link> 組件*內部*定義的。
-->
</navigation-link>
```
2.后備內容:我們可能希望在一個`<button>`內絕大多數情況下都渲染文本“Submit”。為了將“Submit”作為后備內容,我們可以將它放在`<slot>`標簽內:
```html
<button type="submit">
<slot>Submit</slot>
</button>
```
現在當我在一個父級組件中使用 `<submit-button>` 并且不提供任何插槽內容時:
```html
<submit-button></submit-button>
```
后備內容“Submit”將會被渲染:
```html
<button type="submit">
Submit
</button>
```
## 內置組件
1.\<component>
```html
<!-- 動態組件由 vm 實例的屬性值 `componentId` 控制 -->
<component :is="componentId"></component>
```
我們還需要引入使用到的組件,注意是放在 data 選項中:
```js
import StaffInfo from '../components/StaffInfo.vue'
import LeaveTable from '../components/LeaveTable.vue'
import SalaryTable from '../components/SalaryTable.vue'
import GateTable from '../components/GateTable.vue'
export default {
data: function () {
return {
StaffInfo,
LeaveTable,
SalaryTable,
GateTable
}
},
```
2.\<transition>
* 使用 v-show / v-if 動態顯示或隱藏元素時,會觸發過渡動畫
* transition 需要指定 name,并包裹一個含 v-show / v-if 的 div
* vue 會為 transition 包裹的 div 動態添加 class,共6種

v-enter: 顯示之前  v-enter-to: 顯示之后  v-enter-active: 顯示的過程
v-leave: 隱藏之前  v-leave-to: 隱藏之后  v-leave-active: 隱藏的過程
注意 transition 的樣式必須和包裹的 div 同級(scss)
例如:
```html
<transition name="fade">
<div class="popup-bg" @click.stop.prevent="hide()" v-if="popupVisible"></div>
<!--灰色的背景圖層, 點擊后彈窗隱藏. 禁止事件冒泡和預設行為-->
</transition>
```
這是一個淡入淡出的效果:
```css
.fade-enter, .fade-leave-to {
opacity: 0;
}
.fade-enter-to, .fade-leave {
opacity: 1;
}
.fade-enter-active, .fade-leave-active {
transition: all .3s linear;
}
```
3.\<transition-group>
* 不同于`<transition>` ,它會渲染一個真實的 DOM 元素,默認為`span`。你也可以通過 tag 特性更換為其他元素。
* 過渡模式不可用,因為我們不再相互切換特有的元素。
* 內部元素總是需要提供唯一的 key 屬性值。 不僅可以進入和離開動畫,還可以改變定位。要使用這個新功能只需了解新增的 v-move 特性,它會在元素的改變定位的過程中應用。 像之前的類名一樣,可以通過 name 屬性來自定義前綴,也可以通過 move-class 屬性手動設置。
```html
<transition-group name="list"
tag="div"
id="item-list">
<div class="item" v-for="(item, index) in items" :key="item.id"></div>
</transition-group>
```
```css
.list-move {
transition: transform 1s;
}
.list-leave-active {
display: none;
}
```
還需要注意以下事項:
- name:用于自動生成 CSS 過渡類名
- tag:這個\<transition-group>組件在DOM中實際以什么樣的形式存在,默認渲染為 \<span>
- 每個 \<transition-group> 的子節點必須有獨立的 key ,動畫才能正常工作
可以看下這個 [demo](https://github.com/ChenMingK/epub-Proj/blob/master/%E5%BC%80%E5%8F%91%E6%96%87%E6%A1%A3/%E4%B9%A6%E6%9E%B6%E5%BC%80%E5%8F%91.md)
4.\<keep-alive>
`<keep-alive>` 包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。`<keep-alive>`是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現在父組件鏈中。
當組件在 `<keep-alive>` 內被切換,它的 `activated` 和 `deactivated` 這兩個生命周期鉤子函數將會被對應執行。
- Props:
- `include`\- 字符串或正則表達式。只有名稱匹配的組件會被緩存。
- `exclude`\- 字符串或正則表達式。任何名稱匹配的組件都不會被緩存。
- `max`\- 數字。最多可以緩存多少組件實例。
應用場景:避免組件的反復重建和渲染,保存用戶狀態等。
```html
<!-- 基本 -->
<keep-alive>
<component :is="view"></component>
</keep-alive>
<!-- 多個條件判斷的子組件 -->
<keep-alive>
<comp-a v-if="a > 1"></comp-a>
<comp-b v-else></comp-b>
</keep-alive>
<!-- 和 `<transition>` 一起使用 -->
<transition>
<keep-alive>
<component :is="view"></component>
</keep-alive>
</transition>
```
# 生命周期
生命周期函數就是組件在初始化或者數據更新時會觸發的鉤子函數。

下面配合源碼來看下生命周期的鉤子函數是如何執行的,參考:[Vue 技術揭秘](https://ustbhuangyi.github.io/vue-analysis/components/lifecycle.html#beforeupdate-updated)
源碼中最終執行生命周期的函數都是調用`callHook`方法,它的定義在`src/core/instance/lifecycle`中:
```js
export function callHook (vm: Component, hook: string) {
// #7573 disable dep collection when invoking lifecycle hooks
pushTarget()
const handlers = vm.$options[hook]
if (handlers) {
for (let i = 0, j = handlers.length; i < j; i++) {
try {
handlers[i].call(vm)
} catch (e) {
handleError(e, vm, `${hook} hook`)
}
}
}
if (vm._hasHookEvent) {
vm.$emit('hook:' + hook)
}
popTarget()
}
```
`callHook`函數的邏輯很簡單,根據傳入的字符串`hook`,去拿到`vm.$options[hook]`對應的回調函數數組,然后遍歷執行,執行的時候把`vm`作為函數執行的上下文。
各個階段的生命周期的函數會被合并到`vm.$options`里,并且是一個數組。因此`callhook`函數的功能就是調用某個生命周期鉤子注冊的所有回調函數。
## beforeCreate & created
`beforeCreate`和`created`函數都是在實例化`Vue`的階段,在`_init`方法中執行的,它的定義在`src/core/instance/init.js`中:
```js
Vue.prototype._init = function (options?: Object) {
// ...
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm) // 初始化props、data、methods、watch、computed 等屬性
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
// ...
}
```
在這倆個鉤子函數執行的時候,并沒有渲染 DOM,所以我們也不能夠訪問 DOM,一般來說,如果組件在加載的時候需要和后端有交互,放在這倆個鉤子函數執行都可以,如果是需要訪問`props`、`data`等數據的話,就需要使用`created`鉤子函數。vue-router 和 vuex 的就是利用`beforeCreatd`鉤子將自己注入到組件中的。
## beforeMount & mounted
```js
export function mountComponent {
callHook(vm, 'beforeMount')
// ...
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
}
```
`beforeMount`就是在掛載前執行的,然后開始創建 VNode并替換成真實 DOM,最后執行`mounted`鉤子。`vm.$vnode`如果為`null`,則表明這不是一次組件的初始化過程,而是我們通過外部`new Vue`初始化過程,所以直接執行`mounted`鉤子了。如果有子組件的話,會遞歸掛載子組件,只有當所有子組件全部掛載完畢,才會執行根組件的掛載鉤子。
## beforeUpdate & updated
`beforeUpdate`和`updated`的鉤子函數執行時機都應該是在數據更新的時候
`beforeUpdate`的執行時機是在渲染 Watcher 的`before`函數中:
```js
export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
// ...
// we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted) {
callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)
// ...
}
```
注意這里有個判斷,也就是在組件已經`mounted`之后,才會去調用這個鉤子函數。
`update`的執行時機是在`flushSchedulerQueue`函數調用的時候,它的定義在`src/core/observer/scheduler.js`中:
```js
function flushSchedulerQueue () {
// ...
// 獲取到 updatedQueue
callUpdatedHooks(updatedQueue)
}
function callUpdatedHooks (queue) {
let i = queue.length
while (i--) {
const watcher = queue[i]
const vm = watcher.vm
if (vm._watcher === watcher && vm._isMounted) {
callHook(vm, 'updated')
}
}
}
```
`updatedQueue`是更新了的`wathcer`數組,那么在`callUpdatedHooks`函數中,它對這些數組做遍歷,只有滿足當前`watcher`為`vm._watcher`以及組件已經`mounted`這兩個條件,才會執行`updated`鉤子函數。
## beforeDestroy & destroyed
`beforeDestroy`和`destroyed`鉤子函數的執行時機在組件銷毀的階段
最終會調用`$destroy`方法,它的定義在`src/core/instance/lifecycle.js`中:
```js
Vue.prototype.$destroy = function() {
// ...
callHook(vm, 'beforeDestroy')
vm._isBeingDestroyed = true
// remove self from parent
const parent = vm.$parent
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
remove(parent.$children, vm)
}
// teardown watchers
if (vm._watcher) {
vm._watcher.teardown()
}
let i = vm._watchers.length
while (i--) {
vm._watchers[i].teardown()
}
// remove reference from data ob
// frozen object may not have observer.
if (vm._data.__ob__) {
vm._data.__ob__.vmCount--
}
// call the last hook...
vm._isDestroyed = true
// invoke destroy hooks on current rendered tree
vm.__patch__(vm._vnode, null)
// fire destroyed hook
callHook(vm, 'destroyed')
// turn off all instance listeners.
vm.$off()
// remove __vue__ reference
if (vm.$el) {
vm.$el.__vue__ = null
}
// release circular reference (##6759)
if (vm.$vnode) {
vm.$vnode.parent = null
}
}
```
`beforeDestroy`鉤子函數的執行時機是在`$destroy`函數執行最開始的地方,接著執行了一系列的銷毀動作,包括從`parent`的`$children`中刪掉自身,刪除`watcher`,當前渲染的 VNode 執行銷毀鉤子函數等,執行完畢后再調用`destroy`鉤子函數。
在`$destroy`的執行過程中,它又會執行`vm.__patch__(vm._vnode, null)`觸發它子組件的銷毀鉤子函數,這樣一層層的遞歸調用,所以`destroy`鉤子函數執行順序是先子后父,和`mounted`過程一樣。
## activated & deactivated
`activated`和`deactivated`鉤子函數是專門為`keep-alive`組件定制的鉤子
當組件在`<keep-alive>`內被切換,它的`activated`和`deactivated`這兩個生命周期鉤子函數將會被對應執行。
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直線、矩形、多邊形
- Part2-曲線圖形
- Part3-線條操作
- Part4-文本操作
- Part5-圖像操作
- Part6-變形操作
- Part7-像素操作
- Part8-漸變與陰影
- Part9-路徑與狀態
- Part10-物理動畫
- Part11-邊界檢測
- Part12-碰撞檢測
- Part13-用戶交互
- Part14-高級動畫
- CSS
- SCSS
- codePen
- 速查表
- 面試題
- 《CSS Secrets》
- SVG
- 移動端適配
- 濾鏡(filter)的使用
- JS
- 基礎概念
- 作用域、作用域鏈、閉包
- this
- 原型與繼承
- 數組、字符串、Map、Set方法整理
- 垃圾回收機制
- DOM
- BOM
- 事件循環
- 嚴格模式
- 正則表達式
- ES6部分
- 設計模式
- AJAX
- 模塊化
- 讀冴羽博客筆記
- 第一部分總結-深入JS系列
- 第二部分總結-專題系列
- 第三部分總結-ES6系列
- 網絡請求中的數據類型
- 事件
- 表單
- 函數式編程
- Tips
- JS-Coding
- Framework
- Vue
- 書寫規范
- 基礎
- vue-router & vuex
- 深入淺出 Vue
- 響應式原理及其他
- new Vue 發生了什么
- 組件化
- 編譯流程
- Vue Router
- Vuex
- 前端路由的簡單實現
- React
- 基礎
- 書寫規范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 與 Hook
- 《深入淺出React和Redux》筆記
- 前半部分
- 后半部分
- react-transition-group
- Vue 與 React 的對比
- 工程化與架構
- Hybird
- React Native
- 新手上路
- 內置組件
- 常用插件
- 問題記錄
- Echarts
- 基礎
- Electron
- 序言
- 配置 Electron 開發環境 & 基礎概念
- React + TypeScript 仿 Antd
- TypeScript 基礎
- React + ts
- 樣式設計
- 組件測試
- 圖標解決方案
- Storybook 的使用
- Input 組件
- 在線 mock server
- 打包與發布
- Algorithm
- 排序算法及常見問題
- 劍指 offer
- 動態規劃
- DataStruct
- 概述
- 樹
- 鏈表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 課程實戰記錄
- 服務器
- 操作系統基礎知識
- Linux
- Nginx
- redis
- node.js
- 基礎及原生模塊
- express框架
- node.js操作數據庫
- 《深入淺出 node.js》筆記
- 前半部分
- 后半部分
- 數據庫
- SQL
- 面試題收集
- 智力題
- 面試題精選1
- 面試題精選2
- 問答篇
- 2025面試題收集
- Other
- markdown 書寫
- Git
- LaTex 常用命令
- Bugs