我有一组Polymer组件,它们是另一个组件的子类。我想基于子类的模板填充超类的模板。 (对于寻找类似问题解决方案的其他人,请参阅here,遗憾的是没有解决方案。)用法如下所示:
<!-- control.html -->
<media-tabs tabs-title="Alternative input">
<template>
<media-blackout></media-blackout>
<media-slates></media-slates>
<media-playlists></media-playlists>
<media-queue></media-queue>
</template>
</media-tabs>
<!-- media-tabs.html -->
<paper-card heading="[[tabsTitle]]" class="fill-h fill-v">
<div class="card-content">
<paper-tabs id="tabs" selected="{{selectedIndex}}" selectable>
</paper-tabs>
<iron-pages id="content" selected="{{selectedIndex}}">
</iron-pages>
</div>
</paper-card>
// media-tabs.js
ready() {
super.ready();
this.selectedIndex = 0;
const template = this.querySelector('template');
const instance = this._stampTemplate(template);
const tabs = Array.from(instance.children);
tabs.forEach((elm) => {
const content = elm.constructor.template.content;
this.$.tabs.appendChild(content.querySelector('#title'));
this.$.content.appendChild(content.querySelector('#content'));
});
}
<!-- media-tab.html -->
<paper-tab id="title"></paper-tab>
<div id="content"></div>
<!-- media-blackout.html -->
<span id="title">Blackout</span>
<div id="content">
<p>Lorem ipsum dolor sit amet</p>
</div>
<!-- repeat above for media-playlists, media-queue, and media-slates -->
// media-blackout.js -- is a subclass of media-tab
static get template() {
if (!superTemplate) {
const thisTemplate = Polymer.DomModule.import(this.is, 'template');
superTemplate = MediaTab.template.cloneNode(true);
const title = thisTemplate.content.querySelector('#title').textContent;
const content = thisTemplate.content.querySelector('#content');
const children = Array.from(content.children);
superTemplate.content.querySelector('#title').innerHTML = title;
children.forEach((child) => {
superTemplate.content.querySelector('#content').appendChild(child);
});
}
return superTemplate;
}
// repeat above for media-playlists, media-queue, and media-slates
此设置有效。但是,媒体选项卡子类中的template()
getter 相同,我想找到一种方法将该逻辑移动到超类中,而不需要知道超类中的代码子类实现细节。
我试图为超类需要提取的两个字段(例如const title = this.templateTitleElement.textContent;
)创建getter,但是我的实现要么以某种方式戳元素的template
属性(导致堆栈溢出),或者尝试在元素可用之前访问(例如,return this.$.title;
)。
答案 0 :(得分:0)
我设法使用mixins提出解决方案;它不是传统OOP的继承,但它的功能却没有复制相同的功能四次。
// title-content-mixin.js
const titleContentMixin = (function() {
const titleContentMixin = (superClass, options = {}) => {
const titleQuery = options.titleQuery || '#title';
const contentQuery = options.contentQuery || '#content';
const superTitleQuery = options.superTitleQuery || titleQuery;
const superContentQuery = options.superContentQuery || contentQuery;
return class TitleContentMixin extends superClass {
static get template() {
if (this.is === superClass.is || superClass.is.length === 0) return;
const thisTemplate = Polymer.DomModule.import(this.is, 'template')
.cloneNode(true);
const superTemplate = superClass.template.cloneNode(true);
const title = thisTemplate.content.querySelector(titleQuery).textContent;
const content = thisTemplate.content.querySelector(contentQuery);
const children = Array.from(content.children);
superTemplate.content.querySelector(superTitleQuery).innerHTML = title;
children.forEach((child) => {
superTemplate.content.querySelector(superContentQuery)
.appendChild(child);
});
return superTemplate;
}
};
};
return Polymer.dedupingMixin(titleContentMixin);
})();
// media-blackout.js
class MediaBlackout extends titleContentMixin(MediaTab) {
// ...
}
// repeat above for media-playlists, media-queue, and media-slates
答案 1 :(得分:0)
我以前的解决方案存在从标签内容中冒泡事件的问题,因此我不得不提出另一种解决方案:
<!-- control.html -->
<media-tabs tabs-title="Alternative input" on-play-slate="handlePlayTapped">
<media-blackout></media-blackout>
<media-slates></media-slates>
<media-playlists></media-playlists>
<media-queue></media-queue>
</media-tabs>
您可以看到我已从media-tabs
声明中删除了该模板。
<!-- media-tabs.html -->
<paper-card heading="[[tabsTitle]]">
<div class="card-content">
<paper-tabs id="tabs" selected="{{selectedIndex}}" selectable></paper-tabs>
<iron-pages id="content" selected="[[selectedIndex]]">
<slot></slot>
</iron-pages>
</div>
</paper-card>
您可以看到我已将<slot>
插入点添加到铁页。
// media-tabs.js
ready() {
super.ready();
const children = Array.from(this.children);
children.forEach((child) => {
const template = Object.getPrototypeOf(child.constructor).template;
const instance = this._stampTemplate(template);
instance.$.title.innerHTML = child.tabTitle;
this.$.tabs.appendChild(instance.$.title);
});
}
现在我只将儿童附加到paper-tabs
元素,而不是paper-tabs
和iron-pages
。 Object.getPrototypeOf(child.constructor)
返回child
超类的构造函数;这意味着我不仅仅假设孩子的超类是MediaTab,虽然这可以改进,因为我我假设孩子的超类有一个{{1的元素}和一个属性id="title"
。
tabTitle
<!-- media-tab.html -->
<paper-tab id="title"></paper-tab>
// media-tab.js
static get properties() {
return {
tabTitle: String,
};
}
模板不再包含内容div,超类定义media-tab
中引用的tabTitle
属性。
media-tabs.js
<!-- media-blackout.html -->
<p>Lorem ipsum dolor sit amet</p>
<!-- repeat above for media-playlists, media-queue, and media-slates -->
子类不再将其标签标题存储在HTML中,它们只包含内容。
media-tab
不是在// media-blackout.js
class MediaBlackout extends MediaTab {
// ...
static get properties() {
return {
tabTitle: {
type: String,
value: 'Blackout',
readOnly: true,
},
};
}
}
// repeat above for media-playlists, media-queue, and media-slates
中使用子类的标题,而是将其定义为类的属性。
此解决方案不使用mixin,从span
元素中触发的事件可能会冒泡到应用程序的顶部。