🌟 Vue2与Vue3 的区别


🔮 双向数据绑定:Object.defineProperty vs Proxy

Vue2通过Object.defineProperty实现了经典的双向数据绑定机制💡:

// Vue2
const vm = new Vue({
  data: {
    message: 'Hello Vue2!'
  }
});

console.log(vm.$data.message); // 输出 "Hello Vue2!"
vm.message = 'Hello Vue3!';

而Vue3采用Proxy实现更为高效的数据代理🌟:

// Vue3 使用 composition API
import { reactive } from 'vue';

const state = reactive({ message: 'Hello Vue3!' });

console.log(state.message); // 输出 "Hello Vue3!"
state.message = 'Hello Future!';

Proxy的优势在于能够一次性代理整个对象,无需遍历属性,且能更好地处理数组的变化,无需手动调用 $set 方法来确保响应式 TencentWeibo;


🎨 组件化:Options API vs Composition API

Vue2中的组件结构依赖于Options API

// Vue2
export default {
  data() {
    return {
      count: 0,
    };
  },
  computed: {
    doubleCount() {
      return this.count * 2;
    }
  },
  methods: {
    increment() {
      this.count++;
    }
  },
};

Vue3引入了Composition API,让逻辑组织更灵活,便于复用和单元测试:

// Vue3
import { ref, computed } from 'vue';

export default {
  setup() {
    const count = ref(0);
    
    const doubleCount = computed(() => count.value * 2);

    function increment() {
      count.value++;
    }

    return {
      count,
      doubleCount,
      increment
    };
  }
};

💡 生命周期钩子函数调整

Vue2中的生命周期钩子函数在Vue3中进行了精简和重组:

// Vue2
export default {
  beforeCreate() {},
  created() {},
  beforeMount() {},
  mounted() {},
  // ...
};

// Vue3
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated } from 'vue';

export default {
  setup() {
    onBeforeMount(() => {});
    onMounted(() => {});
    onBeforeUpdate(() => {});
    onUpdated(() => {});
  }
};

🌲 Tree Shaking 和渲染优化

Vue3带来了更好的Tree Shaking能力,允许构建工具丢弃未使用的代码片段,减小打包体积💪。同时,Vue3内部的编译器和运行时经过重构,组件渲染算法得到优化,提升了应用整体性能💨。


🎯 Fragments

在Vue2中,每个组件必须有一个单一的根元素。而在Vue3中,引入了Fragments特性,允许一个组件返回多个顶级元素,无需包裹层元素,简化模板结构🎯:

<!-- Vue2 -->
<template>
  <div>
    <h1>Title</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
  </div>
</template>

<!-- Vue3 -->
<template>
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

🚀 Teleport

Vue3新增的Teleport指令,允许我们将组件的内容渲染到DOM树的任何位置,常用于模态框、提示信息等需要跳出当前上下文渲染的情况🌏:

<!-- Vue3 -->
<template>
  <teleport to="#modal-container">
    <modal v-if="showModal">This is a modal!</modal>
  </teleport>
</template>

⏳ Suspense

Vue3引入了Suspense组件,用来优雅地处理异步组件的加载和错误状态。当异步组件还未加载完成时,Suspense组件内的fallback内容将会被展示,提升用户体验⏰:

<template>
  <suspense>
    <template #default>
      <async-component />
    </template>
    <template #fallback>
      <loading-spinner /> <!-- 加载中... -->
    </template>
  </suspense>
</template>

📊 性能优化与编译器改进

Vue3内部的编译器和运行时进行了大量优化,包括:

  • 编译优化:Vue3采用了新的编译器@vue/compiler-sfc,使得模板编译更快、更准确;
  • 运行时优化:通过FragmentTeleport等减少不必要的 DOM 操作,提高渲染效率;
  • 基于Proxy的响应系统:相比Vue2的Object.defineProperty,Vue3的响应系统性能更高,尤其是针对大型对象和数组的监听;
  • v-for的key改进:Vue3对于 v-for 的 key 值有更严格的校验,帮助避免不必要的重渲染问题;
  • Fragment、Teleport等特性:这些特性降低了额外 DOM 元素的创建,提高了渲染性能和DOM结构清晰度。

🌈 TypeScript 更完善的集成

Vue3全面支持TypeScript,提供了官方的声明文件和类型提示,不仅使开发者能够写出类型安全的代码,还增强了IDE自动补全和错误检测的能力💪📚。


🛠 Vuex 更新:Pinia 的兴起

Vue3并未直接在核心库中提供Vuex的新版本,而是推荐使用社区驱动的Pinia作为状态管理库。Pinia借鉴了Vue3的Composition API设计,使得状态管理和组件内逻辑更加统一和简洁便利🛠️:

// 安装Pinia
import { createApp } from 'vue';
import { createPinia } from 'pinia';

const app = createApp(App);
const pinia = createPinia();

app.use(pinia);

// 创建store
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++;
    },
  },
});

// 在组件中使用
import { useCounterStore } from './stores/counter';

export default {
  setup() {
    const counter = useCounterStore();
    
    function handleClick() {
      counter.increment();
    }

    return {
      handleClick
    };
  }
};

🎮 渲染函数 API 的变化

Vue3在渲染函数上也有显著变化,采用了新的setupRenderFunctions方法替代Vue2的render函数。它结合了setup函数,允许我们在同一个地方定义props、emit、context和渲染逻辑🎮:

import { h, defineComponent } from 'vue';

export default defineComponent({
  setup(props, context) {
    // 访问props和emit
    const { foo } = props;
    const { emit } = context;

    // 返回渲染函数
    return () => h('div', {}, `Prop value: ${foo}`);
  },
  props: {
    foo: String
  }
});

🌐 Vue Router 更新

Vue Router 4.x 针对Vue3进行了适配和优化,使用新的Composition API风格,路由守卫和导航钩子的使用方式也有所改变🌐:

import { createRouter, createWebHistory } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
  ],
});

// 在组件中使用
export default {
  setup() {
    const route = useRoute();
    const router = useRouter();

    // 声明导航守卫
    router.beforeEach((to, from, next) => {
      // ...
    });

    return {
      route,
      router
    };
  }
};

🤖 Web Components 支持

Vue3现在提供了更好的原生Web Components兼容性,可以通过defineCustomElement方法将Vue组件转换为自定义元素,以便与非Vue项目或不同的前端框架无缝集成🤖:

import { defineComponent } from 'vue';
import { defineCustomElement } from 'vue/dist/vue.esm-bundler.js';

const MyVueComponent = defineComponent({
  template: '<div>Hello from Vue Component!</div>'
});

customElements.define('my-vue-component', defineCustomElement(MyVueComponent));

🍃 自定义指令的变更

Vue2 中,我们使用 Vue.directive 注册全局自定义指令,而在 Vue3 中,全局指令注册移到了 app.directive 上,语法略有不同,增加了 setup 函数以利用 Composition API:

// Vue2
Vue.directive('my-directive', {
  bind(el, binding, vnode) {
    el.style.color = binding.value;
  }
});

// Vue3
const app = createApp(App);
app.directive('my-directive', {
  beforeMount(el, binding) {
    el.style.color = binding.value;
  },
  updated(el, binding) {
    el.style.color = binding.value;
  }
});

🎭 模板引用的改动

Vue2 中我们通过 ref 属性并在父组件中通过 $refs 访问 DOM 元素。Vue3 引入了 .value 来访问 ref 对象的底层 DOM 节点或组件实例:

<!-- Vue2 -->
<input ref="inputRef">

<script>
export default {
  mounted() {
    console.log(this.$refs.inputRef);
  }
};
</script>

<!-- Vue3 Composition API -->
<input ref="inputRef">

<script setup>
import { ref } from 'vue';

const inputRef = ref(null);

onMounted(() => {
  console.log(inputRef.value);
});
</script>

🎨 动画过渡系统的增强

Vue3 过渡系统仍然支持 transition 组件和相应的 CSS 类名,但新增了 <Transition><TransitionGroup> 组件,可以更好地与 Composition API 结合使用:

<!-- Vue2 -->
<transition name="fade">
  <div v-if="show">Fade in/out</div>
</transition>

<!-- Vue3 Composition API -->
<Transition name="fade">
  <div v-if="show">Fade in/out</div>
</Transition>

📡 Provide / Inject 的变化

Vue3 提供了一个新的 provide/inject 实现,可以与 Composition API 更好地配合,不再局限于全局作用域:

// Vue2
Vue.prototype.$theme = 'dark';

// 子组件
this.$parent.$theme; // 'dark'

// Vue3 Composition API
setup() {
  const theme = inject('theme', 'light');

  provide('theme', 'dark');

  return { theme };
}

🔍 DevTools 更新

Vue DevTools 工具针对 Vue3 进行了全面升级,提供了更友好的界面和更详细的组件状态追踪功能,极大提高了调试效率和开发体验🔍:


💼 打包工具及优化

Vue CLI 的更新

Vue2 主要搭配的是 Vue CLI 2 或 Vue CLI 3,而随着 Vue3 的发布,Vue CLI 也升级到了 Vue CLI 4 及更高版本,它集成了对 Vue3 的开箱即用支持,并且整合了更多现代前端构建工具链的特点,如 Webpack 5(后续版本)以及 Tree Shaking 等优化技术。

Vue CLI 4 及以后版本提供的 @vue/cli-service 包含了对 Vue3 项目的默认配置,开发者无需手动配置就能快速搭建项目并享受到最新的构建和打包优势。

Rollup 与 Vite 的引入

Vue3 同时推荐使用 Vite 作为新一代的开发工具,Vite 使用了 Rollup 作为其打包器,相比于传统的 Webpack,Vite 在开发环境提供了更快的热更新速度和更轻量级的启动时间。Vite 利用 ES 模块原生加载能力,在开发阶段直接基于源码进行按需编译,大大提升了开发效率。

Tree Shaking 加强

Vue3 引入了更细粒度的打包策略,使得 Tree Shaking 更加有效。尤其是在使用 Vue3 的 Composition API 时,由于函数式的模块化设计,更容易被打包工具识别并移除未使用的代码片段,从而减小生产环境下的 JavaScript 包体积。

Scope Hoisting 优化

Webpack 和 Rollup 都支持 Scope Hoisting 技术来优化产出的 bundle 文件,通过此技术,Vue3 项目的多个模块会被合并到一个闭包中,减少函数声明和变量提升带来的开销,进而提高运行时性能。

压缩与分包策略

Vue CLI 和 Vite 都支持各种压缩工具(如 TerserWebpackPlugin 或者 esbuild)对最终生成的代码进行压缩,同时允许开发者自定义 chunk 分割策略,以便实现动态加载和延迟加载,进一步优化首屏加载速度。


04-18 16:28