From b01075982d74e10fa80d4142f0b69113dbdfa8e8 Mon Sep 17 00:00:00 2001 From: zhongkai Date: Tue, 7 Jul 2020 17:32:40 +0800 Subject: [PATCH] support for loop parameters in slot name #504 --- src/view/component.js | 43 ++++++++++++++++++++++++++++++++++++++----- src/view/slot-node.js | 2 +- test/slot.spec.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/src/view/component.js b/src/view/component.js index e65e80bb1..da9746f33 100644 --- a/src/view/component.js +++ b/src/view/component.js @@ -341,12 +341,45 @@ Component.prototype._initSourceSlots = function (isFirstTime) { if (slotBind) { isFirstTime && this.sourceSlotNameProps.push(slotBind); - var slotName = evalExpr(slotBind.expr, this.scope, this.owner); - target = this.sourceSlots.named[slotName]; - if (!target) { - target = this.sourceSlots.named[slotName] = []; + // 处理slot+for的情况:https://github.com/baidu/san/issues/504 + // 因为slot的name包含插值,且插值包含迭代变量,所以需要做特殊处理 + var forDirective = child.directives + && slotBind.expr + && (slotBind.expr.type == ExprType.TEXT || slotBind.expr.type == ExprType.INTERP) + && child.directives['for'] ; // eslint-disable-line dot-notation + var listData = null; + if(forDirective) { + listData = evalExpr(forDirective.value, this.scope, this.owner); + } + + // 插槽未被scoped + if (forDirective && listData) { + for (var index in listData) { + if (listData.hasOwnProperty(index) && listData[index] != null) { + var itemScope = {}; + itemScope[forDirective.item] = listData[index]; + itemScope[forDirective.index || '$index'] = index; + var itemData = new Data(itemScope, this.scope); + var slotName = evalExpr(slotBind.expr, itemData, this.owner); + + target = this.sourceSlots.named[slotName]; + if (!target) { + target = this.sourceSlots.named[slotName] = []; + } + // cache item data for render + target.scope = itemData; + target.push(child.forRinsed); + } + } + } + else { + var slotName = evalExpr(slotBind.expr, this.scope, this.owner); + target = this.sourceSlots.named[slotName]; + if (!target) { + target = this.sourceSlots.named[slotName] = []; + } + target.push(child); } - target.push(child); } else if (isFirstTime) { target = this.sourceSlots.noname; diff --git a/src/view/slot-node.js b/src/view/slot-node.js index 5fe42db14..37a6d7e89 100644 --- a/src/view/slot-node.js +++ b/src/view/slot-node.js @@ -95,7 +95,7 @@ function SlotNode(aNode, parent, scope, owner, reverseWalker) { // child owner & child scope if (this.isInserted) { this.childOwner = owner.owner; - this.childScope = owner.scope; + this.childScope = matchedSlots.scope || owner.scope; } if (initData) { diff --git a/test/slot.spec.js b/test/slot.spec.js index fff6a4e96..040b761a8 100644 --- a/test/slot.spec.js +++ b/test/slot.spec.js @@ -2994,4 +2994,47 @@ describe("Slot", function () { done(); }); }); + + it("slot prop contains for loop parameters", function (done) { + var Folder = san.defineComponent({ + template: '

', + initData: function () { + return { files: ['error', 'rick'] } + } + }); + + var MyComponent = san.defineComponent({ + components: { + 'x-folder': Folder + }, + + initData: function () { + return { + files: ['error', 'rick'] + } + }, + + template: '' + + '
' + + '{{ j }}-{{ i }}' + + '
' + }); + + var myComponent = new MyComponent(); + var wrap = document.createElement('div'); + document.body.appendChild(wrap); + myComponent.attach(wrap); + + var p0 = wrap.getElementsByTagName('p')[0]; + var bs0 = p0.getElementsByTagName('b'); + expect(bs0.length).toBe(1); + expect(bs0[0].innerHTML).toBe('0-error'); + + var p1 = p0.nextSibling; + bs1 = p1.getElementsByTagName('b'); + expect(bs1.length).toBe(1); + expect(bs1[0].innerHTML).toBe('1-rick'); + + done(); + }); });