Skip to content

Commit 25d5dea

Browse files
committed
refactor component scope compilation
1 parent 1165cd2 commit 25d5dea

File tree

7 files changed

+167
-143
lines changed

7 files changed

+167
-143
lines changed

src/api/lifecycle.js

Lines changed: 3 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -51,85 +51,12 @@ function ready () {
5151
}
5252

5353
/**
54-
* Teardown an instance, unobserves the data, unbind all the
55-
* directives, turn off all the event listeners, etc.
56-
*
57-
* @param {Boolean} remove - whether to remove the DOM node.
58-
* @param {Boolean} deferCleanup - if true, defer cleanup to
59-
* be called later
60-
* @public
54+
* Teardown the instance, simply delegate to the internal
55+
* _destroy.
6156
*/
6257

6358
exports.$destroy = function (remove, deferCleanup) {
64-
if (this._isBeingDestroyed) {
65-
return
66-
}
67-
this._callHook('beforeDestroy')
68-
this._isBeingDestroyed = true
69-
var i
70-
// remove self from parent. only necessary
71-
// if parent is not being destroyed as well.
72-
var parent = this.$parent
73-
if (parent && !parent._isBeingDestroyed) {
74-
i = parent._children.indexOf(this)
75-
parent._children.splice(i, 1)
76-
}
77-
// destroy all children.
78-
if (this._children) {
79-
i = this._children.length
80-
while (i--) {
81-
this._children[i].$destroy()
82-
}
83-
}
84-
// teardown all directives. this also tearsdown all
85-
// directive-owned watchers. intentionally check for
86-
// directives array length on every loop since directives
87-
// that manages partial compilation can splice ones out
88-
for (i = 0; i < this._directives.length; i++) {
89-
this._directives[i]._teardown()
90-
}
91-
// teardown all user watchers.
92-
for (i in this._userWatchers) {
93-
this._userWatchers[i].teardown()
94-
}
95-
// remove reference to self on $el
96-
if (this.$el) {
97-
this.$el.__vue__ = null
98-
}
99-
// remove DOM element
100-
var self = this
101-
if (remove && this.$el) {
102-
this.$remove(function () {
103-
self._cleanup()
104-
})
105-
} else if (!deferCleanup) {
106-
this._cleanup()
107-
}
108-
}
109-
110-
/**
111-
* Clean up to ensure garbage collection.
112-
* This is called after the leave transition if there
113-
* is any.
114-
*/
115-
116-
exports._cleanup = function () {
117-
// remove reference from data ob
118-
this._data.__ob__.removeVm(this)
119-
this._data =
120-
this._watchers =
121-
this._userWatchers =
122-
this._watcherList =
123-
this.$el =
124-
this.$parent =
125-
this.$root =
126-
this._children =
127-
this._directives = null
128-
// call the last hook...
129-
this._isDestroyed = true
130-
this._callHook('destroyed')
131-
// turn off all instance listeners.
132-
this.$off()
59+
this._destroy(remove, deferCleanup)
13360
}
13461

13562
/**

src/compiler/transclude.js

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,53 +44,36 @@ function transcludeTemplate (el, options) {
4444
if (!frag) {
4545
_.warn('Invalid template option: ' + template)
4646
} else {
47-
collectRawContent(el)
47+
var rawContent = options._content || _.extractContent(el)
4848
if (options.replace) {
4949
if (frag.childNodes.length > 1) {
50-
transcludeContent(frag)
50+
transcludeContent(frag, rawContent)
5151
return frag
5252
} else {
5353
var replacer = frag.firstChild
5454
_.copyAttributes(el, replacer)
55-
transcludeContent(replacer)
55+
transcludeContent(replacer, rawContent)
5656
return replacer
5757
}
5858
} else {
5959
el.appendChild(frag)
60-
transcludeContent(el)
60+
transcludeContent(el, rawContent)
6161
return el
6262
}
6363
}
6464
}
6565

66-
/**
67-
* Collect raw content inside $el before they are
68-
* replaced by template content.
69-
*/
70-
71-
var rawContent
72-
function collectRawContent (el) {
73-
var child
74-
rawContent = null
75-
if (el.hasChildNodes()) {
76-
rawContent = document.createElement('div')
77-
/* jshint boss:true */
78-
while (child = el.firstChild) {
79-
rawContent.appendChild(child)
80-
}
81-
}
82-
}
83-
8466
/**
8567
* Resolve <content> insertion points mimicking the behavior
8668
* of the Shadow DOM spec:
8769
*
8870
* http://w3c.github.io/webcomponents/spec/shadow/#insertion-points
8971
*
9072
* @param {Element|DocumentFragment} el
73+
* @param {Element} raw
9174
*/
9275

93-
function transcludeContent (el) {
76+
function transcludeContent (el, raw) {
9477
var outlets = getOutlets(el)
9578
var i = outlets.length
9679
if (!i) return
@@ -99,10 +82,10 @@ function transcludeContent (el) {
9982
// for each outlet.
10083
while (i--) {
10184
outlet = outlets[i]
102-
if (rawContent) {
85+
if (raw) {
10386
select = outlet.getAttribute('select')
10487
if (select) { // select content
105-
selected = rawContent.querySelectorAll(select)
88+
selected = raw.querySelectorAll(select)
10689
outlet.content = _.toArray(
10790
selected.length
10891
? selected
@@ -124,7 +107,7 @@ function transcludeContent (el) {
124107
}
125108
// finally insert the main content
126109
if (main) {
127-
insertContentAt(main, _.toArray(rawContent.childNodes))
110+
insertContentAt(main, _.toArray(raw.childNodes))
128111
}
129112
}
130113

src/directive.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@ var expParser = require('./parsers/expression')
1818
* - {String} [arg]
1919
* - {Array<Object>} [filters]
2020
* @param {Object} def - directive definition object
21-
* @param {Function} [linker] - pre-compiled linker function
2221
* @constructor
2322
*/
2423

25-
function Directive (name, el, vm, descriptor, def, linker) {
24+
function Directive (name, el, vm, descriptor, def) {
2625
// public
2726
this.name = name
2827
this.el = el
@@ -33,7 +32,6 @@ function Directive (name, el, vm, descriptor, def, linker) {
3332
this.arg = descriptor.arg
3433
this.filters = _.resolveFilters(vm, descriptor.filters)
3534
// private
36-
this._linker = linker
3735
this._locked = false
3836
this._bound = false
3937
// init

src/directives/component.js

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
var _ = require('../util')
2-
var compile = require('../compiler/compile')
32
var templateParser = require('../parsers/template')
43

54
module.exports = {
@@ -30,12 +29,6 @@ module.exports = {
3029
if (this.keepAlive) {
3130
this.cache = {}
3231
}
33-
// compile parent scope content
34-
this.parentLinkFn = compile(
35-
this.el, this.vm.$options,
36-
true, // partial
37-
true // asParent
38-
)
3932
// if static, build right now.
4033
if (!this._isDynamicLiteral) {
4134
this.resolveCtor(this.expression)
@@ -83,14 +76,10 @@ module.exports = {
8376
var vm = this.vm
8477
var el = templateParser.clone(this.el)
8578
if (this.Ctor) {
86-
var parentUnlinkFn
87-
if (this.parentLinkFn) {
88-
parentUnlinkFn = this.parentLinkFn(vm, el)
89-
}
9079
var child = vm.$addChild({
91-
el: el
80+
el: el,
81+
_asComponent: true
9282
}, this.Ctor)
93-
child._parentUnlinkFn = parentUnlinkFn
9483
if (this.keepAlive) {
9584
this.cache[this.ctorId] = child
9685
}
@@ -108,9 +97,6 @@ module.exports = {
10897
if (!child || this.keepAlive) {
10998
return
11099
}
111-
if (child._parentUnlinkFn) {
112-
child._parentUnlinkFn()
113-
}
114100
// the sole purpose of `deferCleanup` is so that we can
115101
// "deactivate" the vm right now and perform DOM removal
116102
// later.
@@ -201,11 +187,7 @@ module.exports = {
201187
// destroy all keep-alive cached instances
202188
if (this.cache) {
203189
for (var key in this.cache) {
204-
var child = this.cache[key]
205-
if (child._parentUnlinkFn) {
206-
child._parentUnlinkFn()
207-
}
208-
child.$destroy()
190+
this.cache[key].$destroy()
209191
}
210192
this.cache = null
211193
}

src/directives/repeat.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,22 +92,26 @@ module.exports = {
9292
// important: transclude with no options, just
9393
// to ensure block start and block end
9494
this.template = transclude(this.template)
95-
this._linker = compile(this.template, options)
95+
this._linkFn = compile(this.template, options)
9696
} else {
97+
this._asComponent = true
9798
var tokens = textParser.parse(id)
9899
if (!tokens) { // static component
99100
var Ctor = this.Ctor = options.components[id]
100101
_.assertAsset(Ctor, 'component', id)
101-
if (Ctor) {
102+
// If there's no parent scope directives and no
103+
// content to be transcluded, we can optimize the
104+
// rendering by pre-transcluding + compiling here
105+
// and provide a link function to every instance.
106+
if (!this.el.hasChildNodes() &&
107+
!this.el.hasAttributes()) {
102108
// merge an empty object with owner vm as parent
103109
// so child vms can access parent assets.
104-
var merged = mergeOptions(
105-
Ctor.options,
106-
{},
107-
{ $parent: this.vm }
108-
)
110+
var merged = mergeOptions(Ctor.options, {}, {
111+
$parent: this.vm
112+
})
109113
this.template = transclude(this.template, merged)
110-
this._linker = compile(this.template, merged)
114+
this._linkFn = compile(this.template, merged)
111115
}
112116
} else {
113117
// to be resolved later
@@ -274,7 +278,8 @@ module.exports = {
274278
var Ctor = this.Ctor || this.resolveCtor(data, meta)
275279
var vm = this.vm.$addChild({
276280
el: templateParser.clone(this.template),
277-
_linker: this._linker,
281+
_asComponent: this._asComponent,
282+
_linkFn: this._linkFn,
278283
_meta: meta,
279284
data: data,
280285
inherit: this.inherit

0 commit comments

Comments
 (0)