Vue 3 于 2020 年 9 月发布是 Vue.js 的重大升级版本主要改进包括性能优化、新特性引入和更好的 TypeScript 支持。性能打包大小减少41%、初次渲染快51%、更新渲染快133%内存占用减少54%。使用Proxy 代替Object.defineProperty 实现双向数据绑定重写虚拟DOM的实现和Tree-Shaking更好的 TypeScript 支持源码使用 TypeScript 重写提供完整的类型定义开发体验更友好IDE 提示更精准。快速生成vue3项目创建vue项目可以使用vue-cliwebpack和vite更推荐1.node版本要不低于18.32.npm create vuelatest 、 npm init vuelatest、npx create-vuelatest等效 自动从 npm 仓库拉取最新版create-vue工具包临时安装到本地然后按提示操作即可Vue3 的组件可以按两种不同的风格书写选项式 API (Vue2)和组合式 API(Vue3新增加的)选项式 API (Options API-Vue2写法)配置风格数据、方法、计算属性等分散在datamethods,computed中新增或修改需求时需要分别修改data、methods、computed不便于维护和复用组合式 API (Composition API)用函数的方式更优雅的组织代码让相关功能的代码更加有序的组织到一起且data、methods、watch等在同一个位置比较好找不需要像大的Vue2组件中从data找到对应的methods必须搜索要不很难找到Vue3的变化从vue中引入createApp创建应用 createApp(App).mount(#app)script langts/script代表使用ts语言不写默认jsvue3组件中可以有多个根标签setup函数中的this是undefinedvue3已经弱化this了setup和vue2中的data、methods、watch可以同时出现在vue3中但是非常不推荐vue2中可以读取到setup中的数据但是setup中无法读取data配置项的数据因为setup执行的时机更早setup语法糖setup也是一个特殊的钩子专门用于组合式 API。// 在编辑器中新建一个vue文件输入vue可快速生成vue模板script langts setuplet name abcfunction changeName(){name aaa}/script组件命名组件使用的名字和实际文件名字不一致时可以使用vue-setup-extend插件代替组件命名script langts export default {name:ABC} /script1.npm i vite-plugin-vue-setup-extend -D2.在vite.config.ts文件中import VueSetupExtend from vite-plugin-vue-setup-extend在plugins配置中加上VueSetupExtend()3.在script langts setup nameABCref函数声明响应式状态使数据变成响应式ref()接收参数并将其包裹在一个带有.value属性的 ref 对象中返回import { ref } from vue基本数据类型const count ref(0) function changeCount(){ count.value 1}复杂数据类型const obj ref({name: a}) function changeObj(){ obj.vaklue.name b}当在模板中使用时ref 会自动解包不需要附加.value在script标签中需要.value操作数据可引入volar插件自动添加valuebutton clickcount {{ count }} /buttonref可以持有任何类型的值包括深层嵌套的对象、数组或者 JavaScript 内置的数据结构比如Map但基本数据只能使用ref来创建响应数据ref 会使它的值具有深层响应性即使改变嵌套对象或数组时变化也会被检测到ref在将复杂数据类型转换为响应式数据时底层还是借助了reactive的能力reactive()reactive()把对象本身具有响应性只能用于对象类型 (对象、数组和如Map、Set)。它不能持有基本数据类型import { reactive } from vueconst obj reactive({ count: 0 })reactive重新分配一个新对象会丢失响应式可以使用Object.assign(obj,{count:1})去替换整体ref不存在类似问题function changeObj() {obj {a: 456} // 不会生效因为重新分配对象导致丢失响应式Object.assign(obj, {a: 456}) // 需要利用Object.assign更新}层级不深的对象ref和reactive都可以如果是层级较深的对象如表单功能建议使用reactivetoRefs、toRefobj是响应对象let {a} obj, 再对a操作也不会响应式直接解构的数据不是响应数据因为const {a} obj相当于 let aobj.a,响应数据变量obj并没有变化而新定义的a并不是响应式数据let {a} toRefs(obj)toRefs可把解构出来多个值变成响应式相当于使用了ref解构出来的值需要使用.value来操作let a2 toRef(obj, ‘a’)toRef可解构单个值,并把解构出来的值变为响应式也需要使用.value来操作使用场景较少计算属性computedimport { comouted } from vue// 1.此种计算属性只可读取不可修改let fullName computed((){return name1.value name2.value})// 2.此种写法可读可修改let fullName computed({get() {return name1.value name2.value}set(value){name1.vuale value}})watch和wactchEffectimport { watch, ref} from vue; // 支持使用数组监听多个数据let name ref(小明)// 1.监听ref创建的基本响应数据不可以加valuewatch(name, (new, old){if(new 张飞){stopWatch() // 可以停止监听}})// 2.监听ref创建的对象响应数据监听的对象地址所以需要开启深度监听watch(name, (new, old){// 修改的是ref响应对象的属性时newold,因为是同一个对象所以old不能使用// 若修改的是整个ref定义的对象那么不再是同一个值了old可以使用if(new 张飞){stopWatch() // 可以停止监听}}deep: true)3.监视reacive创建的响应数据默认隐式的开启的深度监听且oldnew4.监视ref或者reactive对象中的一个属性时如果这个属性是基本数据类型需要写成函数式因为watch只能监视响应式数据ref、reactive、computed或函数返回值如果这个属性是对象可以直接写建议还是写成函数式再手动开启深度监听因为watch监听的是地址watch(()return obj.a, (newold) {// a为基本数据时new !b// a为对象类型须手动开启深度监听因为watch监听的是函数返回的地址建议此写法})watch( obj.a, (newold) {// a为对象类型时如果a被整体替换无法被监听到具有局限性})wactchEffect自动监听函数中使用的数据变化wactchEffect((){if(sum 5) {console.log(sum)}// 上来会先执行一次,自动监视逻辑代码中的所有变量})标签的refdiv refactive/divimport { ref } from vuelet active ref() // active.value就可以拿到这个目标元素在组件中使用时父组件想获取子组件的数据需要在子组件中使用defineExpose来导出数据共父组件使用import {defineExpose} from vuedefineExpose({a,b})Ts使用可以在src文件下新建一个type文件夹再新建一个index.ts文件定义一个接口类型export interface PersionType {name: string, // 都是小写age: number}export type Persons PersionType[] // 创建一个自定义类型导入的接口需要在前边加一个type用来和普通的方法或数据做区分目标文件中可以直接import {type PersionType} from /type导入使用let abj:PersionType {name: 张三age:19}let arr: ArrayPersionType [{name: 张三age:60}]实际使用let list reactivePersons([ {name: 张三age:19}...])setup中添加langts时引入组件会报错 会报错Module /Users/zhuzhu/Desktop/vue3/vue-project/src/components/TheWelcome.vue has no default export.Vetur(1192)这个问题是因为 TypeScript 无法正确识别script setup的默认导出而 VeturVSCode 的 Vue 插件在 TypeScript 模式下会进行更严格的检查Vetur 对script setup TypeScript 的支持不够完善解决办法是VSCode 扩展中禁用禁用 Vetur安装 Volar重启vscodeprops父组件Person a123 /Person子组件h2{{a}}/h2import { defineProps, widthDefaults } from vue //defineProps是宏函数可不引入直接使用// 此时子组件的模板可以正常使用a变量了但是在script标签中不可以使用defineProps([a])接受并保存才能在script标签中使用let x defineProps([a]) // 可以使用x.a来访问a接收数据限制类型 :defineProps{list: Persons }() 或 :defineProps{list?: Persons }()接收数据限制类型置顶默认值 :widthDefaults(defineProps{list?: Persons }() ,{a:123... // 当父组件传值为空时的兜底})生命周期创建setup 中的代码就是创建阶段执行的所以在 Vue3 中没有针对创建阶段专门的回调函数直接在 setup 中写就好了挂载 onBeforeMount 、onMounted更新onBeforeUpdate、onUpdated卸载onBeforeUnmount、onUnmountedonBeforeMount(() { console.log(挂载前); });自定义hooks可以在src下新建hooks文件夹在其中创建单独的.js或.ts文件将功能拆分到单独的文件中。路由使用路由可以通过不同的URL路径来访问不同的页面组件而无需重新加载整个页面。安装vue-routenpm install vue-routerrouter/index.tsimport { createRouter, createWebHistory } from vue-router import HomeView from ../views/HomeView.vue const router createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: /, name: home, component: HomeView }, { path: /about, name: about, component: () import(../views/AboutView.vue) } ] }) export default routermain.js中引入路由配置import ./assets/main.css import { createApp } from vue import App from ./App.vue // 引入路由 import router from ./router const app createApp(App) // 使用路由 app.use(router) app.mount(#app)路由组件通常放在pages文件夹或views文件夹一般组件放components文件夹导航区to:可以使用字符串或对象router-link active-classactive to/home主页/router-linkrouter-link active-classactive :to{path: /home}主页/router-link展示区RouterView/RouterView嵌套路由的子级不要写/,在 Composition API 中不能直接使用this来访问this.$router因为 Composition API 是基于函数的不使用基于类的组件结构。相反你应该使用setup函数来设置组件并通过useRouter钩子来获取路由实例。import { useRouter } from vue-router;const router useRouter();router.push(/home);query传参获取import { useRouter, toRefs } from vue-routerlet { route } useRouter()let { query } toRefs(route) // 此时可以通过query.id读取参数了params传参(使用to的对象写法必须使用name配置不能使用path还必须提前在规则中占位)router-link active-classactive to/news/datail/hh/ss/pp主页/router-linkimport { useRouter, toRefs } from vue-routerlet { route } useRouter()let { parms } toRefs(route) // 此时可以通过parms.id读取参数了push会增加历史记录replace不会增加记录不能前进回退Pinia状态管理npm install pini, 在main.js文件中挂载到实例对象上import { createApp } from vue import App from ./App.vue import router from ./router // 1.引入pinia import { createPinia } from pinia const app createApp(App) // 2.创建pinia const pinia createPinia() // 3. 安装pinia app.use(pinia) app.use(router) app.mount(#app)