0%

Vuejs 2 和 3 的差異

起手式的寫法

Vu2

1
2
3
4
5
6
7
8
9
10
11
12
13
let app = new Vue({
el: "#app",
data:{
todos: [
'todo1', 'todo2', 'todo3'
],
},
methods: {
deleteTodo: (index)=> {
app.todos.splice(index, 1)
},
},
});

Vue3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const app = Vue.createApp({
data(){
return {
todos: [
'todo1',
'todo2',
'todo3'
],
};
},
methods: {
deleteItem: function(index)=> {
this.app.todos.splice(index, 1)
},
},
})

const vm = app.mount('#app'); // 最後在綁定

TELEPORT

component 寫法不同

Vue2

HTML 裡的 <model-button> 為自定義標籤,HTML 內容則寫在model-buttontemplate裡。
這個 Modal 彈出視窗通常會放在 <body>附近,如果寫在 HTML 太裡面會不好調整, 如果使用 Teleport 則可以使用<teleport to="body">語法,將這個 Modal 放到 </body> 前面。

1
2
3
4
5
6
7
8
9
<body>
<div style="position: relative;">
<h3>cTooltips with Vue 3 Teleport</h3>
<div>
<modal-button></modal-button>
</div>
</div>
<!-- 使用 Teleport 會將 template 放到這裡來。 -->
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// .Vue.extend({
app.component('modal-button',{
template: `
<button @click="modalOpen" = true>
Open full screen modal!
</button>

<div v-if="modalOpen" class="modal">
<div>
I'm a modal
<button @click="modalOpen" = false>
Close
</button>
</div>
</div>
`,
data(){
return {
modalOpen: false,
}
}
})

Teleport 寫法與用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Vue3寫法
template: `
<button @click="modalOpen" = true>
Open full screen modal! (With teleport!)
</button>

<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleport modal (my parent is "body")
<button @click="modalOpen" = false>
Close
</button>
</div>
</div>
</teleport>
`,
data(){
return {
modalOpen: false,
}
}

Composition API

Option API 的寫法叫零散,而 Composition API 寫法適合較大的專案,把同樣性質的碼放在同一區塊裡,讓專案更好管理。

KEY

Vue2

在 Vue2 時頗常使用 KEY 的寫法,來區分哪個 input

1
2
3
4
5
6
7
8
9
// Vue2 寫法
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>

Vue3

不需寫 key 讓程式碼更精簡,Vue3 會自動判斷。

1
2
3
4
5
6
7
8
9
// Vue3 寫法
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>

在 Template 寫法

Vue2

需要寫在每個標籤上

1
2
3
4
5
// Vue2
<template v-if="item in list">
<div :key="item.id">...</div>
<span :key="item.id">...</span>
</template>

Vue3

1
2
3
4
5
// Vue3
<template v-if="item in list" :key="item.id">
<div >...</div>
<span >...</span>
</te

ARRAY CHANGE DETECTION

通常 Data 裡面的資料只要一被更動,就會馬上畫面上更動呈現,但在 Array 的部份,並沒這麼聰明,當我們更改資料裡的陣列時, Vue2 不會立即反應至畫面,解決方法是在以 set 的方式來解決。

Vue2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var vm = Vue({
data: {
items: ['a', 'b', 'c'],
}
})
vm.item[1] = "x"; // is NOT reactive
vm.item.length = 2; // is NOT reactive
// --------------
// 以 Vue.set來解決
Vue.set(vm.items, indexOfItem, newValue)

// Array.prototype.splice
Vue.items.splice(indexOfItem, 1, newValue)

Vue.$set(vm.items, indexOfItem, 1, newValue)
1
2


Vue3

會直接修改畫面,而不需使用 set 範例

V-FOR With V-IF

在Vue 裡 V-FORV-IF 混在一起寫的狀況是非常不推薦的。
在 Vue2 如把兩者寫在一起 <v-for> 會優先,再檢查<v-if> 有沒有成立,而 Vue3 則相反,會先檢查 <v-if> 條件有沒成立,再去跑<v-for> 迴圈。

1
<li v-for="todo in todos" v-if="!todo.isComplete"> {{ todo }} </li>

如果不想記執行順序,最好還是多寫一層會比較清楚。

1
2
3
<template v-for="todo in todos">
<li v-if="!todo.isComplete"> {{ todo }} </li>
</template>

KEY CODE

KEY CODE 是鍵盤的對應代碼,例如 13 = enter,在 Vue3 裡已經棄用此方法,而直接以 Key modifiers 方式寫鍵盤名稱。

1
2
3
4
5
6
7
<!-- vue2 寫法 -->
<input v-on:keyup.13="submit">

<!-- only call `vm.submit()` when the `key` is `Enter` -->
<input @keyup.enter="submit" />
<!-- converting key names to kebad-case -->
<input @keyup.page-down="onPageDown" />

Key Aliases

.enter, .tab, .delete(captures both "Delete" and "Backspace" keys), .esc, .space, .up, .down, .left, .right

CONPONENT

Vue2

component 在 Vue2 的寫法是用 vue 的物件去宣告,切需要將內容包在一個 div(html root) 裡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Define a new component called button-counter
Vue.component('button-counter', {
data: function(){
return {
title: "title",
content: "<p>content...</p>"
}
},
template:`
<div class="blog-post">
<h3>{{title}}</h3>
<div v-html="content"></div>
</div>
`
})
new Vue({ el: '#components-demo'})

Vue3

component 在 Vue3 的寫法會先createApp({})再去宣告一個 component。且內容物不需再以 div 包起來。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// create a Vue application
const app = Vue.createApp({})

// Define a new global component called counter
app.component('button-counter', {
data(){
return: {
title: "title",
content: "<p>content...</p>"
}
},
template:`
<h3>{{title}}</h3>
<div v-html="content"></div>
`
})

app.mount('#components-demo')

V-MODEL ON COMPONENT

1
2
3
4
<input v-model="searchText" />

<!-- 綁定資料 / 監聽 -->
<input :value="searchText" @input="searchText = 4event.target.value" />

在 component 裡綁定的方法也不太相同

Vue2

Vue2 的 v-model 是綁定 value,綁定的事件是 input

1
2
3
4
5
6
7
8
9
10
11
12
<custom-input v-bind:value="searchText" v-on:input="searchText = $event"></custom-input>

// component
Vue.component('custom-input', {
props: ['value'],
templete:
`
<input
v-bind:value="value",
v-on:input="$emit('input', $event.target.value)"
`
})

Vue3

Vue3 的 v-model 綁定的是 model-value 與 update 的事件

1
2
3
4
5
6
7
8
9
10
11
12
13
<custom-input v-bind:model-value="searchText" @update:model-value="searchText = $event"></custom-input>

// component
app.component('custom-input', {
props: ['modelValue'],
emits:['update:modelValue'],
templete:
`
<input
:value="modelValue",
@input="$emit('update:modelValue', $event.target.value)"
`
})
1
<custom-input v-model="searchText"></custom-input>

DOM TEMPLATE PARSING CAVEATS (DOM模板解析的注意事項)

有時想要在一個

塞入一個元件,但因為瀏覽器解析沒有表格標籤trtd就會報錯,所以 vue.js 在 table 同樣置入一個<tr>的標籤,並在標籤上塞入元件名稱,來看看 vue2, 3的差異。

1
2
3
4
<!-- 這樣寫會出錯 -->
<table>
<blog-post-row></blog-post-row>
</table>

Vue2

1
2
3
<table>
<tr is="blog-post-row"></tr>
</table>

Vue3

1
2
3
4
<table>
<!-- 不可直接寫元件名,需用單引號包起來 -->
<tr iv-s="'blog-post-row'"></tr>
</table>

REMOVE $on / $off / $once (棄用)

原本是以 $on / $off / $once 來湊出新的架構為: EVENBUS 來當作各元件之間的橋樑
現在作法會先開一個空的 Vue 並說明客製化一個名為 custom-event ,當event發生時會做一些事情。

Vue2

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
// eventHub.JS
const eventHub = new Vue()
export default eventHub

// ChildComponent.vue
import eventHub from './eventHub'

export default {
mounted() {
// adding eventHub listener
eventHub.$on('custom-event', ()=>{
console.log('Custom event triggered');
})
},
beforeDestroy() {
// removing eventHub listener
eventHub.$off('custom-event')
},
}

// ParentComponent.vue
import eventHub from './eventHub'

export default {
methods:{
callGlobalCustomEvent(){
eventHub.$emit('custom-event')
// if ChildComponent is mounted, we will...
}
}
}

eventBus 被棄用後,替代方案為 Vuex

Vue Cli / Vite

Vue Cli 以下指令的方式創建專案,使用webpack
Vite 以下指令的方式創建專案,但渲染頁面速度更快,因為使用瀏覽器內建系統。

Vue2

Vue3

Vue2

Vue3

Vue2

Vue3