目录
通过Proxy(代理):拦截对象中任意属性的变化,包括属性值的读写,属性的添加,属性的删除。
使用Vue-cli创建
使用vite创建
Composition API 组合API
setup
1.Vue3中的一个新的配置项,值为一个函数
2.可以将组件中所用到的数据,方法等配置在setup中.
3.setup函数的两种返回值
3.1若返回一个对象,则对象中的属性,方法,在模板中均可以直接使用.
3.2若返回一个渲染函数,则可以自定义渲染内容.
注意:Vue2.0配置(data,methos,computed,...)中可以访问到setup中的属性,方法.但在setup中不能访问(data,methos,computed,...).如果有重名,setup优先
执行时机
在beforeCreate生命周期前执行一次,this是undefined
setup的参数
- props:值为对象,包含父组件传递过来,且组件内部声明接收了的属性。
-
export default { props:['name','id'], emits:['事件名称'], setup(props,context){ // props:{name:'',id:''} console.log(props) } }
-
- context:上下文对象
- attrs:值为对象,包含父组件传递过来但没有在props配置中声明的属性,相当于Vue2的this.$attrs.
- slots:收到的插槽内容,相当于Vue2的this.$slots.Vue3中的具名插槽要用v-slot:name
- emit:分发自定义事件的函数,相当于Vue2的this.$emit.(需要再emits配置中声明)
ref函数
定义一个响应式数据
const xxx = ref(initValue)
创建一个包含响应式数据的引用对象(RefImpl)
JS中操作数据:xxx.value
模板中读取数据不需要.value
备注:
- 接收的数据可以是:基本数据类型,也可以是对象类型
- 基本数据类型:响应式依然是用Object.defineProperty()的get与set完成的.
reactive函数
- 定义一个对象类型的响应式数据
- const 对象 = reactive(对象),接收一个对象或数组,返回一个代理对象(Proxy对象)
- reactive定义的响应式数据是"深层次的"
- 基于ES6的Proxy实现,通过代理对象操作源对象内部数据都是响应式的.
reactive对比ref
从定义数据角度对比:
- ref定义基本数据类型
- reactive定义引用数据类型
- ref也可以定义引用数据类型,但是内部还是通过reactive转为代理对象
从原理角度对比:
- ref通过Object.defineProperty()的get和set实现数据响应(数据劫持)
- reactive通过Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据
从使用角度对比:
- ref定义的数据:操作数据时需要.value,在模板中不需要
- reactive定义的数据:操作数据与读取数据均不需要.value
Vue3.0中的响应式原理
Vue2的响应式
-
实现原理
对象类型:通过Object.defineProperty()对属性的读取,修改进行拦截(数据劫持).
数组类型:通过重写更新数组的一系列方法来实现拦截.(对数组的变更方法进行了包裹).
- 存在问题
新增属性,删除属性,界面不会更新.(可以使用this.$set()和this.$delete())
直接通过下标修改数组元素,界面不会更新.(通过splice修改数组元素)
Vue3的响应式
-
实现原理
-
通过Proxy(代理):拦截对象中任意属性的变化,包括属性值的读写,属性的添加,属性的删除。
-
通过Reflect(反射):对被代理对象的属性进行操作。
new Proxy(data,{
// 拦截读取属性值
get(target,propertyName){
// target 源对象
// propertyName 属性名
return Reflect.get(target[propertyName])
},
set(target,propertyName,value){
// value 修改的值
return Reflect.set(target,propertyName,value)
},
deleteProperty(target,propertyName){
return Reflect.deleteProperty(target[propertyName])
}
})
计算属性与监视
computed函数
watch函数
watchEffect函数
toRef和toRefs
-
作用:创建一个ref对象,其value值指向另一个对象中的某个属性
-
语法:const value = toRef(person,'属性名')
-
应用:将响应式对象中的某个属性单独提供给外部使用时
-
扩展: toRefs与toRef功能一致,但是可以批量创建多个ref对象。(toRefs(person)返回一个对象,对象中的所有属性都是一个RefImpl对象,其value值都指向person对象中对应的属性值)
其它Compositon Api
shallowReactive与shallowRef
- shallowReactive:只处理对象最外层属性的响应式(浅响应式)。在一个对象数据,结构比较深,但变化时只是外层属性变化时使用。
- shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理。在一个对象数据,后续功能不会修改对象的属性,而是生成新的对象来替换时使用。
- 传入基本数据类型,跟ref功能一致。
- 传入对象,返回的RefImpl对象的value值是一个普通的Object对象,没有响应式。
readonly与shallowReadonly
- readonly:让一个响应式数据变为只读的(深只读)。
- shallowReadonly:让一个响应式数据变为只读的(浅只读)
不希望数据被修改时使用
toRaw与markRaw
- toRaw:将一个由reactive生成的响应式对象转换为普通对象。
- 用于读取响应式对象对应的普通对象,对这个普通对象的所有操作不会引起页面更新。
- markRaw:标记一个对象,使其永远不会再成为响应式对象。
- 有些值不应该被设置为响应式的,例如复杂的第三方类库等。
- 当渲染具有不可变数据源的列表时,跳过响应式转换可以提高性能。
customRef
- 创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显式控制.
setup(){
//自定义一个myRef
function myRef(value,delay){
return customRef((track,trigger)=>{
let timer
return {
get(){
track() // 通知Vue追踪value的变化,
return value
},
set(newValue){
clearTimeout(timer)
timer = setTimeout(()=>{
value = newValue
trigger() // 通知Vue重新解析模板
},delay)
}
}
})
}
return {
value:myRef('初始值',500)
}
}
provide与inject
- 实现祖孙组件间的通信
// 祖组件中使用provide提供数据
setup(){
let car = reactive({name:'name',price:'price'})
provide('car',car)
}
// 孙组件中使用inject接收数据
setup(){
const car = inject('car')
return {car}
}