Skip to content

Commit 6af5db6

Browse files
committed
allow referencing host with ref inside transclusion content (close #1147)
1 parent cf0339d commit 6af5db6

File tree

5 files changed

+57
-35
lines changed

5 files changed

+57
-35
lines changed

src/directives/component.js

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ module.exports = {
9696
}
9797
}
9898
}
99-
var child = this.build(options)
100-
this.setCurrent(child)
99+
var child = this.childVM = this.build(options)
101100
if (!this.waitForEvent) {
102101
if (activateHook) {
103102
activateHook.call(child, insert)
@@ -142,7 +141,7 @@ module.exports = {
142141
// just remove current
143142
this.unbuild(true)
144143
this.remove(this.childVM, cb)
145-
this.unsetCurrent()
144+
this.childVM = null
146145
} else {
147146
this.resolveComponent(value, _.bind(function () {
148147
this.unbuild(true)
@@ -227,6 +226,7 @@ module.exports = {
227226
// if no inline-template, then the compiled
228227
// linker can be cached for better performance.
229228
_linkerCachable: !this.inlineTemplate,
229+
_ref: this.ref,
230230
_asComponent: true,
231231
_isRouterView: this._isRouterView,
232232
// if this is a transcluded component, context
@@ -339,7 +339,7 @@ module.exports = {
339339
transition: function (target, cb) {
340340
var self = this
341341
var current = this.childVM
342-
this.setCurrent(target)
342+
this.childVM = target
343343
switch (self.transMode) {
344344
case 'in-out':
345345
target.$before(self.anchor, function () {
@@ -357,32 +357,6 @@ module.exports = {
357357
}
358358
},
359359

360-
/**
361-
* Set childVM and parent ref
362-
*/
363-
364-
setCurrent: function (child) {
365-
this.unsetCurrent()
366-
this.childVM = child
367-
var ref = child._refId || this.ref
368-
if (ref) {
369-
(this._scope || this.vm).$[ref] = child
370-
}
371-
},
372-
373-
/**
374-
* Unset childVM and parent ref
375-
*/
376-
377-
unsetCurrent: function () {
378-
var child = this.childVM
379-
this.childVM = null
380-
var ref = (child && child._refId) || this.ref
381-
if (ref) {
382-
(this._scope || this.vm).$[ref] = null
383-
}
384-
},
385-
386360
/**
387361
* Unbind.
388362
*/
@@ -391,7 +365,6 @@ module.exports = {
391365
this.invalidatePending()
392366
// Do not defer cleanup when unbinding
393367
this.unbuild()
394-
this.unsetCurrent()
395368
// destroy all keep-alive cached instances
396369
if (this.cache) {
397370
for (var key in this.cache) {

src/directives/ref.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,21 @@ module.exports = {
1414
}
1515
// If we get here, it means this is a `v-ref` on a
1616
// child, because parent scope `v-ref` is stripped in
17-
// `v-component` already. So we just record our own ref
18-
// here - it will overwrite parent ref in `v-component`,
19-
// if any.
20-
vm._refId = this.expression
17+
// `v-component` already.
18+
var ref = this.expression
19+
var context = this.vm._scope || this.vm._context
20+
context.$[ref] = this.vm
2121

2222
if (process.env.NODE_ENV !== 'production') {
2323
_.deprecation.REF_IN_CHILD()
2424
}
25+
},
26+
27+
unbind: function () {
28+
var ref = this.expression
29+
var context = this.vm._scope || this.vm._context
30+
if (context.$[ref] === this.vm) {
31+
context.$[ref] = null
32+
}
2533
}
2634
}

src/instance/init.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ exports._init = function (options) {
5959
// and container directives.
6060
this._scope = options._scope
6161

62+
// set ref
63+
if (options._ref) {
64+
(this._scope || this._context).$[options._ref] = this
65+
}
66+
6267
// fragment:
6368
// if this instance is compiled inside a Fragment, it
6469
// needs to reigster itself as a child of that fragment

src/instance/lifecycle.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ exports._destroy = function (remove, deferCleanup) {
157157
while (i--) {
158158
this._watchers[i].teardown()
159159
}
160+
// unregister ref
161+
var ref = this.$options._ref
162+
if (ref) {
163+
var scope = this._scope || this._context
164+
if (scope.$[ref] === this) {
165+
scope.$[ref] = null
166+
}
167+
}
160168
// remove reference to self on $el
161169
if (this.$el) {
162170
this.$el.__vue__ = null
@@ -197,6 +205,8 @@ exports._cleanup = function () {
197205
this.$root =
198206
this.$children =
199207
this._watchers =
208+
this._context =
209+
this._scope =
200210
this._directives = null
201211
// call the last hook...
202212
this._isDestroyed = true

test/unit/specs/directives/ref_spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,32 @@ if (_.inBrowser) {
8989
})
9090
})
9191
})
92+
93+
// #1147
94+
it('should be able to reference host via ref inside transclusion content', function (done) {
95+
var vm = new Vue({
96+
el: el,
97+
template:
98+
'<div>' +
99+
'<comp ref="out">{{$.out.msg}}</comp>' +
100+
'</div>',
101+
components: {
102+
comp: {
103+
template: '<slot></slot>',
104+
data: function () {
105+
return { msg: 'hi' }
106+
}
107+
}
108+
}
109+
})
110+
expect(_.warn).not.toHaveBeenCalled()
111+
expect(vm.$el.textContent).toBe('hi')
112+
vm.$children[0].msg = 'ho'
113+
_.nextTick(function () {
114+
expect(vm.$el.textContent).toBe('ho')
115+
done()
116+
})
117+
})
92118

93119
it('should also work in child template', function (done) {
94120
var vm = new Vue({

0 commit comments

Comments
 (0)