-
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
},
}
