Skip to content

Commit 665520f

Browse files
author
Evan You
committed
v-component & v-with refactor
1 parent 2059be5 commit 665520f

File tree

12 files changed

+203
-121
lines changed

12 files changed

+203
-121
lines changed

component.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"src/transition.js",
2424
"src/batcher.js",
2525
"src/directives/index.js",
26+
"src/directives/component.js",
2627
"src/directives/if.js",
2728
"src/directives/repeat.js",
2829
"src/directives/on.js",

src/batcher.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ BatcherProto.flush = function () {
2929
// as we execute existing jobs
3030
for (var i = 0; i < this.queue.length; i++) {
3131
var job = this.queue[i]
32-
if (job.cancelled) continue
33-
if (job.execute() !== false) {
34-
this.has[job.id] = false
32+
if (!job.cancelled) {
33+
job.execute()
3534
}
3635
}
3736
this.reset()

src/binding.js

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ BindingProto.update = function (value) {
3939
execute: function () {
4040
if (!self.unbound) {
4141
self._update()
42-
} else {
43-
return false
4442
}
4543
}
4644
})

src/compiler.js

+38-24
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ CompilerProto.observeData = function (data) {
325325
*/
326326
CompilerProto.compile = function (node, root) {
327327

328+
/* jshint boss: true */
329+
328330
var compiler = this,
329331
nodeType = node.nodeType,
330332
tagName = node.tagName
@@ -335,22 +337,15 @@ CompilerProto.compile = function (node, root) {
335337
if (utils.attr(node, 'pre') !== null) return
336338

337339
// special attributes to check
338-
var repeatExp,
339-
viewExp,
340-
withExp,
341-
directive,
342-
// resolve a standalone child component with no inherited data
343-
hasComponent = this.resolveComponent(node, undefined, true)
340+
var directive, repeatExp, viewExp, Component
344341

345342
// It is important that we access these attributes
346343
// procedurally because the order matters.
347-
//
348344
// `utils.attr` removes the attribute once it gets the
349345
// value, so we should not access them all at once.
350346

351347
// v-repeat has the highest priority
352348
// and we need to preserve all other attributes for it.
353-
/* jshint boss: true */
354349
if (repeatExp = utils.attr(node, 'repeat')) {
355350

356351
// repeat block cannot have v-id at the same time.
@@ -370,18 +365,26 @@ CompilerProto.compile = function (node, root) {
370365
}
371366

372367
// Child component has 2nd highest priority
373-
} else if (root !== true && ((withExp = utils.attr(node, 'with')) || hasComponent)) {
374-
375-
withExp = Directive.split(withExp || '')
376-
withExp.forEach(function (exp, i) {
377-
var directive = Directive.parse('with', exp, compiler, node)
378-
if (directive) {
379-
// notify the directive that this is the
380-
// last expression in the group
381-
directive.last = i === withExp.length - 1
382-
compiler.deferred.push(directive)
383-
}
384-
})
368+
} else if (root !== true && (Component = this.resolveComponent(node, undefined, true))) {
369+
370+
directive = Directive.parse('component', '', compiler, node)
371+
if (directive) {
372+
directive.Ctor = Component
373+
compiler.deferred.push(directive)
374+
}
375+
376+
// should build component
377+
378+
// withExp = Directive.split(withExp || '')
379+
// withExp.forEach(function (exp, i) {
380+
// var directive = Directive.parse('with', exp, compiler, node)
381+
// if (directive) {
382+
// // notify the directive that this is the
383+
// // last expression in the group
384+
// directive.last = i === withExp.length - 1
385+
// compiler.deferred.push(directive)
386+
// }
387+
// })
385388

386389
} else {
387390

@@ -432,7 +435,13 @@ CompilerProto.compileNode = function (node) {
432435
exp = exps[j]
433436
dirname = attr.name.slice(prefix.length)
434437
directive = Directive.parse(dirname, exp, this, node)
435-
this.bindDirective(directive)
438+
439+
if (dirname === 'with') {
440+
this.bindDirective(directive, this.parent)
441+
} else {
442+
this.bindDirective(directive)
443+
}
444+
436445
}
437446
} else if (config.interpolate) {
438447
// non directive attribute, check interpolation tags
@@ -811,7 +820,10 @@ CompilerProto.eval = function (exp, data) {
811820
*/
812821
CompilerProto.resolveComponent = function (node, data, test) {
813822

814-
var exp = utils.attr(node, 'component', test),
823+
// late require to avoid circular deps
824+
ViewModel = ViewModel || require('./viewmodel')
825+
826+
var exp = utils.attr(node, 'component'),
815827
tagName = node.tagName,
816828
id = this.eval(exp, data),
817829
tagId = (tagName.indexOf('-') > 0 && tagName.toLowerCase()),
@@ -822,8 +834,10 @@ CompilerProto.resolveComponent = function (node, data, test) {
822834
}
823835

824836
return test
825-
? Ctor
826-
: Ctor || (ViewModel || (ViewModel = require('./viewmodel')))
837+
? exp === ''
838+
? ViewModel
839+
: Ctor
840+
: Ctor || ViewModel
827841
}
828842

829843
/**

src/directives/component.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module.exports = {
2+
3+
isLiteral: true,
4+
5+
bind: function () {
6+
if (!this.el.vue_vm) {
7+
this.component = new this.Ctor({
8+
el: this.el,
9+
parent: this.vm
10+
})
11+
}
12+
},
13+
14+
unbind: function () {
15+
if (this.component) {
16+
this.component.$destroy()
17+
}
18+
}
19+
20+
}

src/directives/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module.exports = {
1313
style : require('./style'),
1414
partial : require('./partial'),
1515
view : require('./view'),
16+
component : require('./component'),
1617

1718
attr: {
1819
bind: function () {

src/directives/with.js

+123-75
Original file line numberDiff line numberDiff line change
@@ -3,88 +3,136 @@ var utils = require('../utils')
33
module.exports = {
44

55
bind: function () {
6-
if (this.el.vue_vm) {
7-
this.subVM = this.el.vue_vm
8-
var compiler = this.subVM.$compiler
9-
if (this.arg && !compiler.bindings[this.arg]) {
10-
compiler.createBinding(this.arg)
11-
}
12-
} else if (this.isEmpty) {
13-
this.build()
14-
}
15-
},
166

17-
update: function (value, init) {
18-
var vm = this.subVM,
19-
key = this.arg || '$data'
20-
if (!vm) {
21-
this.build(value)
22-
} else if (!this.lock && vm[key] !== value) {
23-
vm[key] = value
24-
}
25-
if (init) {
26-
// watch after first set
27-
this.watch()
28-
// The v-with directive can have multiple expressions,
29-
// and we want to make sure when the ready hook is called
30-
// on the subVM, all these clauses have been properly set up.
31-
// So this is a hack that sniffs whether we have reached
32-
// the last expression. We hold off the subVM's ready hook
33-
// until we are actually ready.
34-
if (this.last) {
35-
this.subVM.$compiler.execHook('ready')
36-
}
37-
}
38-
},
7+
var self = this,
8+
childKey = self.arg,
9+
parentKey = self.key,
10+
compiler = self.compiler,
11+
owner = self.binding.compiler
3912

40-
build: function (value) {
41-
var data = value
42-
if (this.arg) {
43-
data = {}
44-
data[this.arg] = value
13+
if (compiler === owner) {
14+
this.alone = true
15+
return
4516
}
46-
var Ctor = this.compiler.resolveComponent(this.el, data)
47-
this.subVM = new Ctor({
48-
el : this.el,
49-
data : data,
50-
parent : this.vm,
51-
compilerOptions: {
52-
// it is important to delay the ready hook
53-
// so that when it's called, all `v-with` wathcers
54-
// would have been set up.
55-
delayReady: !this.last
56-
}
57-
})
58-
// mark that this VM is created by v-with
59-
utils.defProtected(this.subVM, '$with', true)
60-
},
6117

62-
/**
63-
* For inhertied keys, need to watch
64-
* and sync back to the parent
65-
*/
66-
watch: function () {
67-
if (!this.arg) return
68-
var self = this,
69-
key = self.key,
70-
ownerVM = self.binding.compiler.vm
71-
this.subVM.$compiler.observer.on('change:' + this.arg, function (val) {
72-
if (!self.lock) {
73-
self.lock = true
74-
utils.nextTick(function () {
75-
self.lock = false
76-
})
18+
if (childKey) {
19+
if (!compiler.bindings[childKey]) {
20+
compiler.createBinding(childKey)
7721
}
78-
ownerVM.$set(key, val)
79-
})
22+
// sync changes on child back to parent
23+
compiler.observer.on('change:' + childKey, function (val) {
24+
if (compiler.init) return
25+
if (!self.lock) {
26+
self.lock = true
27+
utils.nextTick(function () {
28+
self.lock = false
29+
})
30+
}
31+
owner.vm.$set(parentKey, val)
32+
})
33+
}
8034
},
8135

82-
unbind: function () {
83-
// all watchers are turned off during destroy
84-
// so no need to worry about it
85-
if (this.subVM.$with) {
86-
this.subVM.$destroy()
36+
update: function (value) {
37+
// sync from parent
38+
if (!this.alone && !this.lock) {
39+
if (this.arg) {
40+
this.vm.$set(this.arg, value)
41+
} else {
42+
this.vm.$data = value
43+
}
8744
}
8845
}
8946

90-
}
47+
}
48+
49+
// var utils = require('../utils')
50+
51+
// module.exports = {
52+
53+
// bind: function () {
54+
// if (this.el.vue_vm) {
55+
// this.subVM = this.el.vue_vm
56+
// var compiler = this.subVM.$compiler
57+
// if (this.arg && !compiler.bindings[this.arg]) {
58+
// compiler.createBinding(this.arg)
59+
// }
60+
// } else if (this.isEmpty) {
61+
// this.build()
62+
// }
63+
// },
64+
65+
// update: function (value, init) {
66+
// var vm = this.subVM,
67+
// key = this.arg || '$data'
68+
// if (!vm) {
69+
// this.build(value)
70+
// } else if (!this.lock && vm[key] !== value) {
71+
// vm[key] = value
72+
// }
73+
// if (init) {
74+
// // watch after first set
75+
// this.watch()
76+
// // The v-with directive can have multiple expressions,
77+
// // and we want to make sure when the ready hook is called
78+
// // on the subVM, all these clauses have been properly set up.
79+
// // So this is a hack that sniffs whether we have reached
80+
// // the last expression. We hold off the subVM's ready hook
81+
// // until we are actually ready.
82+
// if (this.last) {
83+
// this.subVM.$compiler.execHook('ready')
84+
// }
85+
// }
86+
// },
87+
88+
// build: function (value) {
89+
// var data = value
90+
// if (this.arg) {
91+
// data = {}
92+
// data[this.arg] = value
93+
// }
94+
// var Ctor = this.compiler.resolveComponent(this.el, data)
95+
// this.subVM = new Ctor({
96+
// el : this.el,
97+
// data : data,
98+
// parent : this.vm,
99+
// compilerOptions: {
100+
// // it is important to delay the ready hook
101+
// // so that when it's called, all `v-with` wathcers
102+
// // would have been set up.
103+
// delayReady: !this.last
104+
// }
105+
// })
106+
// // mark that this VM is created by v-with
107+
// utils.defProtected(this.subVM, '$with', true)
108+
// },
109+
110+
// /**
111+
// * For inhertied keys, need to watch
112+
// * and sync back to the parent
113+
// */
114+
// watch: function () {
115+
// if (!this.arg) return
116+
// var self = this,
117+
// key = self.key,
118+
// ownerVM = self.binding.compiler.vm
119+
// this.subVM.$compiler.observer.on('change:' + this.arg, function (val) {
120+
// if (!self.lock) {
121+
// self.lock = true
122+
// utils.nextTick(function () {
123+
// self.lock = false
124+
// })
125+
// }
126+
// ownerVM.$set(key, val)
127+
// })
128+
// },
129+
130+
// unbind: function () {
131+
// // all watchers are turned off during destroy
132+
// // so no need to worry about it
133+
// if (this.subVM.$with) {
134+
// this.subVM.$destroy()
135+
// }
136+
// }
137+
138+
// }

src/utils.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ var utils = module.exports = {
6363
/**
6464
* get an attribute and remove it.
6565
*/
66-
attr: function (el, type, preserve) {
66+
attr: function (el, type) {
6767
var attr = config.prefix + '-' + type,
6868
val = el.getAttribute(attr)
69-
if (!preserve && val !== null) {
69+
if (val !== null) {
7070
el.removeAttribute(attr)
7171
}
7272
return val

0 commit comments

Comments
 (0)