]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: dot-delimited path for watch
authorEvan You <yyx990803@gmail.com>
Tue, 25 Sep 2018 01:52:27 +0000 (21:52 -0400)
committerEvan You <yyx990803@gmail.com>
Tue, 25 Sep 2018 01:52:27 +0000 (21:52 -0400)
packages/core/src/componentWatch.ts
packages/core/src/utils.ts

index 17a9eb12b1248fa7be800255e4c43cc125b8efc3..b86e5d9951f2efbb09c10a9c082cc19686f50ddd 100644 (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
index 7ea9151cda206944a4c317743192f7fe9b174352..7b5011de47117a1e9738547024135befaa245f44 100644 (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':