-
proxy对象实现属性监听
-
多层次属性嵌套,在访问属性过程中处理下一级属性
-
默认监听动态添加的属性
-
默认监听数组索引和length属性
-
可以作为单独的模块使用
核心方法
-
Reactive/ref/toRefs/computed
-
effect
-
track
-
trigger
Reactive函数
-
接收一个参数,判断这参数是否是对象
-
创建拦截器对象handler,设置get/set/deleteProperty
-
返回Proxy对象
Reactive代码示例
export function reactive(target) {
if (!isObject(target)) return target
const handler = {
get(target, key, receiver) {
//收集依赖
track(target, key)
// console.log('get', key)
const result = Reflect.get(target, key, receiver)
return convert(result)
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver)
let result = true
if (oldValue !== value) {
result = Reflect.set(target, key, value, receiver)
//触发更新
trigger(target,key)
//console.log('set', key, value)
}
return result
},
deleteProperty(target, key) {
const hadkey = hasOwn(target, key)
const result = Reflect.deleteProperty(target, key)
if (hadkey && result) {
// 触发更新
trigger(target,key)
// console.log('delete', key)
}
return result
}
}
return new Proxy(target, handler)
}
effect代码示例
let activeEffect = null
export function effect(callback) {
activeEffect = callback
callback()//访问响应式对象属性,去收集依赖
activeEffect = null
}
track代码示例
let targetMap = new WeakMap()
export function track(target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}
dep.add(activeEffect)
}
tigger代码示例
export function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const dep = depsMap.get(key)
if(dep){
dep.forEach(effect=>{
effect()
})
}
}
收集依赖
Reactive 和 ref的区别
-
ref可以把基本数据类型数据,转成响应式对象
-
ref返回的对象,重新赋值成对象也是响应式的
-
reactive返回的对象,重新赋值丢失响应式
-
reactive返回的对象不可以解构
reactive的页面实现
import { reactive,effect } from './reactivity/index.js'
const product=reactive({
name:'iphone',
price:'5800',
count:3
})
let total=0
effect(()=>{
total=product.price*product.count
})
console.log('1:'+total)
product.price=4000
console.log('2:'+total)
product.count=1
console.log('3:'+total)
ref的页面实现
import { reactive,effect,ref } from './reactivity/index.js'
const price=ref(5000)
const count=ref(3)
let total=0
effect(()=>{
total=price.value*count.value
})
console.log('1:'+total)
price.value=4000
console.log('2:'+total)
count.value=1
console.log('3:'+total)
如果一个对象成员多的时候使用ref不方便,因为要总要加value,如果只有一个响应式数据的时候用ref,可以直接解构返回
Torefs页面的实现
import { reactive,effect,toRefs } from './reactivity/index.js'
function useProduct(){
const product=reactive({
name:'iphone',
price:'5800',
count:3
})
return toRefs(product)
}
const { price,count }=useProduct()
let total=0
effect(()=>{
total=price.value*count.value
})
console.log('1:'+total)
price.value=4000
console.log('2:'+total)
count.value=1
console.log('3:'+total)
Torefs把reactive返回的对象的每一个属性转换成类似ref返回的对象,可以对reactive返回的对象进行解构
index.js的代码
const isObject = val => val != null && typeof val === 'object'
const convert = target => isObject(target) ? reactive(target) : target
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target, key) => hasOwnProperty.call(target, key)
export function reactive(target) {
if (!isObject(target)) return target
const handler = {
get(target, key, receiver) {
//收集依赖
track(target, key)
// console.log('get', key)
const result = Reflect.get(target, key, receiver)
return convert(result)
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver)
let result = true
if (oldValue !== value) {
result = Reflect.set(target, key, value, receiver)
//触发更新
trigger(target,key)
//console.log('set', key, value)
}
return result
},
deleteProperty(target, key) {
const hadkey = hasOwn(target, key)
const result = Reflect.deleteProperty(target, key)
if (hadkey && result) {
// 触发更新
trigger(target,key)
// console.log('delete', key)
}
return result
}
}
return new Proxy(target, handler)
}
let activeEffect = null
export function effect(callback) {
activeEffect = callback
callback()//访问响应式对象属性,去收集依赖
activeEffect = null
}
let targetMap = new WeakMap()
export function track(target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}
dep.add(activeEffect)
}
export function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const dep = depsMap.get(key)
if(dep){
dep.forEach(effect=>{
effect()
})
}
}
export function ref(raw){
// 判断raw是否是ref创建的对象,如果是的话直接返回
if(isObject(raw) &&raw._v_isRef){
return
}
let value=convert(raw)
const r={
_v_isRef:true,
get value(){
track(r,value)
return value
},
set value(newValue){
if(newValue!==value){
raw=newValue
value=convert(raw)
trigger(r,'value')
}
}
}
return r
}
export function toRefs(proxy){
const ret =proxy instanceof Array?new Array(proxy.length):{}
for(const key in proxy){
ret[key]=toProxyRef(proxy,key)
}
return ret
}
function toProxyRef (proxy, key) {
const r = {
__v_isRef: true,
get value () {
return proxy[key]
},
set value (newValue) {
proxy[key] = newValue
}
}
return r
}
export function computed(getter){
const result =ref()
effect(()=>(result.value=getter()))
return result
}