feat: dot-delimited path for watch

This commit is contained in:
Evan You 2018-09-24 21:52:27 -04:00
parent a848466f07
commit 296164c207
2 changed files with 33 additions and 2 deletions

View File

@ -1,4 +1,4 @@
import { EMPTY_OBJ } from './utils'
import { EMPTY_OBJ, NOOP } from './utils'
import { MountedComponent } from './component'
import { ComponentWatchOptions, WatchOptions } from './componentOptions'
import { autorun, stop } from '@vue/observer'
@ -36,9 +36,17 @@ export function setupWatcher(
const rawGetter =
typeof keyOrFn === 'string'
? () => proxy[keyOrFn]
? parseDotPath(keyOrFn, proxy)
: () => keyOrFn.call(proxy)
if (__DEV__ && rawGetter === NOOP) {
console.warn(
`Failed watching expression: "${keyOrFn}". ` +
`Watch expressions can only be dot-delimited paths. ` +
`For more complex expressions, use $watch with a function instead.`
)
}
const getter = options.deep ? () => traverse(rawGetter()) : rawGetter
let oldValue: any
@ -85,6 +93,27 @@ export function teardownWatch(instance: MountedComponent) {
}
}
const bailRE = /[^\w.$]/
function parseDotPath(path: string, ctx: any): Function {
if (bailRE.test(path)) {
return NOOP
}
const segments = path.split('.')
if (segments.length === 1) {
return () => ctx[path]
} else {
return () => {
let obj = ctx
for (let i = 0; i < segments.length; i++) {
if (!obj) return
obj = obj[segments[i]]
}
return obj
}
}
}
function traverse(value: any, seen: Set<any> = new Set()) {
if (value === null || typeof value !== 'object' || seen.has(value)) {
return

View File

@ -1,5 +1,7 @@
export const EMPTY_OBJ: { readonly [key: string]: any } = Object.freeze({})
export const NOOP = () => {}
export const isReservedProp = (key: string): boolean => {
switch (key) {
case 'key':