-
1. vue2遷移vue3記錄 -
1.1. 掛載方式差別 -
1.2. 使用 vue-router
-
1.3. 使用 vuex
-
1.4. router-view
使用keep-alive
-
1.5. Data選項 -
1.6. emits選項 -
1.7. 事件api -
1.8. 過濾器 -
1.9. 片段 -
1.10. 全局api -
1.11. key attribute -
1.12. 按鍵修飾符 -
1.13. propsData -
1.14. 過渡的 class 名更改 -
1.15. Transition 作為 Root -
1.16. 移除v-on.native修飾符 -
1.17. v-model -
1.18. v-if和v-for優先級 -
1.19. v-bind合並行為 -
1.20. VNode 生命周期事件 -
1.21. watch Array
-
1. vue2遷移vue3記錄
開始用Vue3
寫項目時,查看V3 遷移指南發現由於全局 Vue API
已更改為使用應用程序實例,相應的很多操作諸如掛載App
實例,使用vue-router
、vuex
等都發生了一定的變化,為了以后更快的搭建Vue3
項目,把主要的差別簡單記錄如下:
1.1. 掛載方式差別
vue2:
// index.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
render:h=>h(App)
}).$mount('#app')
vue3:
// index.js
import { createApp } from "vue";
import App from './App.vue'
createApp(App).mount("#app");
1.2. 使用vue-router
vue2:
// index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from '@/router'
Vue.use(VueRouter)
const router = new VueRouter({
routes,
mode: 'history',
})
new Vue({
router,
render: h => h(App),
}).$mount('#app')
// src/router/index.js
const home = () => import('../pages/home/Home')
const routes = [
{
path: '',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: home
}
]
export default routes
vue3:
// index.js
import { createApp } from "vue";
import App from './App.vue'
import router from "./router";
createApp(App).use(router).mount("#app");
// src/router/index.js
import { createRouter, createWebHistory } from "vue-router";
const home = () => import("../views/home/Home");
const routes = [
{
path: "",
redirect: "/home",
},
{
path: "/home",
name: "home",
component: home,
},
];
const router = createRouter({
history: createWebHistory(),
routes: routes,
});
export default router;
1.3. 使用vuex
vue2:
// index.js
import Vue from 'vue'
import store from '@/store/';
new Vue({
store,
render:h=>h(App)
}).$mount('#app')
// src/store/index.js
import Vuex from 'vuex'
import Vue from 'vue'
import actions from './actions'
import getters from './getters';
import mutations from './mutations';
Vue.use(Vuex)
const state = {}
export default new Vuex.Store({
state,
actions,
mutations,
getters,
})
vue3:
// index.js
import { store } from "./store";
createApp(App).use(store).mount("#app");
// src/store/index.js
import { createStore } from "vuex";
import actions from "./actions";
import getters from "./getters";
import mutations from "./mutations";
const state = () => {};
export const store = createStore({
state,
actions,
getters,
mutations,
});
1.4. router-view
使用keep-alive
vue2:
// App.vue
<transition name="router-fade" mode="out-in">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
</transition>
<transition name="router-fade" mode="out-in">
<router-view v-if="!$route.meta.keepAlive"></router-view>
</transition>
vue3:
// App.vue
<router-view v-slot="{ Component }">
<transition name="router-fade" mode="out-in">
<keep-alive>
<component :is="Component"/>
</keep-alive>
</transition>
</router-view>
1.5. Data選項
2.x
在根實例上可以聲明為純 JavaScript
object
Mixin
中 Data
選項合並像是取並集?深度合並
3.x
無論何時都應該聲明為function
Mixin
中 Data
選項合並像是取交集?淺層次執行合並
1.6. emits選項
vue3
新增了 emits
選項,和 prop
類似,組件可觸發的事件可以通過 emits
選項被定義:
<template>
<div>
<p>{{ text }}</p>
<button v-on:click="$emit('accepted')">OK</button>
</div>
</template>
<script>
export default {
props: ['text'],
emits: ['accepted']
}
</script>
1.7. 事件api
2.x
中用於事件總線上的$on
/$off
/$once
實例方法已被移除
1.8. 過濾器
2.x
的過濾器已被移除,3.x
建議使用計算屬性或方法來替換過濾器,全局過濾器可以通過全局屬性在所有組件中使用它:
// main.js
const app = createApp(App)
app.config.globalProperties.$filters = {
currencyUSD(value) {
return '$' + value
}
}
然后,你可以通過 $filters
對象修改所有的模板,像下面這樣:
<template>
<h1>Bank Account Balance</h1>
<p>{{ $filters.currencyUSD(accountBalance) }}</p>
</template>
注意,這種方式只能用於方法中,不可以在計算屬性中使用,因為后者只有在單個組件的上下文中定義時才有意義。
1.9. 片段
3.x
支持多根節點的組件,但是要求開發者顯式定義 attribute
應該分布在哪里。
<!-- Layout.vue -->
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
1.10. 全局api
3.x
中調用 createApp
返回一個應用實例,任何全局改變 Vue
行為的 API
現在都會移動到應用實例上,以下是當前 2.x
全局 API
及其相應實例 API
的表:
2.x 全局 API |
3.x 實例 API (app) |
---|---|
Vue.config | app.config |
Vue.config.productionTip | removed |
Vue.config.ignoredElements | app.config.isCustomElement |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
1.11. key attribute
3.x
中在template
上設置v-for
時key
要加在template
1.12. 按鍵修飾符
3.x
不再支持使用數字 (即鍵碼) 作為 v-on 修飾符,不再支持 config.keyCodes
配置按鍵別名
1.13. propsData
propsData
選項已經被移除。如果你需要在實例創建時向根組件傳入 prop
,你應該使用 createApp
的第二個參數:
const app = createApp(
{
props: ['username'],
template: '<div>{{ username }}</div>'
},
{ username: 'Evan' }
)
1.14. 過渡的 class 名更改
3.x
中過渡類名 v-enter
修改為 v-enter-from
、過渡類名 v-leave
修改為 v-leave-from
。
1.15. Transition 作為 Root
一個 <transition>
原本希望是被其子元素觸發的,而不是被 <transition>
自己切換。 換做向其組件傳遞一個 prop
就可以達到類似的效果:
<template>
<transition>
<div v-if="show" class="modal"><slot/></div>
</transition>
</template>
<script>
export default {
props: ['show']
}
</script>
<!-- 用法 -->
<modal :show="showModal">hello</modal>
1.16. 移除v-on.native修飾符
-
刪除 .native
修飾符的所有實例。 -
確保所有組件都使用 emits
選項記錄其事件。
1.17. v-model
在 3.x
中,自定義組件上的 v-model
相當於傳遞了 modelValue prop
並接收拋出的 update:modelValue
事件:
<ChildComponent v-model="pageTitle" />
<!-- 是以下的簡寫: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
若需要更改 model
名稱,作為組件內 model
選項的替代,現在我們可以將一個 argument
傳遞給 v-model
:
<ChildComponent v-model:title="pageTitle" />
<!-- 是以下的簡寫: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
而且允許我們在自定義組件上使用多個 v-model
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
<!-- 是以下的簡寫: -->
<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
對於所有不帶參數的 v-model
,請確保分別將 prop
和 event
命名更改為 modelValue
和 update:modelValue
<ChildComponent v-model="pageTitle" />
// ChildComponent.vue
export default {
props: {
modelValue: String // 以前是`value:String`
},
emits: ['update:modelValue'],
methods: {
changePageTitle(title) {
this.$emit('update:modelValue', title) // 以前是 `this.$emit('input', title)`
}
}
}
1.18. v-if和v-for優先級
2.x
版本中在一個元素上同時使用 v-if
和 v-for
時,v-for
會優先作用。
3.x
版本中 v-if 總是優先於 v-for
生效。
1.19. v-bind合並行為
在 2.x
,如果一個元素同時定義了 v-bind="object"
和一個相同的單獨的 property
,那么這個單獨的 property
總是會覆蓋 object
中的綁定。
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="red"></div>
在 3.x
,如果一個元素同時定義了 v-bind="object"
和一個相同的單獨的 property
,那么聲明綁定的順序決定了它們如何合並。換句話說,相對於假設開發者總是希望單獨的 property
覆蓋 object
中定義的內容,現在開發者對自己所希望的合並行為有了更好的控制。
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>
<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>
1.20. VNode 生命周期事件
3.x
父組件可以通過vnode-生命周期鈎子來監聽子組件生命周期中的關鍵階段。
<template>
<child-component @vnode-updated="onUpdated">
</template>
或者在駝峰命名法的情況下附帶前綴 vnode
:
<template>
<child-component @vnodeUpdated="onUpdated">
</template>
1.21. watch Array
3.x
當使用 watch
選項偵聽數組時,只有在數組被替換時才會觸發回調。換句話說,在數組改變時 watch
回調將不再被觸發。要想在數組改變時觸發 watch
回調,必須指定 deep
選項。
watch: {
bookList: {
handler(val, oldVal) {
console.log('book list changed')
},
deep: true
},
}