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 }])
|
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', () => {
|
test('provide/inject', () => {
|
||||||
const Root = {
|
const Root = {
|
||||||
data() {
|
data() {
|
||||||
|
@ -119,10 +119,14 @@ export type ExtractComputedReturns<T extends any> = {
|
|||||||
: ReturnType<T[key]>
|
: ReturnType<T[key]>
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComponentWatchOptions = Record<
|
type WatchOptionItem =
|
||||||
string,
|
| string
|
||||||
string | WatchHandler | { handler: WatchHandler } & WatchOptions
|
| WatchHandler
|
||||||
>
|
| { handler: WatchHandler } & WatchOptions
|
||||||
|
|
||||||
|
type ComponentWatchOptionItem = WatchOptionItem | WatchOptionItem[]
|
||||||
|
|
||||||
|
type ComponentWatchOptions = Record<string, ComponentWatchOptionItem>
|
||||||
|
|
||||||
type ComponentInjectOptions =
|
type ComponentInjectOptions =
|
||||||
| string[]
|
| string[]
|
||||||
@ -148,7 +152,6 @@ export interface LegacyOptions<
|
|||||||
data?: D | ((this: ComponentPublicInstance<Props>) => D)
|
data?: D | ((this: ComponentPublicInstance<Props>) => D)
|
||||||
computed?: C
|
computed?: C
|
||||||
methods?: M
|
methods?: M
|
||||||
// TODO watch array
|
|
||||||
watch?: ComponentWatchOptions
|
watch?: ComponentWatchOptions
|
||||||
provide?: Data | Function
|
provide?: Data | Function
|
||||||
inject?: ComponentInjectOptions
|
inject?: ComponentInjectOptions
|
||||||
@ -318,23 +321,7 @@ export function applyOptions(
|
|||||||
}
|
}
|
||||||
if (watchOptions) {
|
if (watchOptions) {
|
||||||
for (const key in watchOptions) {
|
for (const key in watchOptions) {
|
||||||
const raw = watchOptions[key]
|
createWatcher(watchOptions[key], renderContext, ctx, 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}"`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (provideOptions) {
|
if (provideOptions) {
|
||||||
@ -448,3 +435,30 @@ function applyMixins(
|
|||||||
applyOptions(instance, mixins[i], true)
|
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