Bläddra i källkod

add back support for non-standard literal keys in track-by

Evan You 10 år sedan
förälder
incheckning
767e623a9a
2 ändrade filer med 66 tillägg och 15 borttagningar
  1. 22 15
      src/directives/public/for.js
  2. 44 0
      test/unit/specs/directives/public/for/for_spec.js

+ 22 - 15
src/directives/public/for.js

@@ -403,11 +403,7 @@ const vFor = {
     var primitive = !isObject(value)
     var id
     if (key || trackByKey || primitive) {
-      id = trackByKey
-        ? trackByKey === '$index'
-          ? index
-          : getPath(value, trackByKey)
-        : (key || value)
+      id = getTrackByKey(index, key, value, trackByKey)
       if (!cache[id]) {
         cache[id] = frag
       } else if (trackByKey !== '$index') {
@@ -444,11 +440,7 @@ const vFor = {
     var primitive = !isObject(value)
     var frag
     if (key || trackByKey || primitive) {
-      var id = trackByKey
-        ? trackByKey === '$index'
-          ? index
-          : getPath(value, trackByKey)
-        : (key || value)
+      var id = getTrackByKey(index, key, value, trackByKey)
       frag = this.cache[id]
     } else {
       frag = value[this.id]
@@ -476,11 +468,7 @@ const vFor = {
     var key = hasOwn(scope, '$key') && scope.$key
     var primitive = !isObject(value)
     if (trackByKey || key || primitive) {
-      var id = trackByKey
-        ? trackByKey === '$index'
-          ? index
-          : getPath(value, trackByKey)
-        : (key || value)
+      var id = getTrackByKey(index, key, value, trackByKey)
       this.cache[id] = null
     } else {
       value[this.id] = null
@@ -635,6 +623,25 @@ function range (n) {
   return ret
 }
 
+/**
+ * Get the track by key for an item.
+ *
+ * @param {Number} index
+ * @param {String} key
+ * @param {*} value
+ * @param {String} [trackByKey]
+ */
+
+function getTrackByKey (index, key, value, trackByKey) {
+  return trackByKey
+    ? trackByKey === '$index'
+      ? index
+      : trackByKey.charAt(0).match(/\w/)
+        ? getPath(value, trackByKey)
+        : value[trackByKey]
+    : (key || value)
+}
+
 if (process.env.NODE_ENV !== 'production') {
   vFor.warnDuplicate = function (value) {
     warn(

+ 44 - 0
test/unit/specs/directives/public/for/for_spec.js

@@ -572,6 +572,50 @@ describe('v-for', function () {
     }
   })
 
+  it('track by non-standard id path', function (done) {
+    var vm = new Vue({
+      el: el,
+      template: '<test v-for="item in list" :item="item" track-by=".id"></test>',
+      data: {
+        list: [
+          { '.id': 1, msg: 'foo' },
+          { '.id': 2, msg: 'bar' },
+          { '.id': 3, msg: 'baz' }
+        ]
+      },
+      components: {
+        test: {
+          props: ['item'],
+          template: '{{item.msg}}'
+        }
+      }
+    })
+    assertMarkup()
+    var oldVms = vm.$children.slice()
+    // swap the data with different objects, but with
+    // the same ID!
+    vm.list = [
+      { '.id': 1, msg: 'qux' },
+      { '.id': 2, msg: 'quux' }
+    ]
+    _.nextTick(function () {
+      assertMarkup()
+      // should reuse old vms!
+      var i = 2
+      while (i--) {
+        expect(vm.$children[i]).toBe(oldVms[i])
+      }
+      done()
+    })
+
+    function assertMarkup () {
+      var markup = vm.list.map(function (item) {
+        return '<test>' + item.msg + '</test>'
+      }).join('')
+      expect(el.innerHTML).toBe(markup)
+    }
+  })
+
   it('track by $index', function (done) {
     var vm = new Vue({
       el: el,