当前位置: 首页 > news >正文

vue2 跟 vue3 对比总结

一、 响应式原理差异

1、核心实现

// Vue2 使用 Object.defineProperty 来实现响应式,这是 ES5 的特性
function defineReactive(obj, key, val) {const dep = new Dep();Object.defineProperty(obj, key, {enumerable: true,configurable: true,get() {// 依赖收集if (Dep.target) {dep.depend();}return val;},set(newVal) {if (newVal === val) return;val = newVal;// 通知更新dep.notify();}});
}// Vue3 使用`Proxy`和`Reflect`来实现响应式,这是 ES6 的特性
function reactive(obj) {return new Proxy(obj, {get(target, key, receiver) {const result = Reflect.get(target, key, receiver);track(target, key); // 依赖收集return isObject(result) ? reactive(result) : result;},set(target, key, value, receiver) {const oldValue = target[key];const result = Reflect.set(target, key, value, receiver);if (oldValue !== value) {trigger(target, key); // 触发更新}return result;},deleteProperty(target, key) {const result = Reflect.deleteProperty(target, key);trigger(target, key); // 触发更新return result;}});
}

2、vue2 响应式原理

基于 Object.defineProperty 实现,存在一些限制,如无法检测数组索引变化、对数组的处理需要特殊方法(如 pushpopsplice),无法检测对象属性的添加或删除

3、vue3 响应式原理

基于 ES6 的 Proxy和Reflect 实现

可以检测到数组索引变化

可以检测到对象属性的添加或删除

性能更好,无需递归遍历对象所有属性

支持 Map、Set、WeakMap 和 WeakSet

二、 生命周期钩子变化

1、钩子名称调整

// Vue2
export default {beforeCreate() {},created() {},beforeMount() {},mounted() {},beforeUpdate() {},updated() {},beforeDestroy() {},destroyed() {}
}// Vue3
export default {setup() {}, // 替代beforeCreate和createdonBeforeMount() {},onMounted() {},onBeforeUpdate() {},onUpdated() {},onBeforeUnmount() {}, // 替代beforeDestroyonUnmounted() {}      // 替代destroyed
}

三、 模板语法变化

1、v-model 变化

// Vue 2 中 v-model 本质是 value prop 和 input 事件
<ChildComponent v-model="pageTitle" />
<!-- 等价于 -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />// Vue 3 中 v-model 改为 modelValue prop 和 update:modelValue 事件
<ChildComponent v-model="pageTitle" />
<!-- 等价于 -->
<ChildComponent:modelValue="pageTitle"@update:modelValue="pageTitle = $event"
/>

2、支持多个 v-model

<!-- Vue2 -->
<input v-model="message"><!-- Vue3 -->
<MyComponent v-model:value="message" v-model:title="title" />

3、支持多个事件处理器

<!-- Vue2 -->
<button @click="handleClick">点击</button><!-- Vue3 - 支持多个事件处理器 -->
<button @click="handleClick1" @click="handleClick2">点击</button>

4、 片段支持

<!-- Vue2 - 需要1个根节点 -->
<template><div><header>...</header><main>...</main><footer>...</footer></div>
</template><!-- Vue3 - 支持多根节点 -->
<template><header>...</header><main>...</main><footer>...</footer>
</template>

5、允许在 template 上使用 key

<!-- Vue 2 -->
<li v-for="item in list" :key="item.id">{{ item.text }}
</li><!-- Vue 3 -->
<li v-for="item in list" :key="item.id">{{ item.text }}
</li><!-- 但 Vue 3 允许在 template 上使用 key -->
<template v-for="item in list" :key="item.id"><li>{{ item.text }}</li>
</template>

四、异步组件的定义

// vue2
new Vue({components: {AsyncComponent: () => import('./AsyncComponent.vue')}
})// vue3
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent(() => import('./AsyncComponent.vue'))

五、 渲染函数的变化

// vue2
export default {render(h) {return h('div', {attrs: {id: 'foo'},on: {click: this.onClick}}, 'hello')}
}// vue3
import { h } from 'vue'
export default {render() {return h('div', {id: 'foo',onClick: this.onClick}, 'hello')}
}

六、过渡类名变化

Vue 2 过渡类名:

 .v-enter         进入过渡的开始状态

 .v-enter-active  进入过渡的激活状态

 .v-enter-to      进入过渡的结束状态

 .v-leave         离开过渡的开始状态

 .v-leave-active  离开过渡的激活状态

 .v-leave-to      离开过渡的结束状态

Vue 3 过渡类名:

 .v-enter-from    进入过渡的开始状态

 .v-enter-active  进入过渡的激活状态

 .v-enter-to      进入过渡的结束状态

 .v-leave-from    离开过渡的开始状态

 .v-leave-active  离开过渡的激活状态

 .v-leave-to      离开过渡的结束状态

七、 组件通信

// Vue2
export default {props: ['title'],methods: {handleClick() {this.$emit('update', newValue)}}
}// Vue3
import { defineProps, defineEmits } from 'vue'const props = defineProps(['title'])
const emit = defineEmits(['update'])const handleClick = () => {emit('update', newValue)
}

八、全局API变化

1、应用实例创建

// Vue2
import Vue from 'vue'
import App from './App.vue'new Vue({render: h => h(App)
}).$mount('#app')// Vue3
import { createApp } from 'vue'
import App from './App.vue'createApp(App).mount('#app')

2、全局配置

// Vue2
Vue.config.productionTip = false
Vue.use(VueRouter)
Vue.component('MyComponent', MyComponent)// Vue3
import { createApp } from 'vue'
import App from './App.vue'const app = createApp(App)
app.use(VueRouter)
app.component('MyComponent', MyComponent)
app.mount('#app')

九、 状态管理

1、Vuex (Vue2/Vue3)

// Vuex 4 示例
import { createStore } from 'vuex'export default createStore({state: {count: 0,user: null},mutations: {SET_COUNT(state, count) {state.count = count},SET_USER(state, user) {state.user = user}},actions: {async fetchUser({ commit }) {const user = await api.getUser()commit('SET_USER', user)}},getters: {doubleCount: state => state.count * 2}
})// 在组件中使用
export default {computed: {...mapState(['count', 'user']),...mapGetters(['doubleCount'])},methods: {...mapActions(['fetchUser']),increment() {this.$store.commit('SET_COUNT', this.count + 1)}}
}

2、Pinia (Vue3推荐)

// Pinia 示例
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', {state: () => ({count: 0,user: null}),getters: {doubleCount: (state) => state.count * 2},actions: {increment() {this.count++},async fetchUser() {this.user = await api.getUser()}}
})// 在组件中使用
import { useCounterStore } from '@/stores/counter'export default {setup() {const store = useCounterStore()return {count: store.count,doubleCount: store.doubleCount,increment: store.increment,fetchUser: store.fetchUser}}
}

3、vuex和pinia主要区别

特性VuexPinia
Mutations必须通过mutations修改state可以直接在actions中修改state,或直接修改
TypeScript支持需要额外配置,支持度一般一流的TypeScript支持,完全类型安全
模块化需要namespaced模块,较复杂天然模块化,每个store都是独立模块
代码组织需要区分mutations/actions更简洁,减少模板代码
Composition API需要额外适配专为Composition API设计
包大小较大(约4kB)更轻量(约1kB)
开发体验需要遵循严格模式更灵活,减少约束
DevTools支持完善同样完善

十、 构建工具对比

1、Webpack (Vue2常用)

// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/main.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'bundle.js'},module: {rules: [{test: /\.vue$/,loader: 'vue-loader'},{test: /\.js$/,loader: 'babel-loader'}]},plugins: [new HtmlWebpackPlugin({template: './public/index.html'})],devServer: {hot: true,port: 8080}
}

2、Vite (Vue3推荐)

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'export default defineConfig({plugins: [vue()],server: {port: 3000,hot: true},build: {rollupOptions: {output: {manualChunks: {vendor: ['vue', 'vue-router']}}}}
})

3、webpack和vite主要区别

1、核心架构差异

webpack

基于打包器架构:在开发环境下需要先打包所有代码才能启动开发服务器

使用JavaScript作为通用语言:所有文件都需要经过转换和打包

基于插件系统:功能扩展依赖于庞大的插件生态系统

vite

基于原生ES模块:利用浏览器原生支持ES模块的能力

按需编译:只编译当前页面需要的模块,无需打包整个应用

分为开发和生产环境:开发环境使用ES模块,生产环境使用Rollup打包

2、开发服务器启动速度

webpack:随着项目规模增大,启动时间线性增长(可能需要数十秒甚至几分钟)

vte:启动时间几乎与项目规模无关(通常只需几毫秒到几秒)

3、热更新速度(HMR)

webpack:需要重新构建修改的模块及其依赖关系

vite:仅需编译单个文件,HMR更新速度极快(通常<50ms)

4、构建速度

webpack:需要完整打包所有资源

vite:生产环境使用Rollup进行构建,通常比Webpack更快

5、配置复杂度

webpack

配置复杂:需要详细配置loader、plugin、优化选项等

学习曲线陡峭:需要理解各种概念如chunk分割、tree shaking等

灵活性高:几乎可以通过配置实现任何构建需求

vite

开箱即用:默认支持TypeScript、JSX、CSS等,无需复杂配置

配置简单:大多数项目只需极简配置

约定优于配置:提供合理的默认值,减少配置负担

特性

WebpackVite
开发服务器启动慢(需完整打包)极快(按需编译)
热更新较慢(重建依赖图)极快(单个文件编译)
配置复杂度
TypeScript支持需要ts-loader原生支持
CSS处理需要css-loader等原生支持
框架支持通用(需配置)Vue/React优先
生产构建Webpack自身使用Rollup
生态插件极其丰富正在增长

十一、 API风格对比

1、Options API (Vue2/Vue3)

代码基于选项的组织方式:将代码按照功能类型分组到不同的选项中(data、methods、computed等)

关注点分离:相同功能的代码可能分散在不同的选项中,大型组件难以维护和理解

// Options API 示例
export default {name: 'UserList',props: {users: {type: Array,default: () => []}},data() {return {searchQuery: '',selectedUser: null,loading: false}},computed: {filteredUsers() {return this.users.filter(user => user.name.toLowerCase().includes(this.searchQuery.toLowerCase()))}},watch: {searchQuery(newVal, oldVal) {console.log('搜索词变化:', oldVal, '->', newVal)}},methods: {async fetchUsers() {this.loading = truetry {const users = await api.getUsers()this.$emit('update:users', users)} catch (error) {console.error('获取用户失败:', error)} finally {this.loading = false}},selectUser(user) {this.selectedUser = userthis.$emit('user-selected', user)}},mounted() {this.fetchUsers()}
}

2、Composition API (Vue3)

基于功能的组织方式:将相关功能的代码组织在一起

逻辑关注点集中:相同功能的代码集中在一个地方

// Composition API 示例
import { ref, computed, watch, onMounted } from 'vue'export default {name: 'UserList',props: {users: {type: Array,default: () => []}},emits: ['update:users', 'user-selected'],setup(props, { emit }) {// 响应式状态const searchQuery = ref('')const selectedUser = ref(null)const loading = ref(false)// 计算属性const filteredUsers = computed(() => {return props.users.filter(user => user.name.toLowerCase().includes(searchQuery.value.toLowerCase()))})// 监听器watch(searchQuery, (newVal, oldVal) => {console.log('搜索词变化:', oldVal, '->', newVal)})// 方法const fetchUsers = async () => {loading.value = truetry {const users = await api.getUsers()emit('update:users', users)} catch (error) {console.error('获取用户失败:', error)} finally {loading.value = false}}const selectUser = (user) => {selectedUser.value = useremit('user-selected', user)}// 生命周期onMounted(() => {fetchUsers()})return {searchQuery,selectedUser,loading,filteredUsers,fetchUsers,selectUser}}
}

3、<script setup> 语法糖

Vue 3.2 引入了更简洁的 <script setup> 语法,直接将setup加到script标签

<script setup>
import { ref, computed, onMounted } from 'vue'const count = ref(0)
const message = ref('Hello')const doubleCount = computed(() => count.value * 2)function increment() {count.value++
}onMounted(() => {console.log('Component mounted')
})
</script>

4、Options API 和Composition API主要区别

特性Options APIComposition API
代码组织按选项类型分组按逻辑功能分组
逻辑复用Mixins(有命名冲突问题)组合函数(更好的封装和复用)
TypeScript支持需要额外努力一流的TypeScript支持
学习曲线相对平缓,概念简单需要理解响应式API概念
灵活性相对固定极高的灵活性
代码可读性简单组件中更清晰复杂组件中更清晰
this使用大量使用this几乎不需要使用this
规模适应性适合中小型组件特别适合大型复杂组件

十二、 路由系统对比

1、Vue Router 3 (Vue2)

// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'Vue.use(VueRouter)const routes = [{path: '/',name: 'Home',component: Home},{path: '/about',name: 'About',component: () => import('../views/About.vue')}
]const router = new VueRouter({mode: 'history',base: process.env.BASE_URL,routes
})export default router// 在组件中使用
export default {methods: {goToAbout() {this.$router.push('/about')}},computed: {currentRoute() {return this.$route.name}}
}

4、Vue Router 4 (Vue3)

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'const routes = [{path: '/',name: 'Home',component: Home},{path: '/about',name: 'About',component: () => import('../views/About.vue')}
]const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes
})export default router// 在Composition API中使用
import { useRouter, useRoute } from 'vue-router'export default {setup() {const router = useRouter()const route = useRoute()const goToAbout = () => {router.push('/about')}const currentRoute = computed(() => route.name)return {goToAbout,currentRoute}}
}

十三、Vue2 Mixins与Vue3 Hooks

1、Vue 2 Mixins

代码混入机制:将mixin对象的内容合并到组件中

选项式合并:相同选项(data、methods等)会进行特定策略的合并

命名冲突风险:多个mixin之间或与组件之间容易产生命名冲突

关系不清晰:难以追踪属性/方法的来源

// mixin.js
export const userMixin = {data() {return {users: [],loading: false}},methods: {async fetchUsers() {this.loading = truethis.users = await fetch('/api/users')this.loading = false}},mounted() {this.fetchUsers()}
}// 组件中使用
import { userMixin } from './mixins/userMixin'export default {mixins: [userMixin],data() {return {// 可能与mixin中的data产生冲突loading: true // 命名冲突!}}
}

2、Vue3 Hooks 

函数式组合:通过函数调用明确地组合逻辑

明确的数据来源:每个hook返回的数据来源清晰

命名空间隔离:hook内部的变量名不会与组件或其他hook冲突

按需使用:可以选择性使用hook返回的内容

// useUsers.js
import { ref, onMounted } from 'vue'export function useUsers() {const users = ref([])const loading = ref(false)const fetchUsers = async () => {loading.value = trueusers.value = await fetch('/api/users')loading.value = false}onMounted(fetchUsers)return {users,loading,fetchUsers}
}// 组件中使用
import { useUsers } from '@/composables/useUsers'export default {setup() {const { users, loading, fetchUsers } = useUsers()// 可以重命名以避免冲突const { users: adminUsers } = useAdminUsers()return {users,loading,fetchUsers}}
}

3、Mixins和hook主要区别

特性Vue 2 MixinsVue 3 Composition Hooks
命名冲突容易发生,难以调试不会发生,可以重命名
代码来源不透明,难以追踪明确,易于追踪
类型支持TypeScript支持有限优秀的TypeScript支持
逻辑复用选项式混合,不够灵活函数式组合,非常灵活
代码组织逻辑分散在不同选项中相关逻辑集中在一起
性能影响所有选项都会被合并按需使用,没有额外合并开销
可调试性困难,难以追踪问题来源容易,清晰的调用栈
参数传递难以向mixin传递参数可以接受参数,高度可配置

十四、Teleport组件

Teleport 是 Vue3 提供的一个内置组件,允许我们将组件模板的一部分 "传送" 到 DOM 树的其他位置,而不受父组件 CSS 样式、定位等影响。

to 属性 (必需):指定目标容器,可以是 CSS 选择器或 DOM 元素

禁用功能:可以使用 :disabled 属性动态控制是否启用传送

多个 Teleport 到同一目标:多个 Teleport 可以挂载到同一个目标元素,按顺序追加

<!-- <div class="modal"> 会被渲染到 <body> 元素的末尾,而不是在其父组件的 DOM 位置。--><template><div class="app"><h1>主应用</h1><!-- 将内容传送到 body 元素下 --><Teleport to="body"><div class="modal">这是一个模态框</div></Teleport></div>
</template>

十五、 TypeScript支持

1、 类型推断

// Vue3 - 更好的TypeScript支持
import { ref, computed } from 'vue'interface User {id: numbername: string
}export default {setup() {const user = ref<User>({ id: 1, name: 'John' })const userName = computed(() => user.value.name)return { user, userName }}
}

2、类型安全的props和emits

// Vue3
interface Props {title: stringcount?: number
}interface Emits {(e: 'update', value: string): void(e: 'delete'): void
}const props = defineProps<Props>()
const emit = defineEmits<Emits>()

十六、总结

特性Vue2Vue3
API 设计Options APIComposition API
状态管理VuexPinia
构建工具WebpackVite
响应式系统Object.definePropertyProxy
TypeScript 支持有限完全支持
性能表现一般提升 30-50%
包体积较大更小
开发体验基础优秀
学习成本中等
维护性一般更好

http://www.xdnf.cn/news/1432477.html

相关文章:

  • 面向机器人系统的虚实迁移强化学习:从仿真训练到真实落地的技术突破
  • 重磅!PS2021 和企业微信 5.0 可直接运行,统信兼容引擎 V3.3.2 全面升级!
  • 提示词工程实战指南:5大技巧大幅提升LLM输出质量
  • 网络安全法合规视角下的安全运维体系建设:关键控制点与实施细节深度解析
  • 【论文阅读】DeepSeek-LV2:用于高级多模态理解的专家混合视觉语言模型
  • 【js】Promise.try VS try-catch
  • Spring Boot数据校验validation实战:写少一半代码,还更优雅!
  • 在线宠物用品|基于vue的在线宠物用品交易网站(源码+数据库+文档)
  • 硬件开发_基于物联网的自动售卖机系统
  • 联邦学习论文分享:GPT-FL: Generative Pre-Trained Model-AssistedFederated Learning
  • Apache 的安装及基本使用
  • MMORPG 游戏战斗系统架构
  • MATLAB矩阵及其运算(一)变量与常量
  • Python 中将 JSON 字符串转为对象的几种方法对比
  • 软件测试面试题【内附超详细面试宝典】
  • 【本地知识库问答系统】MaxKB搭建本地知识库问答系统
  • 低代码开发平台有哪些,中国十大低代码开发平台排名
  • 从零开始的云计算生活——第五十六天,临深履薄,kubernetes模块之etcd备份恢复和集群升级指南
  • Ruoyi-vue-plus-5.x第三篇Redis缓存与分布式技术:3.2 缓存注解与使用
  • 第2章:用户界面与基本监控
  • Ansible 循环、过滤器与判断逻辑
  • 小学一到六年级语文/英语/数学作业出题布置网站源码 支持生成PDF和打印
  • 基金交易量预测比赛_数据分析
  • MySQL 8.0 窗口函数详解:让数据分析更简单高效
  • 大数据毕业设计选题推荐-基于大数据的大学生就业因素数据分析系统-Spark-Hadoop-Bigdata
  • 华为OD最新机试真题-中庸行者-OD统一考试(C卷)
  • 【Unity Shader学习笔记】(二)图形显示系统
  • 从Web2到Web3:一场重塑数字未来的“静默革命”
  • mac 本地安装maven环境
  • LLM面试50问:NLP/RAG/部署/对齐/安全/多模态全覆盖