Przeglądaj źródła

support setting non-existent dynamic path e.g. "a[b]"

Evan You 11 lat temu
rodzic
commit
34da031bdc

+ 7 - 0
src/api/data.js

@@ -1,3 +1,4 @@
+var _ = require('../util')
 var Watcher = require('../watcher')
 var Path = require('../parsers/path')
 var textParser = require('../parsers/text')
@@ -43,6 +44,12 @@ exports.$set = function (exp, val) {
  */
 
 exports.$add = function (key, val) {
+  _.warn(
+    'You are dynamically adding a property "' + key + '" to ' +
+    'a vm instance. Consider pre-initializing the property ' +
+    'with the "data" option for more reliable reactivity ' +
+    'and better performance.'
+  )
   this._data.$add(key, val)
 }
 

+ 1 - 1
src/parsers/expression.js

@@ -24,7 +24,7 @@ var wsRE = /\s/g
 var newlineRE = /\n/g
 var saveRE = /[\{,]\s*[\w\$_]+\s*:|('[^']*'|"[^"]*")|new |typeof |void /g
 var restoreRE = /"(\d+)"/g
-var pathTestRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\])*$/
+var pathTestRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/
 var pathReplaceRE = /[^\w$\.]([A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\])*)/g
 var booleanLiteralRE = /^(true|false)$/
 

+ 29 - 16
src/parsers/path.js

@@ -34,7 +34,8 @@ var pathStateMachine = {
     'ws': ['inPath', 'push'],
     '.': ['beforeIdent', 'push'],
     '[': ['beforeElement', 'push'],
-    'eof': ['afterPath', 'push']
+    'eof': ['afterPath', 'push'],
+    ']': ['inPath', 'push']
   },
 
   'beforeElement': {
@@ -42,7 +43,8 @@ var pathStateMachine = {
     '0': ['afterZero', 'append'],
     'number': ['inIndex', 'append'],
     "'": ['inSingleQuote', 'append', ''],
-    '"': ['inDoubleQuote', 'append', '']
+    '"': ['inDoubleQuote', 'append', ''],
+    "ident": ['inIdent', 'append', '*']
   },
 
   'afterZero': {
@@ -189,9 +191,12 @@ function parsePath (path) {
 
     mode = transition[0]
     action = actions[transition[1]] || noop
-    newChar = transition[2] === undefined
+    newChar = transition[2]
+    newChar = newChar === undefined
       ? c
-      : transition[2]
+      : newChar === '*'
+        ? newChar + c
+        : newChar
     action()
 
     if (mode === 'afterPath') {
@@ -207,11 +212,13 @@ function parsePath (path) {
  * @return {Boolean}
  */
 
-function formatAccessor(key) {
+function formatAccessor (key) {
   if (identRE.test(key)) { // identifier
     return '.' + key
   } else if (+key === key >>> 0) { // bracket index
     return '[' + key + ']'
+  } else if (key.charAt(0) === '*') {
+    return '[o' + formatAccessor(key.slice(1)) + ']'
   } else { // bracket string
     return '["' + key.replace(/"/g, '\\"') + '"]'
   }
@@ -272,6 +279,7 @@ exports.get = function (obj, path) {
  */
 
 exports.set = function (obj, path, val) {
+  var original = obj
   if (typeof path === 'string') {
     path = exports.parse(path)
   }
@@ -279,20 +287,25 @@ exports.set = function (obj, path, val) {
     return false
   }
   var last, key
-  for (var i = 0, l = path.length - 1; i < l; i++) {
+  for (var i = 0, l = path.length; i < l; i++) {
     last = obj
     key = path[i]
-    obj = obj[key]
-    if (!_.isObject(obj)) {
-      obj = {}
-      last.$add(key, obj)
+    if (key.charAt(0) === '*') {
+      key = original[key.slice(1)]
+    }
+    if (i < l - 1) {
+      obj = obj[key]
+      if (!_.isObject(obj)) {
+        obj = {}
+        last.$add(key, obj)
+      }
+    } else {
+      if (key in obj) {
+        obj[key] = val
+      } else {
+        obj.$add(key, val)
+      }
     }
-  }
-  key = path[i]
-  if (key in obj) {
-    obj[key] = val
-  } else {
-    obj.$add(key, val)
   }
   return true
 }

+ 5 - 0
test/unit/specs/api/data_spec.js

@@ -40,6 +40,11 @@ describe('Data API', function () {
     // setting unexisting
     vm.$set('c.d', 2)
     expect(vm.c.d).toBe(2)
+    // warn against setting unexisting
+    expect(hasWarned(_, 'Consider pre-initializing')).toBe(true)
+  })
+
+  it('$set invalid', function () {
     // invalid, should throw
     if (leftHandThrows()) {
       // if creating a function with invalid left hand