2017-11-10 85 views
0

我有一组聚合物组件是另一个组件的子类。我想根据子类的模板填充超类的模板。 (见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 

这个设置工作。然而,在media-tab子类中,template()获取方为相同,我想找到一种将该逻辑移入超类的方法,而超类中的代码不需要知道子类实现细节。

我试图为超类需要拉的两个字段(例如const title = this.templateTitleElement.textContent;)创建getter,但是我的实现要么以某种方式戳元素的template属性(导致堆栈溢出),要么尝试在可用之前访问元素(例如,return this.$.title;)。

回答

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>插入点添加到iron-pages。

// 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-tabsiron-pagesObject.getPrototypeOf(child.constructor)返回child的超类的构造函数;这意味着我不是简单地假设孩子的超类是MediaTab,尽管这可以改进,因为我假设孩子的超类有一个元素id="title"和属性tabTitle

<!-- media-tab.html --> 
<paper-tab id="title"></paper-tab> 
// media-tab.js 
static get properties() { 
    return { 
    tabTitle: String, 
    }; 
} 

media-tab模板不包含内容的div任何更多,并且超定义tabTitle财产media-tabs.js引用。

<!-- media-blackout.html --> 
<p>Lorem ipsum dolor sit amet</p> 
<!-- repeat above for media-playlists, media-queue, and media-slates --> 

media-tab子不再存储在HTML的分页标题,他们只有内容。

// 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 

而不必在span子类的称号,它被定义为类的属性。

此解决方案不使用mixin,并且从MediaTab元素中触发的事件可以冒泡到应用程序的顶部。

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