fix(watch): this.$watch should support watching keypath

This commit is contained in:
Evan You 2021-04-07 16:19:04 -04:00
parent 0f2d8f3244
commit 870f2a7ba3
3 changed files with 49 additions and 13 deletions

View File

@ -915,4 +915,33 @@ describe('api: watch', () => {
// should not track b as dependency of Child
expect(updated).toHaveBeenCalledTimes(1)
})
test('watching keypath', async () => {
const spy = jest.fn()
const Comp = defineComponent({
render() {},
data() {
return {
a: {
b: 1
}
}
},
watch: {
'a.b': spy
},
created(this: any) {
this.$watch('a.b', spy)
},
mounted(this: any) {
this.a.b++
}
})
const root = nodeOps.createElement('div')
createApp(Comp).mount(root)
await nextTick()
expect(spy).toHaveBeenCalledTimes(2)
})
})

View File

@ -334,11 +334,24 @@ export function instanceWatch(
): WatchStopHandle {
const publicThis = this.proxy as any
const getter = isString(source)
? () => publicThis[source]
? source.includes('.')
? createPathGetter(publicThis, source)
: () => publicThis[source]
: source.bind(publicThis)
return doWatch(getter, cb.bind(publicThis), options, this)
}
export function createPathGetter(ctx: any, path: string) {
const segments = path.split('.')
return () => {
let cur = ctx
for (let i = 0; i < segments.length && cur; i++) {
cur = cur[segments[i]]
}
return cur
}
}
function traverse(value: unknown, seen: Set<unknown> = new Set()) {
if (!isObject(value) || seen.has(value)) {
return value

View File

@ -20,7 +20,12 @@ import {
isPromise
} from '@vue/shared'
import { computed } from './apiComputed'
import { watch, WatchOptions, WatchCallback } from './apiWatch'
import {
watch,
WatchOptions,
WatchCallback,
createPathGetter
} from './apiWatch'
import { provide, inject } from './apiInject'
import {
onBeforeMount,
@ -939,17 +944,6 @@ function createWatcher(
}
}
function createPathGetter(ctx: any, path: string) {
const segments = path.split('.')
return () => {
let cur = ctx
for (let i = 0; i < segments.length && cur; i++) {
cur = cur[segments[i]]
}
return cur
}
}
export function resolveMergedOptions(
instance: ComponentInternalInstance
): ComponentOptions {