# Vue3_尚硅谷学习 **Repository Path**: williamsl13/Vue3_learning ## Basic Information - **Project Name**: Vue3_尚硅谷学习 - **Description**: 此为尚硅谷Vue3视频学习笔记,请支持正版视频资源 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: https://www.bilibili.com/video/BV1Zy4y1K7SH?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 5 - **Created**: 2022-04-28 - **Last Updated**: 2025-02-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## setup 1 理解:Vue3的一个新的配置项,值为一个函数,需要返回值 2 setup是多有Composition API(组合API)的舞台 3 组件中用到的数据、方法等都需要配置在setup中 4 setup函数两种返回值: 1)返回一个对象,对象的属性、方法在模板可以直接使用(主要) 2)返回一个渲染函数,可以自定义渲染内容(用的少) 5 注意: 1)不要与Vue2.x配置项混用 ————Vue2配置项:data、methodscomputed可以直接访问setup的属性、方法 ————但在setup不能访问到Vue2配置:data、methods、computed ————若有重名,setup优先 2)setup不能是一个async函数,因为返回值不再是return的对象,而是被promise包裹的对象,模板看不到return对象的属性 ## ref函数(引入到setup) 1 作用:定义响应式数据 2 语法:const xxx = ref(initValue) -创建一个包含响应式数据的引用对象(reference对象) -JS操作数据:xxx.value -模板中读取数据:不需要.value,直接
{{xxx}}
3 备注 -接收数据:基本类型、对象类型 -基本类型数据:响应式靠Object.defineProperty()的get与set函数完成的 -对象类型数据:内部求助了Vue3的新函数——reactive函数 ## reactive函数(引入到setup) 1 定义一个对象类型的响应式数据(基本类型不要用它,用ref函数) 2 语法:const 代理对象 = reactive(源对象) 接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象) 3 reactive定义的响应式数据是深层次的 4 内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作,改变可以被vue捕获到————响应式 ## Vue3的响应式原理 Vue2.x的响应式: 1 实现原理: 对象类型:Object.defineProperty()对属性读取、修改进行拦截(数据劫持) 数组类型:重写更新数组等方法实现拦截:(对数组的变更的方法进行包裹) Object.defineProperty(data,'count',{ get(){}, set(){} }) 2 存在问题: 新增属性、删除属性,界面不更新 直接通过下标修改数组,界面不自动更新,需要指定数组操作函数才可被识别 ————this.$set(this.person,'sex','女') ————this.$delete(this.person,'sex') ————this.$set(this.person.hobby,0,'吃饭') ————this.person.hobby.splice(0,1,'吃饭') ————Vue.set(this.person,'sex','女') ————Vue.delete(this.person,'sex','女') Vue3的响应式 1 实现原理: 1)通过Proxy(代理):拦截对象任意属性的变化,包括属性值的读写、属性添加、删除等 2)通过Reflect(反射):对被代理对象属性进行操作 3)MDN文档描述的Proxy与Reflect Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect const p = new Proxy(person, { // 读取p某个属性时调用 get(target, propName) { console.log(`有人读取${target}身上的${propName}属性`); // return target[propName]; return Reflect.get(target, propName); }, // 修改p某个属性、或给p追加某个属性时调用 set(target, propName, value) { console.log(`有人修改${target}身上的${propName}属性`); // target[propName] = value; Reflect.set(target, propName, value); }, // 删除p某个属性时调用 deleteProperty(target, propName) { console.log(`有人删除${target}身上的${propName}属性`); // return delete target[propName]; return Reflect.deleteProperty(target, propName); }, }); 备注: Object.defineProperty不能重定义,后续代码不能执行 封装框架:不好捕获错误,使用try{}catch(error){} Reflect.defineProperty,返回true/false,重定义后续代码可以执行 框架封装更友好 ## reactive对比ref 1 定义数据角度: 1)ref定义:基本数据类型 2)reactive定义:对象/数组类型数据 备注:ref也可以定义对象/数组类型数据,内部自动通过reactive转为代理对象 2 原理角度: 1)ref通过Object.defineproperty()的get与set实现响应式(数据劫持) 2)reactive通过使用Proxy实现响应式(数据劫持),通过Reflect操作源对象内部的数据 3 使用角度: 1)ref定义的数据:操作数据需要.value,读取数据时模板直接读取不需要.value 2)reactive定义数据:操作数据与读取数据均不需要.value ## setup两个注意点 1)setup执行时机 beforeCreate之前执行一次,this是undefined 2)setup参数 props:值为对象,包含:组件外部传递,且组件内部声明接收了的新属性 context:上下文 ——attrs:对象,外部传递过来,但没有在props配置声明的属性,相当于this.$attrs ——slots:收到的插槽内容,相当于this.$slots ——emit:分发自定义事件的函数,相当于this.$emit ## computed函数(引入到setup) 1 与Vue2中computed配置功能一致 2 写法 import { computed } from "vue"; setup() { let person = reactive({ firstName: "张", lastName: "三", }); // 计算属性简写 person.fullName = computed(()=>{ return return person.firstName + "-" + person.lastName; }); // 计算属性完整 person.fullName = computed({ get() { return person.firstName + "-" + person.lastName; }, set(value) { const nameArr = value.split("-"); person.firstName = nameArr[0]; person.lastName = nameArr[1]; }, }); return { person, }; }, ## watch函数(引入到setup) 1 与Vue2中watch配置功能一致 2 两个tips 1)监视reactive定义的响应式数据时,oldValue无法正确获取,强制开启深度监视(deep配置失效) 2)监视reactive响应式数据某个属性时,deep配置有效 // 监视ref数据 // watch(sum, (newValue, oldValue) => { // console.log(newValue, oldValue); // },{immediate:true}); // 监视多个ref,可以写两个watch函数 watch( [sum, msg], (newValue, oldValue) => { console.log(newValue, oldValue); }, { immediate: true } ); /* 1 监视reactive定义的响应式数据全部属性 若监视的是对象,无法获取oldValue 注意1:此处无法正确获得正确oldValue,ref则无问题 注意2:强制开启了深度监视,reactive */ watch(person, (newValue, oldValue) => { console.log(newValue); console.log(oldValue); }); // 2 监视reactive所定义的一个响应式数据某个属性 // 监视对象需要写成函数返回值 watch( () => person.age, (newValue, oldValue) => { console.log(newValue); console.log(oldValue); } ); // 3 监视某些属性,写成数组 watch([() => person.age, () => person.name], (newValue, oldValue) => { console.log(newValue); console.log(oldValue); }); // 特殊 // 由于监视的是reactive定义的person的某个属性(依然是对象),所以deep配置生效 watch( () => person.job, (newValue, oldValue) => { console.log(newValue); console.log(oldValue); }, { deep: true } ); ## watchEffect函数 1 watch:既要指明监视的属性,也要指明监视的回调 2 watchEffect:不用指明监视哪个属性,监视回调用到哪个属性,就监视哪个属性 3 watchEffect有点类似于computed 1)computed注重计算出来的值(回调函数返回值),必须写返回值 2)watchEffect注重过程(回调函数函数体),不用写返回值 // watchEffect所指定的回调中用到的数据只要发生变化,直接重新执行回调 watchEffect(()=>{ const x1 = sum.value const x2 = person.age console.log("watchEffect执行了"); }) ## Vue3生命周期钩子(需要引入到setup) beforeCreate ==> setup() created ==> setup() beforeMount ==> onbeforeMount mounted ==> onMounted beforeUpdate ==> onBeforeUnmount updated ==> onUpdated beforeUnmount ==> onBeforeUnmount unmounted ==> onUnmounted 先后顺序: setup——beforeCreate——created——onBeforeMount——beforeMount——onMounted——mounted——…… 组合式API生命周期比配置项写的执行更快 ## 自定义hook函数 1 hook? 本质是函数,把setup函数使用的Composition API进行封装 2 类似Vue2的mixin 3 优势:复用代码,让setup逻辑清楚 ## toRef() 1 作用:创建一个ref对象,value值指向另一个对象的某个属性 2 语法:const name = toRef(person,'name') 3 应用:将响应式对象中的某个属性单独提供给外部使用时 4 扩展:toRefs与toRef功能一致,可以批量创建多个ref对象,语法 toRefs(person),只能拆一层 ## shallowReactive与shallowRef(引入) 1 shallowReactive:只处理对象最外层属性的响应式(浅响应式) 2 shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理 3 什么时候: 1)若有一个对象数据,结构比较深,但变化只是外层属性变化:shallowReactive 2)若一个对象数据,后续功能不会修改对象属性,而是新生成的对象替换:shallowRef ## readonly与shallowReadonly(引入) 1 readonly:让一个响应式数据变为只读(深只读) 2 shallowReadonly:让一个响应式数据变为只读(浅只读),可以修改深层次的数据 3 场景:不希望数据被修改 ## toRaw与markRaw(引入) 1 toRaw 作用:将一个有reactive生成的响应式对象转为普通对象 场景:用于读取响应式对象对应的普通对象,对这个普通对象所有操作不会引起页面更新 2 markRaw 作用:标记一个对象,使其永远不会再成为响应式对象 场景: 1)有些值不应设置响应式的,如第三方的类库等 2)当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能 ## customRef(引入) 1 作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显式控制 2 实现防抖: ## provide与inject(引入) 1 作用:实现祖与后代间通信/跨级组件,父子间也可以,但一般使用props 2 用法:父组件有provide选项提供数据,后代组件有inject选项使用这些数据 3 写法: 祖组件: setup(props) { let car = reactive({ name: "奔驰", price: 30, }); // 给自己后代组件传递数据 provide("car", car); return { ...toRefs(car), }; }, 后代组件: setup(props) { let car = inject("car"); console.log(car); return { car, }; }, ## 响应式数据的判断(引入) 1 isRef:检查一个值是否为ref对象 2 isReactive:检查一个对象是否是由reactive创建的响应式代理 3 isReadonly:检查一个对象是否是由readonly创建只读代理 4 isProxy检查一个对象是否是由reactive或readonly方法创建的代理 ## Composition API优势 1 Options API问题 传统OptionsAPI,新增、修改一个需求,分别在data、methods、computed修改 2 Composition API优势 更优雅的组织代码、函数,让相关功能更加有序的组织在一起 ## Fragment组件 1 在Vue2中:组件必须有一个根标签 2 在Vue3中,组件可以没有根标签,内容会将多个标签包含在一个fragment虚拟元素中 3 好处:减少标签层级,减少内存占用 ## Teleport组件 1 Teleport是一种能让组件html结构移动到指定位置的技术

弹窗

内容

内容

内容

内容

## Suspense组件 1 等待异步组件时渲染一些额外内容,让应用有更好体验 2 使用步骤: 异步引入组件 ## 全局API转移 Vue2有许多全局API和配置 如注册全局组件、注册全局指令等、 ![image-20220502143932435](README.assets/image-20220502143932435.png) ![image-20220502143950266](README.assets/image-20220502143950266.png) 其他改变: ——data选项始终被声明为一个函数,必须函数 ——过渡类名: .v-enter, .v-leave-to{ opacity:0 } .v-leave, .v-enter-to{ opacity:1 } Vue3写法: .v-enter-from, .v-leave-to{ opacity:0 } .v-leave-from, .v-enter-to{ opacity:1 } ——移除keyCode作为v-on的修饰符,也不支持config.keyCodes(兼容性)自定义别名按键 ——移除v-on.native修饰符(原生事件,不是自定义事件) 在子组件声明:即为自定义事件,不然默认是原生事件 emits:'close' ——移除过滤器filter 用methods或computed替换过滤器 …………