• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

baidu / san / 7136888281

08 Dec 2023 03:09AM UTC coverage: 95.074% (+0.04%) from 95.036%
7136888281

push

github

errorrik
bump 3.14.1

1955 of 2143 branches covered (0.0%)

Branch coverage included in aggregate %.

3507 of 3602 relevant lines covered (97.36%)

688.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.96
/src/view/template-component.js
1
/**
2
 * Copyright (c) Baidu Inc. All rights reserved.
3
 *
4
 * This source code is licensed under the MIT license.
5
 * See LICENSE file in the project root for license information.
6
 *
7
 * @file 模板组件类
8
 */
9

10

11
var each = require('../util/each');
12
var guid = require('../util/guid');
13
var extend = require('../util/extend');
14
var nextTick = require('../util/next-tick');
15
var emitDevtool = require('../util/emit-devtool');
16
var ExprType = require('../parser/expr-type');
17
var parseExpr = require('../parser/parse-expr');
18
var parseTemplate = require('../parser/parse-template');
19
var unpackANode = require('../parser/unpack-anode');
20
var removeEl = require('../browser/remove-el');
21
var Data = require('../runtime/data');
22
var evalExpr = require('../runtime/eval-expr');
23
var changeExprCompare = require('../runtime/change-expr-compare');
24
var DataChangeType = require('../runtime/data-change-type');
25
var svgTags = require('../browser/svg-tags');
26
var insertBefore = require('../browser/insert-before');
27
var createNode = require('./create-node');
28
var preheatEl = require('./preheat-el');
29
var parseComponentTemplate = require('./parse-component-template');
30
var preheatANode = require('./preheat-a-node');
31
var LifeCycle = require('./life-cycle');
32
var getANodeProp = require('./get-a-node-prop');
33
var isDataChangeByElement = require('./is-data-change-by-element');
34
var hydrateElementChildren = require('./hydrate-element-children');
35
var NodeType = require('./node-type');
36
var styleProps = require('./style-props');
37
var nodeSBindInit = require('./node-s-bind-init');
38
var nodeSBindUpdate = require('./node-s-bind-update');
39
var elementOwnAttached = require('./element-own-attached');
40
var elementOwnDetach = require('./element-own-detach');
41
var elementOwnDispose = require('./element-own-dispose');
42
var elementDisposeChildren = require('./element-dispose-children');
43
var handleError = require('../util/handle-error');
44
 
45
 
46
 
47
/**
48
 * 模板组件类
49
 *
50
 * @class
51
 * @param {Object} options 初始化参数
52
 */
53
function TemplateComponent(options) { // eslint-disable-line
1✔
54
    options = options || {};
33!
55
    this.lifeCycle = LifeCycle.start;
33✔
56
    this.id = guid++;
33✔
57

58
    this.children = [];
33✔
59
    this.slotChildren = [];
33✔
60
    this.implicitChildren = [];
33✔
61

62
    var clazz = this.constructor;
33✔
63

64
    this.inheritAttrs = !(this.inheritAttrs === false || clazz.inheritAttrs === false);
33✔
65
    this.owner = options.owner;
33✔
66
    this.scope = options.scope;
33✔
67
    var parent = options.parent;
33✔
68
    if (parent) {
33✔
69
        this.parent = parent;
32✔
70
        this.parentComponent = parent.nodeType === NodeType.CMPT
32✔
71
            ? parent
32!
72
            : parent && parent.parentComponent;
×
73
    }
74
    else if (this.owner) {
1!
75
        this.parentComponent = this.owner;
×
76
        this.scope = this.owner.data;
×
77
    }
78

79
    this.sourceSlotNameProps = [];
33✔
80
    this.sourceSlots = {
33✔
81
        named: {}
82
    };
83

84
    var proto = clazz.prototype;
33✔
85

86
    // compile
87
    if (!proto.hasOwnProperty('aNode')) {
33✔
88
        var aPack = clazz.aPack || proto.hasOwnProperty('aPack') && proto.aPack;
32!
89
        if (aPack) {
32!
90
            proto.aNode = unpackANode(aPack);
×
91
            clazz.aPack = proto.aPack = null;
×
92
        }
93
        else {
94
            proto.aNode = parseComponentTemplate(clazz);
32✔
95
        }
96
    }
97

98
    preheatANode(proto.aNode, this);
33✔
99

100
    this.tagName = proto.aNode.tagName;
33✔
101
    this.source = typeof options.source === 'string'
33✔
102
        ? parseTemplate(options.source).children[0]
33!
103
        : options.source;
104

105
    preheatANode(this.source);
33✔
106
    proto.aNode._i++;
33✔
107

108
    if (this.source) {
33✔
109
        // 组件运行时传入的结构,做slot解析
110
        this._initSourceSlots(1);
32✔
111

112
        for (var i = 0, l = this.source.events.length; i < l; i++) {
32✔
113
            var eventBind = this.source.events[i];
1✔
114
            // 保存当前实例的native事件,下面创建aNode时候做合并
115
            if (eventBind.modifier.native) {
1!
116
                // native事件数组
117
                this.nativeEvents = this.nativeEvents || [];
1✔
118
                this.nativeEvents.push(eventBind);
1✔
119
            }
120
        }
121

122
        this.tagName = this.tagName || this.source.tagName;
32!
123
        this.binds = this.source._b;
32✔
124
        this.attrs = this.source.attrs;
32✔
125

126
        // init s-bind data
127
        this._srcSbindData = nodeSBindInit(this.source.directives.bind, this.scope, this.owner);
32✔
128
    }
129

130
    // init data
131
    var initData;
33✔
132
    try {
33✔
133
        initData = typeof this.initData === 'function' && this.initData();
33✔
134
    }
135
    catch (e) {
136
        handleError(e, this, 'initData');
×
137
    }
138
    initData = extend(initData || {}, options.data || this._srcSbindData);
33✔
139

140
    if (this.binds && this.scope) {
33✔
141
        for (var i = 0, l = this.binds.length; i < l; i++) {
32✔
142
            var bindInfo = this.binds[i];
46✔
143

144
            var value = evalExpr(bindInfo.expr, this.scope, this.owner);
46✔
145
            if (typeof value !== 'undefined') {
46✔
146
                // See: https://github.com/ecomfe/san/issues/191
147
                initData[bindInfo.name] = value;
42✔
148
            }
149
        }
150

151
        if (this.attrs) {
32✔
152
            initData.$attrs = {};
12✔
153
            for (var i = 0, l = this.attrs.length; i < l; i++) {
12✔
154
                var attr = this.attrs[i];
28✔
155
    
156
                var value = evalExpr(attr.expr, this.scope, this.owner);
28✔
157
                if (typeof value !== 'undefined') {
28!
158
                    // See: https://github.com/ecomfe/san/issues/191
159
                    initData.$attrs[attr.name] = value;
28✔
160
                }
161
            }
162
        }
163
    }
164

165
    this.data = new Data(initData);
33✔
166

167
    this.tagName = this.tagName || 'div';
33!
168
    // #[begin] allua
169
    // ie8- 不支持innerHTML输出自定义标签
170
    /* istanbul ignore if */
171
    if (ieOldThan9 && this.tagName.indexOf('-') > 0) {
172
        this.tagName = 'div';
173
    }
174
    // #[end]
175

176
    this._initDataChanger();
33✔
177
    this._sbindData = nodeSBindInit(this.aNode.directives.bind, this.data, this);
33✔
178
    this.lifeCycle = LifeCycle.inited;
33✔
179

180
    // #[begin] hydrate
181
    var hydrateWalker = options.hydrateWalker;
33✔
182
    if (hydrateWalker) {
33✔
183
        if (this.aNode.Clazz) {
13!
184
            this._rootNode = createHydrateNode(this.aNode, this, this.data, this, hydrateWalker);
×
185
            this._rootNode._getElAsRootNode && (this.el = this._rootNode._getElAsRootNode());
×
186
        }
187
        else {
188
            this.el = hydrateWalker.current;
13✔
189
            hydrateWalker.goNext();
13✔
190

191
            hydrateElementChildren(this, this.data, this);
13✔
192
        }
193

194
        this.lifeCycle = LifeCycle.created;
13✔
195
        this._attached();
13✔
196
        this.lifeCycle = LifeCycle.attached;
13✔
197
    }
198
    // #[end]
199
}
200

201

202
/**
203
 * 初始化组件内部监听数据变化
204
 *
205
 * @private
206
 * @param {Object} change 数据变化信息
207
 */
208
TemplateComponent.prototype._initDataChanger = function () {
1✔
209
    var me = this;
33✔
210

211
    this._dataChanger = function (change) {
33✔
212
        if (me.lifeCycle.created) {
51!
213
            if (!me._dataChanges) {
51✔
214
                nextTick(me._update, me);
29✔
215
                me._dataChanges = [];
29✔
216
            }
217

218
            me._dataChanges.push(change);
51✔
219
        }
220
        else if (me.lifeCycle.inited && me.owner) {
×
221
            me._updateBindxOwner([change]);
×
222
        }
223
    };
224

225
    this.data.listen(this._dataChanger);
33✔
226
};
227

228

229
/**
230
 * 将组件attach到页面
231
 *
232
 * @param {HTMLElement} parentEl 要添加到的父元素
233
 * @param {HTMLElement=} beforeEl 要添加到哪个元素之前
234
 */
235
TemplateComponent.prototype.attach = function (parentEl, beforeEl) {
1✔
236
    if (!this.lifeCycle.attached) {
20!
237
        // #[begin] devtool
238
        emitDevtool('comp-beforeAttach', this);
20✔
239
        // #[end]
240

241
        var aNode = this.aNode;
20✔
242

243
        if (aNode.Clazz) {
20✔
244
            // #[begin] devtool
245
            emitDevtool('comp-beforeCreate', this);
4✔
246
            // #[end]
247

248
            this._rootNode = this._rootNode || createNode(aNode, this, this.data, this);
4✔
249
            this._rootNode.attach(parentEl, beforeEl);
4✔
250
            this._rootNode._getElAsRootNode && (this.el = this._rootNode._getElAsRootNode());
4✔
251
            
252
            this.lifeCycle = LifeCycle.created;
4✔
253
            // #[begin] devtool
254
            emitDevtool('comp-create', this);
4✔
255
            // #[end]
256
        }
257
        else {
258
            if (!this.el) {
16!
259
                // #[begin] devtool
260
                emitDevtool('comp-beforeCreate', this);
16✔
261
                // #[end]
262

263
                var props;
16✔
264
                var doc = parentEl.ownerDocument;
16✔
265

266
                if (aNode._ce && aNode._i > 2) {
16✔
267
                    props = aNode._dp;
×
268
                    this.el = (aNode._el || preheatEl(aNode, doc)).cloneNode(false);
×
269
                }
270
                else {
271
                    props = aNode.props;
16✔
272
                    this.el = svgTags[this.tagName] && doc.createElementNS
16!
273
                        ? doc.createElementNS('http://www.w3.org/2000/svg', this.tagName)
16!
274
                        : doc.createElement(this.tagName);
275
                }
276

277
                if (this._sbindData) {
16!
278
                    for (var key in this._sbindData) {
×
279
                        if (this._sbindData.hasOwnProperty(key)) {
×
280
                            getPropHandler(this.tagName, key)(
×
281
                                this.el,
282
                                this._sbindData[key],
283
                                key,
284
                                this
285
                            );
286
                        }
287
                    }
288
                }
289

290
                for (var i = 0, l = props.length; i < l; i++) {
16✔
291
                    var prop = props[i];
48✔
292
                    var value = evalExpr(prop.expr, this.data, this);
48✔
293

294
                    if (value || !styleProps[prop.name]) {
48✔
295
                        prop.handler(this.el, value, prop.name, this);
25✔
296
                    }
297
                }
298

299
                if (this.attrs && this.inheritAttrs) {
16✔
300
                    var attrsData = this.data.get('$attrs');
4✔
301
                    for (var i = 0; i < this.attrs.length; i++) {
4✔
302
                        var attr = this.attrs[i];
10✔
303
                        if (this.aNode._pi[attr.name] == null) {
10✔
304
                            getPropHandler(this.tagName, attr.name)(this.el, attrsData[attr.name], attr.name, this);
9✔
305
                        }
306
                    }
307
                }
308

309
                this.lifeCycle = LifeCycle.created;
16✔
310
                // #[begin] devtool
311
                emitDevtool('comp-create', this);
16✔
312
                // #[end]
313
            }
314

315
            insertBefore(this.el, parentEl, beforeEl);
16✔
316

317
            if (!this._contentReady) {
16!
318
                var htmlDirective = aNode.directives.html;
16✔
319

320
                if (htmlDirective) {
16!
321
                    // #[begin] error
322
                    warnSetHTML(this.el);
×
323
                    // #[end]
324

325
                    this.el.innerHTML = evalExpr(htmlDirective.value, this.data, this);
×
326
                }
327
                else {
328
                    for (var i = 0, l = aNode.children.length; i < l; i++) {
16✔
329
                        var childANode = aNode.children[i];
16✔
330
                        var child = childANode.Clazz
16✔
331
                            ? new childANode.Clazz(childANode, this, this.data, this)
16✔
332
                            : createNode(childANode, this, this.data, this);
333
                        this.children.push(child);
16✔
334
                        child.attach(this.el);
16✔
335
                    }
336
                }
337

338
                this._contentReady = 1;
16✔
339
            }
340

341
            this._attached();
16✔
342
        }
343

344
        this.lifeCycle = LifeCycle.attached;
20✔
345
        // #[begin] devtool
346
        emitDevtool('comp-attached', this);
20✔
347
        // #[end]
348
    }
349
};
350

351
/**
352
 * 类型标识
353
 *
354
 * @type {string}
355
 */
356
TemplateComponent.prototype.nodeType = NodeType.CMPT;
1✔
357

358
TemplateComponent.prototype._getElAsRootNode = function () {
1✔
359
    return this.el;
6✔
360
};
361

362
/**
363
 * 视图更新函数
364
 *
365
 * @param {Array?} changes 数据变化信息
366
 */
367
TemplateComponent.prototype._update = function (changes) {
1✔
368
    if (this.lifeCycle.disposed) {
61✔
369
        return;
27✔
370
    }
371

372
    var me = this;
34✔
373

374

375
    var needReloadForSlot = false;
34✔
376
    this._notifyNeedReload = function () {
34✔
377
        needReloadForSlot = true;
×
378
    };
379

380
    if (changes) {
34✔
381
        if (this.source) {
32!
382
            this._srcSbindData = nodeSBindUpdate(
32✔
383
                this.source.directives.bind,
384
                this._srcSbindData,
385
                this.scope,
386
                this.owner,
387
                changes,
388
                function (name, value) {
389
                    if (name in me.source._pi) {
×
390
                        return;
×
391
                    }
392

393
                    me.data.set(name, value, {
×
394
                        target: {
395
                            node: me.owner
396
                        }
397
                    });
398
                }
399
            );
400
        }
401

402
        each(changes, function (change) {
32✔
403
            var changeExpr = change.expr;
49✔
404

405
            each(me.binds, function (bindItem) {
49✔
406
                var relation;
86✔
407
                var setExpr = bindItem.name;
86✔
408
                var updateExpr = bindItem.expr;
86✔
409

410
                if (!isDataChangeByElement(change, me, setExpr)
86✔
411
                    && (relation = changeExprCompare(changeExpr, updateExpr, me.scope))
412
                ) {
413
                    if (relation > 2) {
27!
414
                        setExpr = {
×
415
                            type: ExprType.ACCESSOR,
416
                            paths: [
417
                                {
418
                                    type: ExprType.STRING,
419
                                    value: setExpr
420
                                }
421
                            ].concat(changeExpr.paths.slice(updateExpr.paths.length))
422
                        };
423
                        updateExpr = changeExpr;
×
424
                    }
425

426
                    if (relation >= 2 && change.type === DataChangeType.SPLICE) {
27✔
427
                        me.data.splice(setExpr, [change.index, change.deleteCount].concat(change.insertions), {
×
428
                            target: {
429
                                node: me.owner
430
                            }
431
                        });
432
                    }
433
                    else {
434
                        me.data.set(setExpr, evalExpr(updateExpr, me.scope, me.owner), {
27✔
435
                            target: {
436
                                node: me.owner
437
                            }
438
                        });
439
                    }
440
                }
441
            });
442

443
            each(me.attrs, function (bindItem) {
49✔
444
                if (changeExprCompare(changeExpr, bindItem.expr, me.scope)) {
28✔
445
                    me.data.set(
22✔
446
                        bindItem._data,
447
                        evalExpr(bindItem.expr, me.scope, me.owner)
448
                    );
449
                }
450
            });
451

452
            each(me.sourceSlotNameProps, function (bindItem) {
49✔
453
                needReloadForSlot = needReloadForSlot || changeExprCompare(changeExpr, bindItem.expr, me.scope);
7✔
454
                return !needReloadForSlot;
7✔
455
            });
456
        });
457

458
        if (needReloadForSlot) {
32!
459
            this._initSourceSlots();
×
460
            this._repaintChildren();
×
461
        }
462
        else {
463
            var slotChildrenLen = this.slotChildren.length;
32✔
464
            while (slotChildrenLen--) {
32✔
465
                var slotChild = this.slotChildren[slotChildrenLen];
22✔
466

467
                if (slotChild.lifeCycle.disposed) {
22!
468
                    this.slotChildren.splice(slotChildrenLen, 1);
×
469
                }
470
                else if (slotChild.isInserted) {
22!
471
                    slotChild._update(changes, 1);
22✔
472
                }
473
            }
474
        }
475
    }
476

477
    var dataChanges = this._dataChanges;
34✔
478
    if (dataChanges) {
34✔
479
        // #[begin] devtool
480
        emitDevtool('comp-beforeUpdate', this);
29✔
481
        // #[end]
482

483
        this._dataChanges = null;
29✔
484

485
        this._sbindData = nodeSBindUpdate(
29✔
486
            this.aNode.directives.bind,
487
            this._sbindData,
488
            this.data,
489
            this,
490
            dataChanges,
491
            function (name, value) {
492
                if (me._rootNode || (name in me.aNode._pi)) {
×
493
                    return;
×
494
                }
495

496
                getPropHandler(me.tagName, name)(me.el, value, name, me);
×
497
            }
498
        );
499

500
        var htmlDirective = this.aNode.directives.html;
29✔
501

502
        if (this._rootNode) {
29✔
503
            this._rootNode._update(dataChanges);
3✔
504
            this._rootNode._getElAsRootNode && (this.el = this._rootNode._getElAsRootNode());
3✔
505
        }
506
        else if (htmlDirective) {
26!
507
            var len = dataChanges.length;
×
508
            while (len--) {
×
509
                if (changeExprCompare(dataChanges[len].expr, htmlDirective.value, this.data)) {
×
510
                    // #[begin] error
511
                    warnSetHTML(this.el);
×
512
                    // #[end]
513

514
                    this.el.innerHTML = evalExpr(htmlDirective.value, this.data, this);
×
515
                    break;
×
516
                }
517
            }
518
        }
519
        else {
520
            var dynamicProps = this.aNode._dp;
26✔
521
            for (var i = 0; i < dynamicProps.length; i++) {
26✔
522
                var prop = dynamicProps[i];
71✔
523

524
                for (var j = 0; j < dataChanges.length; j++) {
71✔
525
                    var change = dataChanges[j];
122✔
526
                    if (changeExprCompare(change.expr, prop.expr, this.data)
122!
527
                        || prop.hintExpr && changeExprCompare(change.expr, prop.hintExpr, this.data)
528
                    ) {
529
                        prop.handler(this.el, evalExpr(prop.expr, this.data, this), prop.name, this);
12✔
530
                        break;
12✔
531
                    }
532
                }
533
            }
534

535
            if (this.attrs && this.inheritAttrs) {
26✔
536
                var attrsData = this.data.get('$attrs');
8✔
537

538
                for (var i = 0; i < this.attrs.length; i++) {
8✔
539
                    var attr = this.attrs[i];
20✔
540

541
                    if (this.aNode._pi[attr.name] == null) {
20✔
542
                        for (var j = 0; j < dataChanges.length; j++) {
18✔
543
                            var changePaths = dataChanges[j].expr.paths;
24✔
544

545
                            if (changePaths[0].value === '$attrs' && changePaths[1].value === attr.name) {
24✔
546
                                getPropHandler(this.tagName, attr.name)(this.el, attrsData[attr.name], attr.name, this);
12✔
547
                                break;
12✔
548
                            }
549
                        }
550
                    }
551
                }
552
            }
553

554
            for (var i = 0; i < this.children.length; i++) {
26✔
555
                this.children[i]._update(dataChanges);
36✔
556
            }
557
        }
558

559
        if (needReloadForSlot) {
29!
560
            this._initSourceSlots();
×
561
            this._repaintChildren();
×
562
        }
563

564
        if (this.owner && this._updateBindxOwner(dataChanges)) {
29✔
565
            this.owner._update();
×
566
        }
567
    }
568

569
    this._notifyNeedReload = null;
34✔
570
};
571

572
TemplateComponent.prototype._updateBindxOwner = function (dataChanges) {
1✔
573
    var me = this;
28✔
574
    var xbindUped;
28✔
575

576
    each(dataChanges, function (change) {
28✔
577
        each(me.binds, function (bindItem) {
49✔
578
            var changeExpr = change.expr;
84✔
579
            if (bindItem.x
84!
580
                && !isDataChangeByElement(change, me.owner)
581
                && changeExprCompare(changeExpr, parseExpr(bindItem.name), me.data)
582
            ) {
583
                var updateScopeExpr = bindItem.expr;
×
584
                if (changeExpr.paths.length > 1) {
×
585
                    updateScopeExpr = {
×
586
                        type: ExprType.ACCESSOR,
587
                        paths: bindItem.expr.paths.concat(changeExpr.paths.slice(1))
588
                    };
589
                }
590

591
                xbindUped = 1;
×
592
                me.scope.set(
×
593
                    updateScopeExpr,
594
                    evalExpr(changeExpr, me.data, me),
595
                    {
596
                        target: {
597
                            node: me,
598
                            prop: bindItem.name
599
                        }
600
                    }
601
                );
602
            }
603
        });
604
    });
605

606
    return xbindUped;
28✔
607
};
608

609

610
/**
611
 * 初始化创建组件外部传入的插槽对象
612
 *
613
 * @protected
614
 * @param {boolean} isFirstTime 是否初次对sourceSlots进行计算
615
 */
616
TemplateComponent.prototype._initSourceSlots = function (isFirstTime) {
1✔
617
    this.sourceSlots.named = {};
32✔
618

619
    // 组件运行时传入的结构,做slot解析
620
    if (this.source && this.scope) {
32✔
621
        var sourceChildren = this.source.children;
32✔
622

623
        for (var i = 0, l = sourceChildren.length; i < l; i++) {
32✔
624
            var child = sourceChildren[i];
21✔
625
            var target;
21✔
626

627
            var slotBind = !child.textExpr && getANodeProp(child, 'slot');
21✔
628
            if (slotBind) {
21✔
629
                isFirstTime && this.sourceSlotNameProps.push(slotBind);
3✔
630

631
                var slotName = evalExpr(slotBind.expr, this.scope, this.owner);
3✔
632
                target = this.sourceSlots.named[slotName];
3✔
633
                if (!target) {
3!
634
                    target = this.sourceSlots.named[slotName] = [];
3✔
635
                }
636
                target.push(child);
3✔
637
            }
638
            else if (isFirstTime) {
18!
639
                target = this.sourceSlots.noname;
18✔
640
                if (!target) {
18✔
641
                    target = this.sourceSlots.noname = [];
17✔
642
                }
643
                target.push(child);
18✔
644
            }
645
        }
646
    }
647
};
648

649
TemplateComponent.prototype._repaintChildren = function () {
1✔
650
    // TODO: repaint once?
651

652
    if (this._rootNode) {
×
653
        var parentEl = this._rootNode.el.parentNode;
×
654
        var beforeEl = this._rootNode.el.nextSibling;
×
655
        this._rootNode.dispose(0, 1);
×
656
        this.slotChildren = [];
×
657

658
        this._rootNode = createNode(this.aNode, this, this.data, this);
×
659
        this._rootNode.attach(parentEl, beforeEl);
×
660
        this._rootNode._getElAsRootNode && (this.el = this._rootNode._getElAsRootNode());
×
661
    }
662
    else {
663
        elementDisposeChildren(this.children, 0, 1);
×
664
        this.children = [];
×
665
        this.slotChildren = [];
×
666

667
        for (var i = 0, l = this.aNode.children.length; i < l; i++) {
×
668
            var child = createNode(this.aNode.children[i], this, this.data, this);
×
669
            this.children.push(child);
×
670
            child.attach(this.el);
×
671
        }
672
    }
673
};
674

675
TemplateComponent.prototype._leave = function () {
1✔
676
    if (this.leaveDispose) {
33!
677
        if (!this.lifeCycle.disposed) {
33!
678
            // #[begin] devtool
679
            emitDevtool('comp-beforeDetach', this);
33✔
680
            // #[end]
681

682
            this.data.unlisten();
33✔
683
            this.dataChanger = null;
33✔
684
            this._dataChanges = null;
33✔
685

686
            this.source = null;
33✔
687
            this.sourceSlots = null;
33✔
688
            this.sourceSlotNameProps = null;
33✔
689

690
            // 这里不用挨个调用 dispose 了,因为 children 释放链会调用的
691
            this.slotChildren = null;
33✔
692

693

694
            if (this._rootNode) {
33✔
695
                // 如果没有parent,说明是一个root component,一定要从dom树中remove
696
                this._rootNode.dispose(this.disposeNoDetach && this.parent);
4✔
697
            }
698
            else {
699
                var len = this.children.length;
29✔
700
                while (len--) {
29✔
701
                    this.children[len].dispose(1, 1);
42✔
702
                }
703

704
                // #[begin] allua
705
                /* istanbul ignore if */
706
                if (this._inputTimer) {
707
                    clearInterval(this._inputTimer);
708
                    this._inputTimer = null;
709
                }
710
                // #[end]
711

712
                // 如果没有parent,说明是一个root component,一定要从dom树中remove
713
                if (!this.disposeNoDetach || !this.parent) {
29✔
714
                    removeEl(this.el);
2✔
715
                }
716
            }
717

718
            this.lifeCycle = LifeCycle.detached;
33✔
719
            // #[begin] devtool
720
            emitDevtool('comp-detached', this);
33✔
721
            // #[end]
722

723
            // #[begin] devtool
724
            emitDevtool('comp-beforeDispose', this);
33✔
725
            // #[end]
726

727
            this._rootNode = null;
33✔
728
            this.el = null;
33✔
729
            this.owner = null;
33✔
730
            this.scope = null;
33✔
731
            this.children = null;
33✔
732

733
            this.lifeCycle = LifeCycle.disposed;
33✔
734
            // #[begin] devtool
735
            emitDevtool('comp-disposed', this);
33✔
736
            // #[end]
737

738
            if (this._ondisposed) {
33!
739
                this._ondisposed();
×
740
            }
741
        }
742
    }
743
    else if (this.lifeCycle.attached) {
×
744
        // #[begin] devtool
745
        emitDevtool('comp-beforeDetach', this);
×
746
        // #[end]
747

748
        if (this._rootNode) {
×
749
            if (this._rootNode.detach) {
×
750
                this._rootNode.detach();
×
751
            }
752
            else {
753
                this._rootNode.dispose();
×
754
                this._rootNode = null;
×
755
            }
756
        }
757
        else {
758
            removeEl(this.el);
×
759
        }
760

761
        this.lifeCycle = LifeCycle.detached;
×
762
        // #[begin] devtool
763
        emitDevtool('comp-detached', this);
×
764
        // #[end]
765
    }
766
};
767

768
TemplateComponent.prototype.detach = elementOwnDetach;
1✔
769
TemplateComponent.prototype.dispose = elementOwnDispose;
1✔
770
TemplateComponent.prototype._attached = elementOwnAttached;
1✔
771

772
exports = module.exports = TemplateComponent;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc