# 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 实现防抖:
{{ keyWord }}
## 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和配置
如注册全局组件、注册全局指令等、


其他改变:
——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替换过滤器
…………