Vue 3 简介Vue 3 是一个流行的开源JavaScript框架用于构建用户界面和单页面应用。它带来了许多新特性和改进包括更好的性能、更小的打包大小、更好的TypeScript支持、全新的组合式 API以及一些新的内置组件。1. Vue 3 的新特性Vue 3引入了许多新特性包括组合式API这是Vue 3最重要的新特性之一它允许更灵活、更逻辑化地组织代码。更好的性能Vue 3的虚拟DOM重写提供了更快的挂载、修补和渲染速度。更小的打包大小由于新的架构和树摇技术Vue 3的打包大小比Vue 2小。更好的TypeScript支持Vue 3在内部使用了TypeScript因此它为开发者提供了更好的TypeScript支持。2. 与 Vue 2 的区别Vue 3与Vue 2的主要区别包括构建Vue 3使用monorepo架构更容易管理和维护。APIVue 3引入了新的组合式API它提供了更灵活的代码组织方式。性能Vue 3提供了更好的性能包括更快的渲染速度和更小的打包大小。TypeScriptVue 3提供了更好的TypeScript支持。3. 全新的核心架构Vue 3的核心架构进行了全面的重写和优化以提高性能和灵活性。此外Vue 3还引入了许多新的API和组件以满足现代web开发的需求。基础1. 创建 Vue 3 项目首先我们需要通过Vite创建一个新的Vue 3项目。你可以通过下面的命令安装Vitepnpm create vite然后你可以通过下面的命令创建一个新的Vue 3项目pnpm create vite my-vue-app --template vue-ts2. 应用和组件编写在Vue 3中我们可以使用新的组合式API创建和管理组件。下面是一个简单的Vue 3组件示例template div p{ { count }}/p button clickincrementIncrement/button /div /template script import { ref } from vue export default { setup() { const count ref(0) const increment () { count.value } return { count, increment } } } /script在这个示例中我们首先导入了ref函数然后在setup函数中使用ref创建了一个响应式值count。我们还定义了一个increment函数用于增加count的值。最后我们将count和increment返回给模板以便在模板中使用它们。响应式系统1. 响应式原理Vue的响应式系统是其核心特性之一它使得数据变更能够自动更新到UI上。在Vue 3中这个系统基于JavaScript的Proxy对象重写提供了更好的性能和更多的功能。2. ref 和 reactiveVue 3提供了两个主要的函数来创建响应式数据ref和reactive。ref函数创建一个响应式引用。在模板中你可以直接使用响应式引用的值而在JavaScript代码中你需要通过.value属性来访问或修改它的值。import { ref } from vue const count ref(0) console.log(count.value) // 0 count.value // 1reactive函数创建一个响应式对象。你可以直接访问和修改它的属性。import { reactive } from vue const state reactive({ count: 0 }) console.log(state.count) // 0 state.count // 13. 实现机制区别ref和reactive的主要区别在于ref是为了让基本类型如数字和字符串可以变为响应式而reactive是为了让对象变为响应式。ref创建的响应式数据需要通过.value属性进行访问和修改而reactive创建的响应式对象可以直接访问和修改其属性。因此ref更适合于处理基本类型而reactive更适合于处理对象。组合式 API组合式API是Vue 3的重要新特性它提供了一种更灵活、更逻辑化的方式来组织和复用代码。1. setup 函数在Vue 3中你可以使用setup函数来使用组合式API。setup函数是组件的入口点在组件实例被创建和初始化之后但在渲染发生之前被调用。export default { setup() { // 在这里使用组合式 API } }2. 响应式编程你可以在setup函数中使用ref和reactive来创建响应式数据。import { ref, reactive } from vue export default { setup() { const count ref(0) const state reactive({ name: Vue }) return { count, state } } }3. 计算属性与监视你可以使用computed和watch来创建计算属性和监视响应式数据的变化。import { ref, computed, watch } from vue export default { setup() { const count ref(0) const doubled computed(() count.value * 2) watch(count, (newValue, oldValue) { console.log(count changed from ${oldValue} to ${newValue}) }) return { count, doubled } } }4. 生命周期钩子你可以在setup函数中使用生命周期钩子比如onMounted、onUpdated和onUnmounted。import { onMounted, onUpdated, onUnmounted } from vue export default { setup() { onMounted(() { console.log(component mounted) }) onUpdated(() { console.log(component updated) }) onUnmounted(() { console.log(component unmounted) }) } }5. 自定义 hooks你可以创建自定义的hooks来复用代码。一个自定义hook就是一个函数它可以使用其他的响应式数据和组合式API。import { ref, onMounted } from vue function useCounter() { const count ref(0) const increment () { count.value } onMounted(() { console.log(counter mounted) }) return { count, increment } } export default { setup() { const counter useCounter() return { counter } } }高级功能1. 浅层响应式在某些情况下你可能想要创建一个浅层的响应式对象这样其内部的属性不会被转化为响应式的。这可以通过shallowReactive函数来实现。import { shallowReactive } from vue const state shallowReactive({ count: 0 })2. 只读数据你可以使用readonly函数来创建一个只读的响应式对象。任何试图修改只读对象的操作都将在开发环境下引发一个错误。import { readonly } from vue const state readonly({ count: 0 })3. 自定义 Ref你可以使用customRef函数来创建一个自定义的响应式引用。这允许你控制和观察当引用的值发生变化时的行为。import { customRef } from vue const count customRef((track, trigger) { let value 0 return { get() { track() return value }, set(newValue) { value newValue trigger() } } })4. toRefs 和 toRef当我们从setup函数返回一个响应式对象时对象的属性将失去响应式。为了防止这种情况我们可以使用toRefs或toRef函数。import { reactive, toRefs } from vue export default { setup() { const state reactive({ count: 0 }) return { ...toRefs(state) } } }新组件1. Fragment在Vue 3中你可以在一个组件的模板中有多个根节点这被称为 Fragment。template divHello/div divWorld/div /template2. TeleportTeleport 组件允许你将子组件渲染到DOM的任何位置而不仅仅是它的父组件中。teleport to#modal divThis will be rendered wherever the #modal element is./div /teleport3. SuspenseSuspense 组件允许你等待一个或多个异步组件然后显示一些备用内容直到所有的异步组件都被解析。Suspense template #default AsyncComponent / /template template #fallback divLoading.../div /template /Suspense深入编译优化Vue 3在编译优化上做出了很大的提升。在编译过程中Vue 3对模板进行静态分析提取出不会改变的部分预编译为纯JavaScript这大大提高了运行时的渲染效率。下面详细介绍一下这些优化。静态节点提升在 Vue 3 中如果你的模板中有不会改变的部分例如template div h1Hello, world!/h1 pWelcome to Vue 3/p /div /template在编译时Hello, world! 和 Welcome to Vue 3 这些静态节点将会被提升避免了每次渲染时都需要重新创建。片段、模板并用在 Vue 3 中你可以在一个组件模板中有多个根节点这就是片段template headerHeader/header mainMain content/main footerFooter/footer /template在这个示例中我们有三个根节点这在 Vue 2 中是不允许的。但在 Vue 3 中这是完全正常的。动态编译Vue 3 的动态编译可以让我们在运行时编译模板字符串例如我们可以动态创建一个问候组件import { compile, h } from vue const template h1{ { greeting }} World!/h1 const render compile(template) export default { data() { return { greeting: Hello, } }, render }在这个例子中我们在运行时编译了模板字符串并将结果设置为组件的渲染函数。这种技术在需要动态生成模板的场景中非常有用比如在一个 CMS 中渲染用户提供的模板。深入组件化Vue 3在组件化方面也有很多进步下面详细介绍一下。动态组件Vue 3支持使用component标签来动态加载组件组件可以是一个组件选项对象也可以是一个组件的名字。这个特性在根据不同的状态显示不同组件时非常有用。component :iscurrentComponent/component异步组件Vue 3 支持异步组件你可以使用defineAsyncComponent方法来定义一个异步组件该方法接收一个返回 Promise 的工厂函数Promise 需要解析为一个组件。import { defineAsyncComponent } from vue const AsyncComponent defineAsyncComponent(() import(./components/AsyncComponent.vue) )高阶组件高阶组件Higher-Order Component简称 HOC是一种设计模式它是接收一个组件并返回一个新组件的函数。在 Vue 3 中你可以使用组合式 API 来更容易地创建高阶组件。import { ref } from vue export default function withHover(Component) { return { setup(props, { slots }) { const isHovered ref(false) return () ( div onMouseenter{() (isHovered.value true)} onMouseleave{() (isHovered.value false)} Component {...props} isHovered{isHovered.value} v-slots{slots} / /div ) } } }在这个例子中withHover函数接收一个组件并返回一个新的组件新的组件有一个isHovered属性表示鼠标是否悬停在组件上。这种模式可以帮助我们在不同的组件间复用逻辑。其它组合APIcomputedcomputed函数用于创建一个响应式的计算属性。这个属性的值是由提供的 getter 函数计算得出并且只有当它的依赖项改变时才会重新计算。import { ref, computed } from vue export default { setup() { const count ref(0) const doubleCount computed(() count.value * 2) return { count, doubleCount } } }在这个示例中我们创建了一个doubleCount计算属性它的值始终是count的两倍。watch 和 watchEffectwatch和watchEffect函数用于观察一个或多个响应式引用或函数并在其值改变时执行副作用。import { ref, watch, watchEffect } from vue export default { setup() { const count ref(0) watch(count, (newCount, oldCount) { console.log(Count changed from ${oldCount} to ${newCount}) }) watchEffect(() { console.log(Count is ${count.value}) }) return { count } } }在这个示例中我们使用watch函数观察count并在其值改变时打印消息。我们还使用watchEffect函数创建了一个副作用它会在count改变时立即执行。lifecycle hooks在 Vue 3 中你可以在setup函数中直接使用生命周期钩子函数例如onMountedonUpdated和onUnmounted。import { onMounted, onUpdated, onUnmounted } from vue export default { setup() { onMounted(() { console.log(Component is mounted) }) onUpdated(() { console.log(Component is updated) }) onUnmounted(() { console.log(Component is unmounted) }) } }在这个示例中我们在组件挂载、更新和卸载时打印消息。这些是 Vue 3 中提供的更为高级的响应式 API让我们逐一了解它们。shallowReactive 与 shallowRefshallowReactive和shallowRef允许我们创建一个浅层的响应式对象。对于shallowReactive只有对象的第一层属性会变为响应式的对象的更深层次的属性不会被转换。shallowRef是ref的浅层版本它不会自动解包内部的值。import { shallowReactive, shallowRef } from vue const obj shallowReactive({ a: { b: 1 } }) obj.a.b // 这不是一个响应式的值 const num shallowRef(1) num.value // 你需要使用 .value 才能访问到值readonly 与 shallowReadonlyreadonly和shallowReadonly允许我们创建一个只读的响应式对象。对于readonly对象的所有属性包括嵌套属性都会变为只读。shallowReadonly是readonly的浅层版本只有对象的第一层属性会变为只读。import { readonly, shallowReadonly } from vue const obj readonly({ a: { b: 1 } }) obj.a 2 // 这会抛出一个错误 const shallowObj shallowReadonly({ a: { b: 1 } }) shallowObj.a.b 2 // 这不会抛出错误toRaw 与 markRawtoRaw和markRaw允许我们逃避 Vue 的响应式系统。toRaw可以返回一个对象的原始版本而markRaw可以防止一个对象被转换为响应式的。import { reactive, toRaw, markRaw } from vue const obj reactive({ a: 1 }) const rawObj toRaw(obj) // rawObj 是 obj 的原始版本 const nonReactiveObj markRaw({ a: 1 }) // nonReactiveObj 不会被转换为响应式的customRefcustomRef允许我们创建一个自定义的 ref我们可以控制它何时触发依赖追踪和更新。import { customRef } from vue const myRef customRef((track, trigger) ({ get() { track() return someValue }, set(newValue) { someValue newValue trigger() } }))provide 与 injectprovide和inject是 Vue 3 的依赖注入 API可以用于在组件树中传递值而不必一层一层地通过 props 传递。import { provide, inject } from vue // 在父组件中 provide(myValue, 123) // 在子组件中 const myValue inject(myValue) // myValue 现在是 123响应式判断Vue 3 提供了isReactive和isRef函数用于检查一个值是否是响应式的或者一个 ref。import { reactive, ref, isReactive, isRef } from vue const obj reactive({ a: 1 }) isReactive(obj) // true const num ref(1) isRef(num) // true这些 API 提供了更多的控制和灵活性使我们能够根据需要来选择如何使用 Vue 的响应式系统。深入响应式系统Vue 3 的响应式系统构建在一个名为effect的函数基础之上它被用来收集依赖项依赖追踪和触发副作用。当一个响应式对象的属性被访问时effect将其收集为依赖项当一个响应式对象的属性被修改时它将触发关联的副作用。effect、reactive、refreactive和ref是 Vue 3 的两种基本响应式 API。它们都使用effect来跟踪依赖项和触发更新。import { effect, reactive, ref } from vue // 使用 reactive const state reactive({ a: 1 }) effect(() { console.log(state.a) }) state.a 2 // 打印 2 // 使用 ref const count ref(0) effect(() { console.log(count.value) }) count.value // 打印 1在这个示例中我们创建了一个响应式对象和一个 ref然后使用effect创建了两个副作用它们分别打印出对象和 ref 的值。当这些值被改变时副作用就会被触发。track、triggertrack和trigger是 Vue 3 的底层 API它们分别被用来收集依赖项和触发更新。import { reactive, effect, track, trigger } from vue const state reactive({ a: 1 }) effect(() { // 手动进行依赖追踪 track(state, a) console.log(state.a) }) state.a 2 // 打印 2 // 手动触发更新 trigger(state, a)在这个示例中我们使用track手动收集了state.a作为依赖项然后使用trigger手动触发了更新。嵌套结构处理Vue 3 的响应式系统可以处理嵌套的响应式对象。import { reactive, effect } from vue const state reactive({ user: { name: Alice } }) effect(() { console.log(state.user.name) }) state.user.name Bob // 打印 Bob在这个示例中我们创建了一个嵌套的响应式对象并使用effect创建了一个副作用它打印出用户的名字。当用户的名字被改变时副作用就会被触发。Render 函数在 Vue 3 中Render 函数是一种提供了更大灵活性的高级功能。虽然 Vue 的模板系统已经足够强大但在某些情况下直接使用 JavaScript 编写渲染逻辑会更加方便。Render 函数的工作原理是通过返回一个虚拟节点VNode来告诉 Vue 如何渲染界面。Vue 3 提供了h函数用于创建 VNode。import { h } from vue export default { render() { return h(div, {}, Hello, world!) } }在这个例子中我们使用h函数创建了一个div元素然后在 Render 函数中返回它。编译优化Vue 3 的编译器在编译时做了许多优化例如静态节点提升和动态节点绑定从而在运行时减少了不必要的工作。静态节点提升可以将不会改变的节点从渲染函数中提取出来从而避免在每次渲染时都重新创建它们。动态节点绑定则是对那些可能改变的节点进行优化只有当这些节点的绑定值发生变化时才会重新渲染节点。手动编写渲染逻辑有时我们可能需要手动编写渲染逻辑。比如当我们需要根据一组数据动态生成一个列表时我们可以在 Render 函数中使用 JavaScript 的数组方法。import { h } from vue export default { data() { return { items: [Apple, Banana, Cherry] } }, render() { return h(div, {}, this.items.map(item h(div, {}, item))) } }在这个例子中我们使用map方法动态生成了一个列表的元素然后在 Render 函数中返回它。Render 函数提供了一种强大的方式来控制 Vue 应用的渲染过程使得我们能够更好地控制和优化应用的性能。vue生态配套状态管理Pinia 是 Vue 3 提供的一种新型状态管理库它提供了 Vuex 的核心功能但在 API 设计上更加简洁且易用。Pinia 的主要优点包括它有更简洁的 API减少了模板代码的数量。它通过 TypeScript 提供了更好的类型支持。它提供了基于组件的状态存储只在需要时加载状态。下面是一个 Pinia 使用示例首先安装 Pinianpm install pinia然后创建一个 Pinia store// src/stores/counter.js import { defineStore } from pinia export const useCounterStore defineStore({ id: counter, state: () ({ count: 0 }), actions: { increment() { this.count } } })然后在你的 main.js 或 main.ts 文件中创建 Pinia 插件并将其添加到你的 Vue 应用中import { createApp } from vue import { createPinia } from pinia import App from ./App.vue const app createApp(App) app.use(createPinia()) app.mount(#app)然后你可以在组件中使用该 storetemplate button clickincrement{ { count }}/button /template script import { useCounterStore } from /stores/counter export default { setup() { const counter useCounterStore() return { count: counter.count, increment: counter.increment } } } /script以上就是 Pinia 的基本用法它提供了一种更简洁、更灵活的方式来管理 Vue 应用的状态。路由管理 - Vue RouterVue Router 是 Vue.js 的路由库你可以使用它构建单页面应用程序如下面的例子所示首先创建一个 routerimport { createRouter, createWebHistory } from vue-router import Home from ./components/Home.vue import About from ./components/About.vue const router createRouter({ history: createWebHistory(), routes: [ { path: /, component: Home }, { path: /about, component: About } ] })然后在 Vue 应用中使用这个 routerimport { createApp } from vue import App from ./App.vue import router from ./router createApp(App).use(router).mount(#app)最后在组件中使用router-link和router-view来导航和渲染路由template router-link to/Home/router-link router-link to/aboutAbout/router-link router-view/router-view /templateUI 框架 - Element UIElement UI 是一个为 Vue.js 开发的 UI 框架它提供了一套丰富多样的组件可以帮助我们更容易地构建出漂亮的界面template el-button typeprimary主要按钮/el-button el-button typesuccess成功按钮/el-button el-button typewarning警告按钮/el-button /template测试方案 - VitestVitest 是一个由 Vite 提供支持的极速单元测试框架。import { assert, describe, it } from vitest describe.skip(skipped suite, () { it(test, () { // 已跳过此测试套件无错误 assert.equal(Math.sqrt(4), 3) }) }) describe(suite, () { it.skip(skipped test, () { // 已跳过此测试无错误 assert.equal(Math.sqrt(4), 3) }) })其他改变在 Vue 3 中开发者会注意到一些重要的变化主要体现在全局 API 的转移等以及对 TypeScript 的更好支持上。全局 API 转移在 Vue 3 中一些全局 API 已经被转移到了globalProperties上例如Vue.prototype在 Vue 3 中变成了app.config.globalProperties。这样做是为了更好地隔离全局 API并为未来可能的更改提供更大的灵活性。例如原本在 Vue 2 中我们可能会这样添加一个全局的方法Vue.prototype.$myGlobalMethod function () { return Hello World! }在 Vue 3 中我们需要这样做const app createApp(App) app.config.globalProperties.$myGlobalMethod function () { return Hello World! }然后我们就可以在任何组件中使用这个方法this.$myGlobalMethod()删除的 APIVue 3 为了简化框架并避免未来的维护负担删除了一些在 Vue 2 中已经被废弃的 API例如Vue.set、Vue.delete和Vue.observable。TypeScript 支持Vue 3 从一开始就在内部使用了 TypeScript 重写因此在 TypeScript 的支持上有了显著的提升。这包括更好的类型推断、自动补全以及更强大的类型安全性。例如在 Vue 2 中我们可能需要使用 Vue.extend() 或者Component装饰器来确保 TypeScript 类型正确但在 Vue 3 中我们可以直接使用defineComponent方法它能正确地推断出组件的类型import { defineComponent } from vue export default defineComponent({ // type inference enabled })下载地址:扫码关注公众号回复“方方格子”自动获取下载链接