Skip to content

Commit c17e387

Browse files
kazuponyyx990803
authored andcommitted
fix $refs updateing (vuejs#3217)
ref: vuejs#3204
1 parent bbe09df commit c17e387

File tree

5 files changed

+122
-22
lines changed

5 files changed

+122
-22
lines changed

src/compiler/compile.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,8 +665,8 @@ function makeTerminalNodeLinkFn (el, dirName, value, options, def, rawName, arg,
665665
modifiers: modifiers,
666666
def: def
667667
}
668-
// check ref for v-for and router-view
669-
if (dirName === 'for' || dirName === 'router-view') {
668+
// check ref for v-for, v-if and router-view
669+
if (dirName === 'for' || dirName === 'if' || dirName === 'router-view') {
670670
descriptor.ref = findRef(el)
671671
}
672672
var fn = function terminalNodeLinkFn (vm, el, host, scope, frag) {

src/directives/public/for.js

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616
def,
1717
cancellable,
1818
isArray,
19-
isPlainObject
19+
isPlainObject,
20+
findVmFromFrag
2021
} from '../../util/index'
2122

2223
let uid = 0
@@ -602,24 +603,6 @@ function findPrevFrag (frag, anchor, id) {
602603
return frag
603604
}
604605

605-
/**
606-
* Find a vm from a fragment.
607-
*
608-
* @param {Fragment} frag
609-
* @return {Vue|undefined}
610-
*/
611-
612-
function findVmFromFrag (frag) {
613-
let node = frag.node
614-
// handle multi-node frag
615-
if (frag.end) {
616-
while (!node.__vue__ && node !== frag.end && node.nextSibling) {
617-
node = node.nextSibling
618-
}
619-
}
620-
return node.__vue__
621-
}
622-
623606
/**
624607
* Create a range array from given number.
625608
*

src/directives/public/if.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
remove,
66
replace,
77
createAnchor,
8-
warn
8+
warn,
9+
findVmFromFrag
910
} from '../../util/index'
1011

1112
export default {
@@ -40,8 +41,10 @@ export default {
4041
if (value) {
4142
if (!this.frag) {
4243
this.insert()
44+
this.updateRef(value)
4345
}
4446
} else {
47+
this.updateRef(value)
4548
this.remove()
4649
}
4750
},
@@ -76,6 +79,29 @@ export default {
7679
}
7780
},
7881

82+
updateRef (value) {
83+
var ref = this.descriptor.ref
84+
if (!ref) return
85+
var hash = (this.vm || this._scope).$refs
86+
var refs = hash[ref]
87+
var key = this._frag.scope.$key
88+
if (!refs) return
89+
if (value) {
90+
if (Array.isArray(refs)) {
91+
refs.push(findVmFromFrag(this._frag))
92+
} else {
93+
refs[key] = findVmFromFrag(this._frag)
94+
}
95+
} else {
96+
if (Array.isArray(refs)) {
97+
refs.$remove(findVmFromFrag(this._frag))
98+
} else {
99+
refs[key] = null
100+
delete refs[key]
101+
}
102+
}
103+
},
104+
79105
unbind () {
80106
if (this.frag) {
81107
this.frag.destroy()

src/util/dom.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,3 +449,21 @@ export function getOuterHTML (el) {
449449
return container.innerHTML
450450
}
451451
}
452+
453+
/**
454+
* Find a vm from a fragment.
455+
*
456+
* @param {Fragment} frag
457+
* @return {Vue|undefined}
458+
*/
459+
460+
export function findVmFromFrag (frag) {
461+
let node = frag.node
462+
// handle multi-node frag
463+
if (frag.end) {
464+
while (!node.__vue__ && node !== frag.end && node.nextSibling) {
465+
node = node.nextSibling
466+
}
467+
}
468+
return node.__vue__
469+
}

test/unit/specs/directives/public/if_spec.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,4 +432,77 @@ describe('v-if', function () {
432432
done()
433433
})
434434
})
435+
436+
// GitHub issue #3204
437+
it('update array refs', function (done) {
438+
var vm = new Vue({
439+
el: el,
440+
template: '<foo v-if="!activeItem || $index === activeItem" v-ref:foo :index="$index" v-for="item in items"></foo>',
441+
data: {
442+
items: [0, 1, 2],
443+
activeItem: null
444+
},
445+
components: {
446+
foo: {
447+
props: ['index'],
448+
template: '<div>I am foo ({{ index }})<div>'
449+
}
450+
}
451+
})
452+
vm.$refs.foo.forEach(function (ref, index) {
453+
expect(ref.$el.textContent).toBe('I am foo (' + index + ')')
454+
expect(ref.index).toBe(index)
455+
})
456+
vm.activeItem = 1 // select active item
457+
nextTick(function () {
458+
expect(vm.$refs.foo.length).toBe(1)
459+
expect(vm.$refs.foo[0].index).toBe(1)
460+
vm.activeItem = null // enable all elements
461+
nextTick(function () {
462+
expect(vm.$refs.foo.length).toBe(3)
463+
done()
464+
})
465+
})
466+
})
467+
468+
it('update object refs', function (done) {
469+
var vm = new Vue({
470+
el: el,
471+
template: '<foo v-if="!activeKey || $key === activeKey" v-ref:foo :key="$key" v-for="item in items"></foo>',
472+
data: {
473+
items: {
474+
a: 1,
475+
b: 2,
476+
c: 3
477+
},
478+
activeKey: null
479+
},
480+
components: {
481+
foo: {
482+
props: ['key'],
483+
template: '<div>I am foo ({{ key }})<div>'
484+
}
485+
}
486+
})
487+
Object.keys(vm.$refs.foo).forEach(function (key) {
488+
var ref = vm.$refs.foo[key]
489+
expect(ref.$el.textContent).toBe('I am foo (' + key + ')')
490+
expect(ref.key).toBe(key)
491+
})
492+
vm.activeKey = 'b' // select active item
493+
nextTick(function () {
494+
expect(Object.keys(vm.$refs.foo).length).toBe(1)
495+
expect(vm.$refs.foo['b'].key).toBe('b')
496+
vm.activeKey = null // enable all elements
497+
nextTick(function () {
498+
expect(Object.keys(vm.$refs.foo).length).toBe(3)
499+
Object.keys(vm.$refs.foo).forEach(function (key) {
500+
var ref = vm.$refs.foo[key]
501+
expect(ref.$el.textContent).toBe('I am foo (' + key + ')')
502+
expect(ref.key).toBe(key)
503+
})
504+
done()
505+
})
506+
})
507+
})
435508
})

0 commit comments

Comments
 (0)