diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index bf3a5fd..9f30aa9 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -41,6 +41,7 @@ export class ReactiveEffect { activeEffect = this return this.fn() //完成第一次getter行为的触发 } + stop() {} } /** diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index 7964e45..0ce2c70 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -1,4 +1,4 @@ -export { reactive } from './reactive' -export { effect } from './effect' +export { reactive, isReactive } from './reactive' +export { effect, ReactiveEffect } from './effect' export { ref } from './ref' export { computed } from './computed' diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index 2ed7ec0..e585f1e 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -8,6 +8,10 @@ import { isObject } from '@vue/shared' */ export const reactiveMap = new WeakMap() +export const enum ReactiveFlags { + IS_REACTIVE = '__v_isReactive' +} + /** * 为复杂数据类型, 创建响应式对象 * @param target 被代理的对象 @@ -35,7 +39,8 @@ function createReactiveObject( } //未被代理则生成proxy实例 const proxy = new Proxy(target, baseHandlers) - + //添加reactive标识 + proxy[ReactiveFlags.IS_REACTIVE] = true //缓存代理对象 proxyMap.set(target, proxy) return proxy @@ -43,3 +48,7 @@ function createReactiveObject( export const toReactive = (value: T): T => isObject(value) ? reactive(value as object) : value + +export function isReactive(value): boolean { + return !!(value && value[ReactiveFlags.IS_REACTIVE]) +} diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts new file mode 100644 index 0000000..7a5e5c4 --- /dev/null +++ b/packages/runtime-core/src/apiWatch.ts @@ -0,0 +1,60 @@ +import { EMPTY_OBJ, hasChanged } from '@vue/shared' +import { isReactive, ReactiveEffect } from '@vue/reactivity' +import { queuePreFlushCb } from '@vue/runtime-core' + +export interface WatchOptions { + immediate?: immediate + deep?: boolean +} + +export function watch(source, cb: Function, options?: WatchOptions) { + return doWatch(source, cb, options) +} + +function doWatch( + source, + cb: Function, + { immediate, deep }: WatchOptions = EMPTY_OBJ +) { + let getter: () => any + if (isReactive(source)) { + getter = () => source + deep = true + } else { + getter = () => {} + } + //处理deep的状态 + if (cb && deep) { + //todo + //浅拷贝的形式--指向同样的内存空间 + const baseGetter = getter + getter = () => baseGetter() + } + + let oldValue = {} + //每次执行等同于watch被触发一次 + const job = () => { + if (cb) { + const newValue = effect.run() + if (deep || hasChanged(newValue, oldValue)) { + cb(newValue, oldValue) + oldValue = newValue + } + } + } + //调度器 + let scheduler = () => queuePreFlushCb(job) + const effect = new ReactiveEffect(getter, scheduler) + if (cb) { + if (immediate) { + job() + } else { + oldValue = effect.run() + } + } else { + effect.run() + } + return () => { + effect.stop() + } +} diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index a3a2657..c1885a8 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -1 +1,2 @@ export { queuePreFlushCb } from './scheduler' +export { watch } from './apiWatch' diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 5494e3b..f740520 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -15,3 +15,5 @@ export const isFunction = (val: unknown): val is Function => { } export const extend = Object.assign + +export const EMPTY_OBJ: { readonly [key: string]: any } = {} diff --git a/packages/vue/examples/reactivity/watch.html b/packages/vue/examples/reactivity/watch.html new file mode 100644 index 0000000..1340c0f --- /dev/null +++ b/packages/vue/examples/reactivity/watch.html @@ -0,0 +1,26 @@ + + + + + Document + + + +
+ + + \ No newline at end of file diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index 8fb36c5..08ac420 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -1,2 +1,2 @@ export { reactive, effect, ref, computed } from '@vue/reactivity' -export { queuePreFlushCb } from '@vue/runtime-core' +export { queuePreFlushCb, watch } from '@vue/runtime-core'