Skip to content

Commit 8153977

Browse files
committed
hoist component binding
1 parent c29177f commit 8153977

File tree

7 files changed

+41
-20
lines changed

7 files changed

+41
-20
lines changed

src/compiler/compile.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,14 @@ exports.compile = function (el, options, partial) {
8686
function linkAndCapture (linker, vm) {
8787
var originalDirCount = vm._directives.length
8888
linker()
89-
return vm._directives.slice(originalDirCount)
89+
var dirs = vm._directives.slice(originalDirCount)
90+
for (var i = 0, l = dirs.length; i < l; i++) {
91+
if (dirs[i].name === 'component') dirs[i]._bind()
92+
}
93+
for (var i = 0, l = dirs.length; i < l; i++) {
94+
if (dirs[i].name !== 'component') dirs[i]._bind()
95+
}
96+
return dirs
9097
}
9198

9299
/**

src/directive.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ function Directive (name, el, vm, descriptor, def, host, scope, frag, arg) {
3636
this.arg = arg || descriptor.arg
3737
this.filters = descriptor.filters
3838
// private
39+
this._def = def
3940
this._descriptor = descriptor
4041
this._locked = false
4142
this._bound = false
@@ -44,8 +45,6 @@ function Directive (name, el, vm, descriptor, def, host, scope, frag, arg) {
4445
this._host = host
4546
this._scope = scope
4647
this._frag = frag
47-
// init
48-
this._bind(def)
4948
}
5049

5150
/**
@@ -56,7 +55,8 @@ function Directive (name, el, vm, descriptor, def, host, scope, frag, arg) {
5655
* @param {Object} def
5756
*/
5857

59-
Directive.prototype._bind = function (def) {
58+
Directive.prototype._bind = function () {
59+
var def = this._def
6060
var name = this.name
6161
if (
6262
(name !== 'cloak' || this.vm._isCompiled) &&

src/directives/component.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ module.exports = {
4141
_.deprecation.V_REF()
4242
}
4343
this.ref = ref || this.param('ref')
44+
if (this.ref) {
45+
_.defineReactive((this._scope || this.vm).$, this.ref, null)
46+
}
4447

4548
if (this.keepAlive) {
4649
this.cache = {}
@@ -345,12 +348,7 @@ module.exports = {
345348
this.childVM = child
346349
var ref = child._refId || this.ref
347350
if (ref) {
348-
var hash = (this._scope || this.vm).$
349-
if (!hash.hasOwnProperty(ref)) {
350-
_.defineReactive(hash, ref, child)
351-
} else {
352-
hash[ref] = child
353-
}
351+
(this._scope || this.vm).$[ref] = child
354352
}
355353
},
356354

@@ -362,9 +360,8 @@ module.exports = {
362360
var child = this.childVM
363361
this.childVM = null
364362
var ref = (child && child._refId) || this.ref
365-
var hash = (this._scope || this.vm).$
366-
if (ref && hash.hasOwnProperty(ref)) {
367-
hash[ref] = null
363+
if (ref) {
364+
(this._scope || this.vm).$[ref] = null
368365
}
369366
},
370367

test/unit/specs/compiler/compile_spec.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@ var compile = compiler.compile
88
if (_.inBrowser) {
99
describe('Compile', function () {
1010

11-
var vm, el, data, directiveTeardown
11+
var vm, el, data, directiveBind, directiveTeardown
1212
beforeEach(function () {
1313
// We mock vms here so we can assert what the generated
1414
// linker functions do.
1515
el = document.createElement('div')
1616
data = {}
17-
directiveTeardown = jasmine.createSpy()
17+
directiveBind = jasmine.createSpy('bind')
18+
directiveTeardown = jasmine.createSpy('teardown')
1819
vm = {
1920
_data: {},
2021
_directives: [],
2122
_bindDir: function (name) {
2223
this._directives.push({
2324
name: name,
25+
_bind: directiveBind,
2426
_teardown: directiveTeardown
2527
})
2628
},
@@ -59,6 +61,7 @@ if (_.inBrowser) {
5961
var linker = compile(el, options)
6062
expect(typeof linker).toBe('function')
6163
linker(vm, el)
64+
expect(directiveBind.calls.count()).toBe(4)
6265
expect(vm._bindDir.calls.count()).toBe(4)
6366
expect(vm._bindDir).toHaveBeenCalledWith('a', el, descriptorB, defA, undefined, undefined, undefined, undefined)
6467
expect(vm._bindDir).toHaveBeenCalledWith('a', el.firstChild, descriptorA, defA, undefined, undefined, undefined, undefined)

test/unit/specs/directive_spec.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe('Directive', function () {
3535
arg: 'someArg',
3636
filters: [{name: 'test'}]
3737
}, def)
38+
d._bind()
3839
// properties
3940
expect(d.el).toBe(el)
4041
expect(d.name).toBe('test')
@@ -63,6 +64,7 @@ describe('Directive', function () {
6364
var d = new Directive('test', el, vm, {
6465
expression: 'a'
6566
}, def)
67+
d._bind()
6668
expect(d._watcher).toBeUndefined()
6769
expect(d.expression).toBe('a')
6870
expect(d.bind).toHaveBeenCalled()
@@ -75,6 +77,7 @@ describe('Directive', function () {
7577
var d = new Directive('test', el, vm, {
7678
expression: '{{a}}'
7779
}, def)
80+
d._bind()
7881
expect(d._watcher).toBeUndefined()
7982
expect(d.expression).toBe(1)
8083
expect(d.bind).toHaveBeenCalled()
@@ -87,6 +90,7 @@ describe('Directive', function () {
8790
var d = new Directive('test', el, vm, {
8891
expression: '{{a}}'
8992
}, def)
93+
d._bind()
9094
expect(d._watcher).toBeDefined()
9195
expect(d.expression).toBe('')
9296
expect(def.bind).toHaveBeenCalled()
@@ -113,6 +117,7 @@ describe('Directive', function () {
113117
expression: 'a++',
114118
filters: [{name: 'test'}]
115119
}, def)
120+
d._bind()
116121
expect(d._watcher).toBeUndefined()
117122
expect(d.bind).toHaveBeenCalled()
118123
var wrappedFn = d.update.calls.argsFor(0)[0]
@@ -133,6 +138,7 @@ describe('Directive', function () {
133138
expression: 'a',
134139
filters: [{name: 'test'}]
135140
}, def)
141+
d._bind()
136142
d.set(2)
137143
expect(vm.a).toBe(6)
138144
nextTick(function () {
@@ -144,9 +150,10 @@ describe('Directive', function () {
144150

145151
it('deep', function (done) {
146152
def.deep = true
147-
new Directive('test', el, vm, {
153+
var d = new Directive('test', el, vm, {
148154
expression: 'b'
149155
}, def)
156+
d._bind()
150157
vm.b.c.d = 3
151158
nextTick(function () {
152159
expect(def.update.calls.count()).toBe(2)
@@ -158,6 +165,7 @@ describe('Directive', function () {
158165
var d = new Directive('test', el, vm, {
159166
expression: 'a'
160167
}, def.update)
168+
d._bind()
161169
expect(d.update).toBe(def.update)
162170
expect(def.update).toHaveBeenCalled()
163171
})

test/unit/specs/directives/ref_spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ if (_.inBrowser) {
5353
})
5454
})
5555

56-
it('should be reactive when bound by dynamic component', function (done) {
56+
it('should be reactive when bound by dynamic component and hoisted', function (done) {
5757
var vm = new Vue({
5858
el: el,
5959
data: { view: 'one' },
60-
template: '<component bind-is="view" ref="test"></component>{{$.test.value}}',
60+
template: '{{$.test.value}}<component bind-is="view" ref="test"></component>',
6161
components: {
6262
one: {
6363
id: 'one',

test/unit/specs/element-directives/partial_spec.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,15 @@ describe('Partial', function () {
109109
}
110110
})
111111
expect(vm._directives.length).toBe(2)
112-
expect(vm._directives[1].name).toBe('partial')
113112
expect(vm._watchers.length).toBe(2)
114-
vm._directives[1]._teardown()
113+
var partialDir
114+
vm._directives.some(function (d) {
115+
if (d.name === 'partial') {
116+
partialDir = d
117+
return true
118+
}
119+
})
120+
partialDir._teardown()
115121
// the text-directive should've been removed.
116122
expect(vm._directives.length).toBe(1)
117123
expect(vm._directives[0].name).toBe('partial')

0 commit comments

Comments
 (0)