vue2迁移vue3记录

1. vue2迁移vue3记录

开始用Vue3写项目时,查看V3 迁移指南发现由于全局 Vue API 已更改为使用应用程序实例,相应的很多操作诸如挂载App实例,使用vue-routervuex等都发生了一定的变化,为了以后更快的搭建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,
  renderh => 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 MixinData 选项合并像是取并集?深度合并

3.x无论何时都应该声明为function MixinData 选项合并像是取交集?浅层次执行合并

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-forkey要加在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,请确保分别将 propevent 命名更改为 modelValueupdate:modelValue

<ChildComponent v-model="pageTitle" />
// ChildComponent.vue

export default {
  props: {
    modelValueString // 以前是`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-ifv-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‘)
    },
    deeptrue
  },
}

vue2迁移vue3记录

上一篇:The Book of CSS3 中文版 第一章:介绍CSS3


下一篇:灵巧的JS下拉导航代码