Skip to content

Commit ed0be36

Browse files
committed
clean up array diff algorithm
1 parent 6626d3b commit ed0be36

File tree

1 file changed

+56
-103
lines changed

1 file changed

+56
-103
lines changed

src/directives/repeat.js

Lines changed: 56 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -71,46 +71,34 @@ module.exports = {
7171
},
7272

7373
init: function (collection, isObject) {
74-
var vm, vms = [],
75-
data,
76-
ref = this.ref,
77-
ctn = this.container,
78-
init = this.compiler.init
74+
var vm, vms = []
7975
for (var i = 0, l = collection.length; i < l; i++) {
80-
if (isObject) {
81-
data = collection[i]
82-
data.$index = i
83-
} else {
84-
data = { $index: i }
85-
data.$value = collection[i]
86-
}
87-
vm = this.build(data, i, isObject)
76+
vm = this.build(collection[i], i, isObject)
8877
vms.push(vm)
89-
if (init) {
90-
ctn.insertBefore(vm.$el, ref)
78+
if (this.compiler.init) {
79+
this.container.insertBefore(vm.$el, this.ref)
9180
} else {
92-
vm.$before(ref)
81+
vm.$before(this.ref)
9382
}
9483
}
9584
return vms
9685
},
9786

9887
/**
9988
* Diff the new array with the old
100-
* and determine the minimum amount of DOM manipulations
89+
* and determine the minimum amount of DOM manipulations.
10190
*/
10291
diff: function (newCollection, isObject) {
10392

104-
var i, l, item, vm, oi, ni, wrapper, ref,
105-
ctn = this.container,
106-
oldVMs = this.oldVMs,
107-
alias = this.arg || '$value',
108-
OLD_REUSED = [],
109-
NEW_REUSED = [],
110-
NEW_DATA = [],
111-
FINAL = []
93+
var i, l, item, vm,
94+
oldIndex,
95+
targetNext,
96+
currentNext,
97+
ctn = this.container,
98+
oldVMs = this.oldVMs,
99+
vms = []
112100

113-
FINAL.length = newCollection.length
101+
vms.length = newCollection.length
114102

115103
// first pass, collect new reused and new created
116104
for (i = 0, l = newCollection.length; i < l; i++) {
@@ -120,22 +108,20 @@ module.exports = {
120108
if (item[this.identifier]) {
121109
// this piece of data is being reused.
122110
// record its final position in reused vms
123-
item.$newReuseIndex = NEW_REUSED.length++
111+
item.$reused = true
124112
} else {
125-
NEW_DATA.push(item)
113+
vms[i] = this.build(item, i, isObject)
126114
}
127115
} else {
128116
// we can't attach an identifier to primitive values
129-
// so have to do an indexOf
130-
oi = indexOf(oldVMs, item)
131-
if (oi > -1) {
117+
// so have to do an indexOf...
118+
oldIndex = indexOf(oldVMs, item)
119+
if (oldIndex > -1) {
132120
// record the position on the existing vm
133-
oldVMs[oi].$newReuseIndex = NEW_REUSED.length++
134-
oldVMs[oi].$data.$index = i
121+
oldVMs[oldIndex].$reused = true
122+
oldVMs[oldIndex].$data.$index = i
135123
} else {
136-
wrapper = { $index: i }
137-
wrapper[alias] = item
138-
NEW_DATA.push(wrapper)
124+
vms[i] = this.build(item, i, isObject)
139125
}
140126
}
141127
}
@@ -144,78 +130,60 @@ module.exports = {
144130
for (i = 0, l = oldVMs.length; i < l; i++) {
145131
vm = oldVMs[i]
146132
item = vm.$data
147-
ni = isObject
148-
? item.$newReuseIndex
149-
: vm.$newReuseIndex
150-
if (ni != null) {
151-
// this vm can be reused.
152-
vm.$newReuseIndex = ni
133+
if (item.$reused) {
134+
vm.$reused = true
135+
delete item.$reused
136+
}
137+
if (vm.$reused) {
153138
// update the index to latest
154139
vm.$index = item.$index
155140
// the item could have had a new key
156141
if (item.$key && item.$key !== vm.$key) {
157142
vm.$key = item.$key
158143
}
159-
NEW_REUSED[ni] = vm
160-
FINAL[vm.$index] = vm
161-
vm.$oldReuseIndex = OLD_REUSED.length
162-
OLD_REUSED.push(vm)
144+
vms[vm.$index] = vm
163145
} else {
164146
// this one can be destroyed.
165147
delete item[this.identifier]
166148
vm.$destroy()
167149
}
168150
}
169151

170-
// sort reused
171-
var targetNext,
172-
currentNext,
173-
moves = 0
174-
175-
i = NEW_REUSED.length
152+
// final pass, move/insert DOM elements
153+
i = vms.length
176154
while (i--) {
177-
vm = NEW_REUSED[i]
155+
vm = vms[i]
178156
item = vm.$data
179-
currentNext = vm.$el.nextSibling.vue_vm
180-
targetNext = NEW_REUSED[i + 1]
181-
if (currentNext !== targetNext) {
182-
moves++
183-
if (!targetNext) {
184-
ctn.insertBefore(vm.$el, this.ref)
185-
} else {
186-
ctn.insertBefore(vm.$el, targetNext.$el)
157+
targetNext = vms[i + 1]
158+
if (vm.$reused) {
159+
currentNext = vm.$el.nextSibling.vue_vm
160+
if (currentNext !== targetNext) {
161+
if (!targetNext) {
162+
ctn.insertBefore(vm.$el, this.ref)
163+
} else {
164+
ctn.insertBefore(vm.$el, targetNext.$el)
165+
}
187166
}
167+
delete vm.$reused
168+
delete item.$index
169+
delete item.$key
170+
} else { // a new vm
171+
vm.$before(targetNext ? targetNext.$el : this.ref)
188172
}
189-
delete vm.$newReuseIndex
190-
delete vm.$oldReuseIndex
191-
delete item.$newReuseIndex
192-
delete item.$index
193-
delete item.$key
194173
}
195174

196-
// create new
197-
for (i = 0, l = NEW_DATA.length; i < l; i++) {
198-
item = NEW_DATA[i]
199-
ni = item.$index
200-
vm = this.build(item, ni, isObject)
201-
ref = ni === FINAL.length - 1
202-
? this.ref
203-
: ni === 0
204-
? NEW_REUSED.length
205-
? NEW_REUSED[0].$el
206-
: this.ref
207-
: FINAL[ni - 1].$el.nextSibling
208-
vm.$before(ref)
209-
FINAL[ni] = vm
210-
}
211-
212-
console.log('moves: ' + moves)
213-
214-
return FINAL
175+
return vms
215176
},
216177

217178
build: function (data, index, isObject) {
218179

180+
// wrap non-object values
181+
if (!isObject || this.arg) {
182+
var raw = data
183+
data = { $index: index }
184+
data[this.arg || '$value'] = raw
185+
}
186+
219187
var el = this.el.cloneNode(true),
220188
Ctor = this.compiler.resolveComponent(el, data),
221189
vm = new Ctor({
@@ -245,29 +213,14 @@ module.exports = {
245213

246214
},
247215

248-
findVMByKey: function (key) {
249-
var i = this.vms.length, vm
250-
while (i--) {
251-
vm = this.vms[i]
252-
if (vm.$key === key) {
253-
return vm
254-
}
255-
}
256-
},
257-
258216
unbind: function () {
259217
if (this.childId) {
260218
delete this.vm.$[this.childId]
261219
}
262220
if (this.vms) {
263-
var i = vms.length, vm
221+
var i = this.vms.length
264222
while (i--) {
265-
vm = vms[i]
266-
if (vm.$reused) {
267-
delete vm.$reused
268-
} else {
269-
vm.$destroy()
270-
}
223+
this.vms[i].$destroy()
271224
}
272225
}
273226
}
@@ -282,7 +235,7 @@ module.exports = {
282235
function indexOf (vms, obj) {
283236
for (var vm, i = 0, l = vms.length; i < l; i++) {
284237
vm = vms[i]
285-
if (vm.$newReuseIndex == null && vm.$value === obj) {
238+
if (!vm.$reused && vm.$value === obj) {
286239
return i
287240
}
288241
}

0 commit comments

Comments
 (0)