Vue.js 由 1 到 2 的旅程 - (1)

這系列文章會是記錄從 Vue 版一轉移到版二過程中差異點的筆記,希望以輕鬆短篇的方式撰寫。小弟認為如果您不是那種會乖乖的把文件完整娓娓讀一遍的人,有許多差異點可能就被您忽略了,當然就把它們忘了或從來沒理解過(從 Vue 2 入手的朋友們)也不會是什麼大問題,反正等到您遇到問題的時候肯定又會找到它。不過這系列跟希望紀錄的是思路的演進,像是為什麼不支援內建 filter 這類的議題,每一次改變總有它的道理我們不一定能參透但試著想想看並記錄下來希望下一次能成為更好的開發者。

廢話不多說就讓我們開始來說今天的故事:

is 與 < component >

事實上很多直上 vue-loader 的觀眾們可能會忽略 Vue 有一個 < component > 樣板標籤。
怎麼使用呢?看看下面的範例程式碼,假如我們定義了一個元件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Vue.component('engine', {
template: `
<div>
Engine: TSI
</div>
`,
})

new Vue({
el: '#root',
template: `
<div>
<component is="engine"></component>
</div>
`
})

什麼用途呢?腦袋轉得快的朋友們馬上就意識到可以用來 binding 變數切換元件,官方文件當然也有說明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Vue.component('iphone', {
template: `<div>iphone</div>`
})

Vue.component('s7', {
template: `<div>Samsung S7</div>`
})

new Vue({
el: '#app',
template: `
<div>
<button type="button" @click="change">Change Phone</button>
<component :is="mobile"></component>
</div>
`,
data: {
mobile: 'iphone'
},
methods: {
change: function () {
this.mobile = this.mobile === 'iphone' ? 's7' : 'iphone'
}
}
})

keep-alive

不管您是順著文件閱讀或是直覺地想問 切換過程中我可以保留該元件的狀態嗎? 萬一我的元件很大可以快取嗎?,下一個解救我們的主角 - keep-alive 就會接續登場。

沒錯!它的用途就是將我們的物件實例暫存在記憶體,避免反覆重新渲染同時也保留了狀態。只不過他在版本ㄧ、二之間有點差異:

1
2
3
4
5
6
7
<!-- v 1.x -->
<component :is="currentView" keep-alive></component>

<!-- v 2.x -->
<keep-alive>
<component :is="currentView"></component>
</keep-alive>

上面這兩小節純粹是為了鋪陳,沒什麼特別驚人之處,keep-alive 也只是順便帶上。接下來就是本日容易忽略的地方:

今日特餐 - activate(v1.x) v.s activated/deactivated(v2.x)

先來聊聊在版本一時,官方文件 - Components 一章曾經探討到關於 activate 這個特殊的 hook。白話文來說這個事件在我們手動插入 Vue 物件實例時,例如:使用 new Vue() 的情況下是不會被觸發的。只有在使用 這樣的方式才會發動,第一次認識這傢伙是因為 vue-router v1。

另外這傢伙有一個特殊之處就是它具備一個 done 參數,須被執行元件才會正確地被掛載。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* Vue 1.x
*/
Vue.component('transmission', {
template: `
<div>{{name}}</div>
`,
data: function () {
return {
name: 'DQ200'
}
},
activate: function (done) {
console.log('transmission activate')
done()
}
})

Vue.component('engine', {
template: `
<div>{{name}}</div>
`,
data: function () {
return {
name: 'TSI'
}
},
activate: function (done) {
console.log('engine activate')
done()
}
})

new Vue({
el: '#car',
activate: function (done) {
console.log('car activate') // missing: no trigger
done()
}
})

這也讓我們有機會在切換元件的過程中確定是不是該輸出該元件。可想而知這用在 router 上是多麽合適。

那麼在版本二之後呢?

在 Vue 2.x 裡我們已經沒有這個 Hook 可以使用了,沒有取而代之。但是有相似的傢伙 - 是 activated 與 deactivated。且需要注意的是這兩個掛鉤只會在套用 keep-alive 時被觸發。注意過去式,這兩者和版本一的 activate 觸發的時間點是不同的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Vue.component('iphone', {
template: `<div>iphone</div>`,
activated: function () {
console.log('iphone activated')
},
deactivated: function () {
console.log('iphone deactivated')
}
})

Vue.component('s7', {
template: `<div>Samsung S7</div>`,
activated: function () {
console.log('s7 activate')
},
deactivated: function () {
console.log('s7 deactivated')
}
})

new Vue({
el: '#app',
template: `
<div>
<button type="button" @click="change">Change Phone</button>
<keep-alive>
<component :is="mobile"></component>
</keep-alive>
</div>
`,
data: {
mobile: 'iphone'
},
methods: {
change: function () {
this.mobile = this.mobile === 'iphone' ? 's7' : 'iphone'
}
}
})

Vue.js 由 1 到 2 的旅程 - (1)

https://andyyou.github.io/2016/12/05/vue-hook/

作者

andyyou(YOU,ZONGYAN)

發表於

2016-12-05

更新於

2023-12-05

許可協議