Vue 3 引入了一些新功能和一系列重大更改。让我们看看这些更改将如何影响我们的应用程序。
在 Vue 3 中,重大更改基本上分为七类:
在所有更改中,有一些是任何应用程序都会使用的,例如全局API和组件。因此,如果你想开始使用新的 Vue 版本,就需要考虑它们。
值得一提的是以下附加更改:
有关更改的完整列表,您可以转到文档
现在,让我们更详细地看一下其中的一些更改。
vue2
- import Vue from 'vue'
- Vue.prototype.$http=Axiox
- Vue.prototype.$echart= Echart
vue3
globalProperties- app.config.globalProperties.$http = Axios
- app.config.globalProperties.$echart = Echart
- import {getCurrentInstance} from 'vue'
-
- setup () {
- const { ctx } = getCurrentInstance();
- onMounted(() => {
- console.log(ctx.$http)
- })
- .......
- }
vue2
VUE2中的V-FOR与REF一起使用,当引用批量模板时,获得的REF是一个数组。
- <div v-for = "i in 3" ref = "setItemref": key = "i"> {{i}} </ div> // Here are arrays
-
- mounted() {
- console.log(this.$refs.setItemRef)
- },
vue3
VUE3 中的 REF 绑定是一个函数,
- <div v-for = "item in 3": ref = "setItemRef"> </ div> // This is a function
-
- setup(){
- let itemRefs = []
- const setItemRef = el => {
- itemRefs.push(el)
- }
- onMounted(() => {
- console.log(itemRefs)
- })
- }
REF 的 DOM 模式已更改,但结果是相同的

在路由中,通常使用延迟加载的方式来引入组件。
vue2
component: () => import('@/views/homePage/index.vue'),
vue3
在 Vue3 中引入一个新方法--->定义异步组件来打包 Vue2 介绍的内容defineAsyncComponent
- import { defineAsyncComponent } from 'vue'
- component: defineAsyncComponent(() => import('./NextPage.vue'))
vue2
VUE2 中绑定的钩子函数是
vue3
钩子函数的命名与生命周期的钩子函数一致
某些实例需要获取组件中实例的某些属性
vue2
- Vue.directive('has', {
- inserted: (el, binding, vnode) => checkPermission(el, binding, vnode),
- });
-
- export const checkPermission = (el, binding, vnode) => {
- ...
- Const permissionarr = vnode.context. $ store.state.PermissionID // All permission ID
- ...
- }
vue3
- export const checkPermission = (el, binding, vnode) => {
- ...
- Const permissionarr = binding.instance. $ store.State.PermissionID // All permission ID
- ...
- }
v-bind=“$attrs”
vue2
<component :is="currentTabComponent"></component>
- <table>
- <tr is="blog-post-row"></tr>
- </table>
vue3
<component is="currentTabComponent"></component>
- <table>
- <TR V-IS = "'blog-post-rot"> </ tr> // V-IS is similar to binding a variable, and we need a component name, a string, so wrapped with single quotes
- </table>
$on$off$once$emit过滤器函数在 Vue3 中被删除。建议使用方法或计算代替,实际上,在 Vue2 中,你可以实现这两种方式。
vue2
- <p>{{message|toLower}}</p>
-
- data() {
- return {
- message: 'ABC'
- }
- },
- filters: {
- toLower(value) {
- return value.toLowerCase()
- }
- }
vue3
- <p>{{messageToLower}}</p>
-
- import {
- computed,
- ref,
- } from 'vue';
-
- setup(){
-
- let message = ref('ABC')
- let messageToLower = computed(() => {
- // console.log(message)
- return message.value.toLowerCase()
- })
- return{
- messageToLower,
- }
-
- }
vue2
- Vue.filter('toLower', (value)=> {
- return value.toLowerCase()
- })
vue3
- const app =createApp(App)
- app.config.globalProperties.$filter={
- toLower(value){
- return value.toLowerCase()
- }
- }
<p>{{$filters.toLower(message)}}</p>
vue2
template- <template>
- <div id="app">
- ...
- </div>
- </template>
vue3
- <template>
- <div>...</div>
- <a>...</a>
- <p>...</p>
- </template>
- <template>
- <div class="wrap">
- <div>{{ num }}</div>
- <Button @ click = "getdata"> change data </ button>
- </div>
- </template>
- <style lang="less" scoped>
- .wrap {
- width: 100%;
- height: 100%;
- border: 1px solid red;
- }
- </style>
-
- <!-- vue2 -->
- <script>
- export default {
- data() {
- return {
- num: 333,
- };
- },
- //
- mounted() {
- alert('111');
- this.getData();
- },
- methods: {
- getData() {
- this.num = '2222';
- },
- },
- };
- </script>
- <!-- vue3.0 -->
- <script>
- import { defineComponent, ref } from 'vue';
- export default defineComponent({
- setup() {
- let num = ref(1223);
- function getSecondData(params) {
- alert('222');
- }
- function getData(params) {
- num.value = 'weruwiru';
- getSecondData();
- }
- return {
- num,
- getData,
- };
- },
- });
- </script>
- <!-- vue3.2 -->
- <script setup>
- import { ref } from 'vue';
- let num = ref(1223);
- function getSecondData(params) {
- alert('222');
- }
- function getData(params) {
- num.value = 'weruwiru';
- getSecondData();
- }
- </script>
vue2
使用内联模板属性
Vue2 中的文档会提示这样一个词,所以我几乎用了
但是,内联模板会使模板的作用更难理解。因此,作为最佳实践,请选择组件模板 Option 或.vue One中的file<template> Elements来定义模板。>
vue3
删除此功能,
vue2
- <!---->
- <template v-if="loginType === 'username'">
- <hello-world title="username"></hello-world>
- </template>
- <template v-else>
- <hello-world title="email"></hello-world>
- </template>
- <Button @ Click = "ChangeType"> Switch </ button>
- <template v-if="loginType === 'username'">
- <hello-world title="username" key="a"></hello-world>
- </template>
- <template v-else>
- <hello-world title="email" key="b"></hello-world>
- </template>
- <Button @ Click = "ChangeType"> Switch </ button>
vue3
Vue3 默认为键,此键始终是唯一的,不同于其他键,不能使用相同的键来强制重用分支。
- <div v-if="condition">Yes</div>
- <div v-else>No</div>
vue2
在 Vue2 的 Template 选项卡上,你可以使用 V-FOR 指令,但不能绑定 Key,只能在子节点上绑定唯一的 KEY。
- <template v-for="item in list">
- <div :key="item.id">...</div>
- </template>
vue3
键可以绑定到 Vue3 中的模板
- <template v-for="item in list" :key="item.id">
- <div>...</div>
- </template>
这就是主要区别所在 —— Vue2 Options API 与 Vue 3 Composition API。
选项 API 将我们的代码分为不同的属性:数据、计算属性、方法等。同时,组合API允许我们按函数而不是属性类型对代码进行分组。
对于窗体组件,假设我们只有两个数据属性:a 和 a。username password
Vue2 代码看起来像这样 – 我们只是在数据属性中折腾了两个值。
- export default {
- props: {
- title: String,
- },
- data() {
- return {
- username: "",
- password: "",
- };
- },
- };
在 Vue 3 中,我们必须通过使用一种新方法来投入更多的精力,其中所有组件初始化都应该进行。setup()
此外,为了让开发人员能够更好地控制什么是反应式的,我们可以直接访问 Vue 的反应性 API。
创建反应式数据涉及三个步骤:
从 vue 导入reactive
使用反应式方法声明我们的数据
让我们的方法返回反应式数据,以便我们的模板可以访问它setup
就代码而言,它看起来有点像这样。
- import { reactive } from "vue";
-
- export default {
- props: {
- title: String,
- },
- setup() {
- const state = reactive({
- username: "",
- password: "",
- });
-
- return { state };
- },
- };
然后,在我们的模板中,我们像和state.username state.password
Vue2 选项 API 有一个单独的方法部分。在其中,我们可以定义我们所有的方法并以我们想要的任何方式组织它们。
Vue 3 Composition API中的 setup 方法也处理方法。它的工作方式有点类似于声明数据——我们必须首先声明我们的方法,然后返回它,以便我们组件的其他部分可以访问它。
在 Vue2 中,我们可以直接从我们的组件选项中访问生命周期钩子。对于我们的示例,我们将等待mounted 事件。
现在使用 Vue 3 组合 API,几乎所有内容都在 setup() 方法中。这包括已安装的生命周期挂钩。
但是,默认情况下不包含生命周期钩子,因此我们必须导入onMounted在 Vue 3 中调用的方法。这看起来与之前导入响应式的方法相同。
然后,在我们的 setup 方法中,我们可以通过将 onMounted 方法传递给我们的函数来使用它。
让我们添加一个计算属性,将我们的用户名转换为小写字母。
为了在 Vue2 中实现这一点,我们向选项对象添加了一个计算字段。从这里,我们可以像这样定义我们的属性……
Vue 3 的设计允许开发人员导入他们使用的东西,并且在他们的项目中没有不必要的包。本质上,他们不希望开发人员必须包含他们从未使用过的东西,这在 Vue2 中正成为一个日益严重的问题。
因此,要在 Vue 3 中使用计算属性,我们首先必须将计算属性导入到我们的组件中。
然后,与我们之前创建响应式数据的方式类似,我们可以将一段响应式数据作为计算值
访问 props 带来了 Vue 2 和 Vue 3 之间的重要区别——this意味着完全不同的东西。
在 Vue2 中,this几乎总是引用组件,而不是特定的属性。虽然这在表面上使事情变得容易,但它使类型支持变得痛苦。
然而,我们可以很容易地访问道具——让我们添加一个简单的例子,比如title在挂载的钩子中打印出我们的道具:
但是在 Vue 3 中,我们不再使用this来访问 props、发出事件和获取属性。相反,该setup()方法采用两个参数:
props– 对组件道具的不可变访问
context– Vue 3 公开的选定属性(emit、slots、attrs)
使用 props 参数,上面的代码看起来像这样。
同样,在 Vue 2 中Emitting事件非常简单,但 Vue 3 让您可以更好地控制如何访问属性/方法。
假设在我们的例子中,当按下“提交”按钮时,我们想要向父组件发出登录事件。
Vue 2 代码只需要调用this.$emit并传入我们的有效负载对象。
然而,在 Vue 3 中,我们现在知道这this不再意味着同样的事情,所以我们必须以不同的方式来做。
幸运的是,上下文对象暴露emit给了我们同样的东西this.$emit
我们所要做的就是将context第二个参数添加到我们的设置方法中。我们将解构上下文对象以使我们的代码更简洁。
然后,我们只需调用 emit 来发送我们的事件。然后,就像以前一样,emit 方法接受两个参数:
我们的活动名称
与我们的事件一起传递的有效负载对象
在 Vue 3 中,你创建应用的方式发生了变化。Vue 应用程序现在使用新方法来创建应用程序实例。.createApp()
Vue 应用程序现在被视为根组件,因此您定义其数据选项的方式也发生了变化。
HTML 根元素尚未更改,因此在索引.html文件中,您仍将看到如下内容:
<div id="app"></div>
在 JavaScript 文件中,您需要了解一个重要的更改:您将不再用于创建新的应用程序实例,而是使用一个名为:new Vue()createApp()
- // Vue 3 syntax
-
- const app = Vue.createApp({
- // options object
- })
- app.mounth('#app') // Vue Instance - Root component
-
- // Vue 2 syntax
- const app = new Vue({
- // options object
- el: '#app'
- })
要在 Vue 3 中定义组件,请不再使用 。相反,您现在使用应用程序根组件,如下所示:Vue.component()
- /* Vue 3 syntax */
- const app = Vue.createApp({
- // options here
- })
-
- app.component('componenet-name', {
- // component code here
- })
-
-
- /* Vue 2 syntax*/
- Vue.component('component-name', {
- // component code here
- })
假设主应用实例现在被视为根组件,则无法再将数据属性指定为对象。相反,您需要将其定义为返回对象的函数,就像通常在组件中所做的那样。
- // Vue 3
- const app = Vue.createApp({
- // options object
- data(){
- return {
- message: 'hi there'
- }
- }
- })
- app.mounth('#app') // Vue Instance - Root component
-
- // Vue 2 syntax
- const app = new Vue({
- // options object
- el: '#app'
- data: {
- message: 'hi there'
- }
- })
在 Vue 2 中,如果在同一元素上使用了两个指令,则 v-for 指令将优先于 v-if。但是在 Vue 3 中,v-if 总是优先。
但是,使用这两个指令并不是一个好主意。请务必访问此处的文档以了解更多信息。
与该属性类似,现在在 Vue 3 中,还有一个属性,组件可以使用该属性来声明它可以向父组件发出的事件。propsemits
我强烈建议使用此属性,以避免在需要重新发出本机事件(如单击事件)的组件中两次发出事件。
以下是官方文档中的示例:
- <template>
- <div>
- <p>{{ text }}</p>
- <button v-on:click="$emit('accepted')">OK</button>
- </div>
- </template>
- <script>
- export default {
- props: ['text'],
- emits: ['accepted']
- }
- </script>
emits 属性也可以接受对象。
我现在还不会深入探讨这个问题,但我保证迟早会在专门的视频系列中解决每个功能/变化。
随着 Vue.js 的新版本发布,我们也有了新版本的 Vue Router。新版本 v4.x 有一些重大更改,如果你想将项目迁移到新的 Vue 版本,你需要考虑这些更改。
两个重大更改特别值得一提,因为它们位于 Vue 路由器应用程序的基础。稍后需要了解它们才能迁移应用程序。
此处提供了更改的完整列表。
让我们深入看看这两个变化。
要创建新的 Vue 路由器实例,请不再使用 VueRuter 函数构造函数。
以下是 Vue Router v.3x 文档,因此您可以进行比较。
代码由以下原因更改:
- // 3. Create the router instance and pass the `routes` option
- // You can pass in additional options here, but let's
- // keep it simple for now.
- const router = new VueRouter({
- routes // short for `routes: routes`
- })
-
- // 4. Create and mount the root instance.
- // Make sure to inject the router with the router option to make the
- // whole app router-aware.
- const app = new Vue({
- router
- }).$mount('#app')
对此:
- // 3. Create the router instance and pass the `routes` option
- // You can pass in additional options here, but let's
- // keep it simple for now.
- const router = VueRouter.createRouter({
- // 4. Provide the history implementation to use. We are using the hash history for simplicity here.
- history: VueRouter.createWebHashHistory(), // <-- this is a new property and it is mandatory!
- routes, // short for `routes: routes`
- })
-
- // 5. Create and mount the root instance.
- const app = Vue.createApp({})
- // Make sure to _use_ the router instance to make the
- // whole app router-aware.
- app.use(router)
-
- app.mount('#app')
在上面的代码中,要创建新的 Vue 路由器实例,您现在必须使用 VueRouter 对象并调用该方法。createRouter()
此外,新的历史记录属性是必需的 – 。您必须定义它,否则将收到控制台错误。history: VueRouter.createWebHashHistory()
接下来,您将使用该方法创建 Vue 实例,并使用变量来调用该方法。您将您在上一步中创建的路由器实例传递到该位置。createApp()app.use()
最后,您可以使用 在应用程序实例上挂载根 DOM 元素。app.mount('#app')
你可以阅读 Vue 路由器 v4.x 文档了解更多详情。
main.js
- // create and mount the Vue instance
-
- const app = new Vue({
- router
- }).$mount('#app')
-
对此:
- // create and mount the Vue instance
-
- const app = Vue.createApp({
- router
- })
- app.mount('#app')
Vue 路由器的实例化方式已更改
它从这个变化:
- // create the router instance
- const router = new VueRouter({
- routes
- })
-
对此:
- // create the router instance
- const router = VueRouter.createRouter({
- // Provide the history implementation to use. We are using the hash history for simplicity here.
- history: VueRouter.createWebHashHistory(),
- routes, // short for `routes: routes`
- })
上面的代码处理两个主要更改:已替换为 ,新选项现在将替换 。new VueRouter()VueRouter.createRouter()historymode
请访问 Vue 路由器 4 的文档以了解更多信息。
最后,让我们的应用程序知道我们正在使用 Vue 路由器。如果我们在 Vue 应用程序中注入了路由器实例,现在我们需要指示它使用 Vue 路由器,使用该方法执行此操作,并将路由器实例传递给它。.use()
由此更改:
- // create and mount the Vue instance
-
- const app = Vue.createApp({
- router
- })
- app.mount('#app')
对此:
- // create and mount the Vue instance
-
- const app = Vue.createApp({})
- app.use(router)
- app.mount('#app')