前言
import { reactive } from 'vue';
const arr = reactive([1,2,3,4]);
console.log(arr); // 输出的是代理之后的 Proxy {0: 1, 1: 2, 2: 3, 3: 4}
ref 原理和使用方式
// 可以是对象的属性
export function ref<T extends object>(
value: T
): T extends Ref ? T : Ref<UnwrapRef<T>>
// 也可以是一个任意值
export function ref<T>(value: T): Ref<UnwrapRef<T>>
export function ref<T = any>(): Ref<T | undefined>
// ref的值是可选的,非必填项
export function ref(value?: unknown) {
return createRef(value)
}
import { ref } from 'vue';
const refParam = ref();
console.log(refParam) // 返回是一个RefImpl {_rawValue: undefined, _shallow: false, __v_isRef: true, _value: undefined}
// 如果是一个对象,则使用reactive做深度代理,否则直接返回
const convert = <T extends unknown>(val: T): T =>
isObject(val) ? reactive(val) : val
// shallow 用来表示是浅层代理还是深度代理
function createRef(rawValue: unknown, shallow = false) {
if (isRef(rawValue)) {
return rawValue
}
let value = shallow ? rawValue : convert(rawValue) // convert 如果是一个对象,则使用reactive做深度代理,否则直接返回
const r = {
__v_isRef: true,
get value() {
// 方法追踪
track(r, TrackOpTypes.GET, 'value')
return value
},
set value(newVal) {
// 判断新值和旧值是否是一致的,如果不是一致的就进行更新操作
if (hasChanged(toRaw(newVal), rawValue)) {
rawValue = newVal
value = shallow ? newVal : convert(newVal)
trigger(r, TriggerOpTypes.SET, 'value', newVal)
}
}
}
return r
}
computed 计算机属性3.0实现源码,与2.0版本的区别
// 返回的值是只读属性,并且是响应式
export function computed<T>(getter: ComputedGetter<T>): ComputedRef<T>
// 增加了计算机属性的读写操作
export function computed<T>(
options: WritableComputedOptions<T>
): WritableComputedRef<T>
// 参数可以是一个对象形式,也可以是一个方法
export function computed<T>(
// 参数是一个方法或者是一个对象参数,如果是方法执行只读,如果是对象可以操作读写
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>
) {
let getter: ComputedGetter<T>
let setter: ComputedSetter<T>
// 如果是方法的话,不可以修改属性值,读取,如果是一个对象的话,则可以操作读写功能
if (isFunction(getterOrOptions)) {
getter = getterOrOptions
setter = __DEV__
? () => {
console.warn('Write operation failed: computed value is readonly')
}
: NOOP
} else {
getter = getterOrOptions.get
setter = getterOrOptions.set
}
let dirty = true
let value: T
let computed: ComputedRef<T>
// effect 传进来一个getter,这个getter = 如果当前参数是一个方法,值直接赋值当前的function,否则赋值这个对象的get方法
const runner = effect(getter, {
lazy: true, // 懒执行
scheduler: () => {
if (!dirty) {
dirty = true
trigger(computed, TriggerOpTypes.SET, 'value')
}
}
})
computed = {
// 标记为这个是需要代理的响应式
__v_isRef: true,
// 是否是只读标记
[ReactiveFlags.IS_READONLY]:
isFunction(getterOrOptions) || !getterOrOptions.set,
// expose effect so computed can be stopped
effect: runner,
get value() {
if (dirty) {
value = runner()
dirty = false
}
track(computed, TrackOpTypes.GET, 'value')
return value
},
set value(newValue: T) {
setter(newValue)
}
} as any
return computed
}
// 只读模式操作
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误!
// 读写模式操作
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
},
})
plusOne.value = 1
console.log(count.value) // 0
reactive
// only unwrap nested ref
// 解嵌套
type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRef<T>
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version.
// 如果当前的目标对象存在并且是只读则直接返回当前对象
if (target && (target as Target)[ReactiveFlags.IS_READONLY]) {
return target
}
// 创建一个响应式对象
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers
)
}
function createReactiveObject(
target: Target, // 需要代理的目标对象
isReadonly: boolean, // 是不是只读对象
baseHandlers: ProxyHandler<any>, // 基础的处理方法
collectionHandlers: ProxyHandler<any> // 收集依赖
) {
if (!isObject(target)) {
if (__DEV__) {
console.warn(`value cannot be made reactive: ${String(target)}`)
}
return target
}
// target is already a Proxy, return it.
// exception: calling readonly() on a reactive object
// 当前对象是不是原始对象,并且是被代理过的只读对象
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
// target already has corresponding Proxy
// 如果已经有了对应的代理对象就返回这个代理的对象
const reactiveFlag = isReadonly
? ReactiveFlags.READONLY
: ReactiveFlags.REACTIVE
if (hasOwn(target, reactiveFlag)) {
return target[reactiveFlag]
}
// only a whitelist of value types can be observed.
if (!canObserve(target)) {
return target
}
const observed = new Proxy(
target,
collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers
)
def(target, reactiveFlag, observed)
return observed
}
export const isObject = (val: unknown): val is Record<any, any> =>
val !== null && typeof val === 'object'
通过上述的分析,我们不难看出,ref和reactive,computed的区别还是蛮大的;
今天的分享就到这了,如果有哪些地方说的不对,还望在下边的评论区发表出来,大家一起讨论;
如果想要体验vue3.0的同学也可以参考一下我的这篇文章vue3 学习 之 vue3使用
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!