From 2e3ffcb5a45a39fbe313a8d320bb37cea55f3671 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Mon, 4 Jul 2016 03:28:59 +0900 Subject: [PATCH] fix $refs updateing ref: #3204 --- src/compiler/compile.js | 4 +- src/directives/public/for.js | 21 +----- src/directives/public/if.js | 28 +++++++- src/util/dom.js | 18 +++++ test/unit/specs/directives/public/if_spec.js | 73 ++++++++++++++++++++ 5 files changed, 122 insertions(+), 22 deletions(-) diff --git a/src/compiler/compile.js b/src/compiler/compile.js index c53967dd52d..90087939119 100644 --- a/src/compiler/compile.js +++ b/src/compiler/compile.js @@ -665,8 +665,8 @@ function makeTerminalNodeLinkFn (el, dirName, value, options, def, rawName, arg, modifiers: modifiers, def: def } - // check ref for v-for and router-view - if (dirName === 'for' || dirName === 'router-view') { + // check ref for v-for, v-if and router-view + if (dirName === 'for' || dirName === 'if' || dirName === 'router-view') { descriptor.ref = findRef(el) } var fn = function terminalNodeLinkFn (vm, el, host, scope, frag) { diff --git a/src/directives/public/for.js b/src/directives/public/for.js index 9713208a1a1..f8af46cbbab 100644 --- a/src/directives/public/for.js +++ b/src/directives/public/for.js @@ -16,7 +16,8 @@ import { def, cancellable, isArray, - isPlainObject + isPlainObject, + findVmFromFrag } from '../../util/index' let uid = 0 @@ -602,24 +603,6 @@ function findPrevFrag (frag, anchor, id) { return frag } -/** - * Find a vm from a fragment. - * - * @param {Fragment} frag - * @return {Vue|undefined} - */ - -function findVmFromFrag (frag) { - let node = frag.node - // handle multi-node frag - if (frag.end) { - while (!node.__vue__ && node !== frag.end && node.nextSibling) { - node = node.nextSibling - } - } - return node.__vue__ -} - /** * Create a range array from given number. * diff --git a/src/directives/public/if.js b/src/directives/public/if.js index 324e548ff9b..8485dc6b83e 100644 --- a/src/directives/public/if.js +++ b/src/directives/public/if.js @@ -5,7 +5,8 @@ import { remove, replace, createAnchor, - warn + warn, + findVmFromFrag } from '../../util/index' export default { @@ -40,8 +41,10 @@ export default { if (value) { if (!this.frag) { this.insert() + this.updateRef(value) } } else { + this.updateRef(value) this.remove() } }, @@ -76,6 +79,29 @@ export default { } }, + updateRef (value) { + var ref = this.descriptor.ref + if (!ref) return + var hash = (this.vm || this._scope).$refs + var refs = hash[ref] + var key = this._frag.scope.$key + if (!refs) return + if (value) { + if (Array.isArray(refs)) { + refs.push(findVmFromFrag(this._frag)) + } else { + refs[key] = findVmFromFrag(this._frag) + } + } else { + if (Array.isArray(refs)) { + refs.$remove(findVmFromFrag(this._frag)) + } else { + refs[key] = null + delete refs[key] + } + } + }, + unbind () { if (this.frag) { this.frag.destroy() diff --git a/src/util/dom.js b/src/util/dom.js index 26382953e0a..38f43f72ada 100644 --- a/src/util/dom.js +++ b/src/util/dom.js @@ -449,3 +449,21 @@ export function getOuterHTML (el) { return container.innerHTML } } + +/** + * Find a vm from a fragment. + * + * @param {Fragment} frag + * @return {Vue|undefined} + */ + +export function findVmFromFrag (frag) { + let node = frag.node + // handle multi-node frag + if (frag.end) { + while (!node.__vue__ && node !== frag.end && node.nextSibling) { + node = node.nextSibling + } + } + return node.__vue__ +} diff --git a/test/unit/specs/directives/public/if_spec.js b/test/unit/specs/directives/public/if_spec.js index f9d28fc9f72..91f0aec4c0d 100644 --- a/test/unit/specs/directives/public/if_spec.js +++ b/test/unit/specs/directives/public/if_spec.js @@ -432,4 +432,77 @@ describe('v-if', function () { done() }) }) + + // GitHub issue #3204 + it('update array refs', function (done) { + var vm = new Vue({ + el: el, + template: '', + data: { + items: [0, 1, 2], + activeItem: null + }, + components: { + foo: { + props: ['index'], + template: '
I am foo ({{ index }})
' + } + } + }) + vm.$refs.foo.forEach(function (ref, index) { + expect(ref.$el.textContent).toBe('I am foo (' + index + ')') + expect(ref.index).toBe(index) + }) + vm.activeItem = 1 // select active item + nextTick(function () { + expect(vm.$refs.foo.length).toBe(1) + expect(vm.$refs.foo[0].index).toBe(1) + vm.activeItem = null // enable all elements + nextTick(function () { + expect(vm.$refs.foo.length).toBe(3) + done() + }) + }) + }) + + it('update object refs', function (done) { + var vm = new Vue({ + el: el, + template: '', + data: { + items: { + a: 1, + b: 2, + c: 3 + }, + activeKey: null + }, + components: { + foo: { + props: ['key'], + template: '
I am foo ({{ key }})
' + } + } + }) + Object.keys(vm.$refs.foo).forEach(function (key) { + var ref = vm.$refs.foo[key] + expect(ref.$el.textContent).toBe('I am foo (' + key + ')') + expect(ref.key).toBe(key) + }) + vm.activeKey = 'b' // select active item + nextTick(function () { + expect(Object.keys(vm.$refs.foo).length).toBe(1) + expect(vm.$refs.foo['b'].key).toBe('b') + vm.activeKey = null // enable all elements + nextTick(function () { + expect(Object.keys(vm.$refs.foo).length).toBe(3) + Object.keys(vm.$refs.foo).forEach(function (key) { + var ref = vm.$refs.foo[key] + expect(ref.$el.textContent).toBe('I am foo (' + key + ')') + expect(ref.key).toBe(key) + }) + done() + }) + }) + }) })