feat(runtime-core): support array in watch option (#376)
This commit is contained in:
parent
a75077569e
commit
532b5eebd7
@ -175,6 +175,75 @@ describe('api: options', () => {
|
||||
assertCall(spyC, 1, [{ qux: 4 }, { qux: 4 }])
|
||||
})
|
||||
|
||||
test('watch array', async () => {
|
||||
function returnThis(this: any) {
|
||||
return this
|
||||
}
|
||||
const spyA = jest.fn(returnThis)
|
||||
const spyB = jest.fn(returnThis)
|
||||
const spyC = jest.fn(returnThis)
|
||||
|
||||
let ctx: any
|
||||
const Comp = {
|
||||
data() {
|
||||
return {
|
||||
foo: 1,
|
||||
bar: 2,
|
||||
baz: {
|
||||
qux: 3
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// string method name
|
||||
foo: ['onFooChange'],
|
||||
// direct function
|
||||
bar: [spyB],
|
||||
baz: [
|
||||
{
|
||||
handler: spyC,
|
||||
deep: true
|
||||
}
|
||||
]
|
||||
},
|
||||
methods: {
|
||||
onFooChange: spyA
|
||||
},
|
||||
render() {
|
||||
ctx = this
|
||||
}
|
||||
}
|
||||
const root = nodeOps.createElement('div')
|
||||
render(h(Comp), root)
|
||||
|
||||
function assertCall(spy: jest.Mock, callIndex: number, args: any[]) {
|
||||
expect(spy.mock.calls[callIndex].slice(0, 2)).toMatchObject(args)
|
||||
}
|
||||
|
||||
assertCall(spyA, 0, [1, undefined])
|
||||
assertCall(spyB, 0, [2, undefined])
|
||||
assertCall(spyC, 0, [{ qux: 3 }, undefined])
|
||||
expect(spyA).toHaveReturnedWith(ctx)
|
||||
expect(spyB).toHaveReturnedWith(ctx)
|
||||
expect(spyC).toHaveReturnedWith(ctx)
|
||||
|
||||
ctx.foo++
|
||||
await nextTick()
|
||||
expect(spyA).toHaveBeenCalledTimes(2)
|
||||
assertCall(spyA, 1, [2, 1])
|
||||
|
||||
ctx.bar++
|
||||
await nextTick()
|
||||
expect(spyB).toHaveBeenCalledTimes(2)
|
||||
assertCall(spyB, 1, [3, 2])
|
||||
|
||||
ctx.baz.qux++
|
||||
await nextTick()
|
||||
expect(spyC).toHaveBeenCalledTimes(2)
|
||||
// new and old objects have same identity
|
||||
assertCall(spyC, 1, [{ qux: 4 }, { qux: 4 }])
|
||||
})
|
||||
|
||||
test('provide/inject', () => {
|
||||
const Root = {
|
||||
data() {
|
||||
|
@ -119,10 +119,14 @@ export type ExtractComputedReturns<T extends any> = {
|
||||
: ReturnType<T[key]>
|
||||
}
|
||||
|
||||
type ComponentWatchOptions = Record<
|
||||
string,
|
||||
string | WatchHandler | { handler: WatchHandler } & WatchOptions
|
||||
>
|
||||
type WatchOptionItem =
|
||||
| string
|
||||
| WatchHandler
|
||||
| { handler: WatchHandler } & WatchOptions
|
||||
|
||||
type ComponentWatchOptionItem = WatchOptionItem | WatchOptionItem[]
|
||||
|
||||
type ComponentWatchOptions = Record<string, ComponentWatchOptionItem>
|
||||
|
||||
type ComponentInjectOptions =
|
||||
| string[]
|
||||
@ -148,7 +152,6 @@ export interface LegacyOptions<
|
||||
data?: D | ((this: ComponentPublicInstance<Props>) => D)
|
||||
computed?: C
|
||||
methods?: M
|
||||
// TODO watch array
|
||||
watch?: ComponentWatchOptions
|
||||
provide?: Data | Function
|
||||
inject?: ComponentInjectOptions
|
||||
@ -318,23 +321,7 @@ export function applyOptions(
|
||||
}
|
||||
if (watchOptions) {
|
||||
for (const key in watchOptions) {
|
||||
const raw = watchOptions[key]
|
||||
const getter = () => ctx[key]
|
||||
if (isString(raw)) {
|
||||
const handler = renderContext[raw]
|
||||
if (isFunction(handler)) {
|
||||
watch(getter, handler as WatchHandler)
|
||||
} else if (__DEV__) {
|
||||
warn(`Invalid watch handler specified by key "${raw}"`, handler)
|
||||
}
|
||||
} else if (isFunction(raw)) {
|
||||
watch(getter, raw.bind(ctx))
|
||||
} else if (isObject(raw)) {
|
||||
// TODO 2.x compat
|
||||
watch(getter, raw.handler.bind(ctx), raw)
|
||||
} else if (__DEV__) {
|
||||
warn(`Invalid watch option: "${key}"`)
|
||||
}
|
||||
createWatcher(watchOptions[key], renderContext, ctx, key)
|
||||
}
|
||||
}
|
||||
if (provideOptions) {
|
||||
@ -448,3 +435,30 @@ function applyMixins(
|
||||
applyOptions(instance, mixins[i], true)
|
||||
}
|
||||
}
|
||||
|
||||
function createWatcher(
|
||||
raw: ComponentWatchOptionItem,
|
||||
renderContext: Data,
|
||||
ctx: ComponentPublicInstance,
|
||||
key: string
|
||||
) {
|
||||
const getter = () => ctx[key]
|
||||
if (isString(raw)) {
|
||||
const handler = renderContext[raw]
|
||||
if (isFunction(handler)) {
|
||||
watch(getter, handler as WatchHandler)
|
||||
} else if (__DEV__) {
|
||||
warn(`Invalid watch handler specified by key "${raw}"`, handler)
|
||||
}
|
||||
} else if (isFunction(raw)) {
|
||||
watch(getter, raw.bind(ctx))
|
||||
} else if (isObject(raw)) {
|
||||
if (isArray(raw)) {
|
||||
raw.forEach(r => createWatcher(r, renderContext, ctx, key))
|
||||
} else {
|
||||
watch(getter, raw.handler.bind(ctx), raw)
|
||||
}
|
||||
} else if (__DEV__) {
|
||||
warn(`Invalid watch option: "${key}"`)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user