2017-03-02 141 views
3

是否可以在运行时动态定义自定义组件模板内的元素类型?在运行时更改元素类型

我想,以避免在下面的示例中的buttona元件的内部重复内容:

<template> 
    <button if.bind="!isLinkBtn"> 
     <span class="btn-icon">${icon}</span> 
     <span class="btn-text">${contentText}</span> 
    </button> 

    <a if.bind="isLinkBtn"> 
     <!-- 
     The content is a 1:1 duplicate of the button above which should be prevented 
     somehow in order to keep the view DRY 
     --> 
     <span class="btn-icon">${icon}</span> 
     <span class="btn-text">${contentText}</span> 
    </a> 
</template> 

是否有可能写的是这样的:

<template> 
    <!-- 
    The type of element should be defined at runtime and can be a standard HTML "button" 
    or an anchor "a" 
    --> 
    <element type.bind="${isLinkBtn ? 'a' : 'button'}"> 
     <span class="btn-icon">${icon}</span> 
     <span class="btn-text">${contentText}</span> 
    </element> 
</template> 

我我知道<compose view="${widget.type}-view.html"></compose>的动态组合,但据我所知,这不会让我创建默认的HTML元素,但只有自定义组件,是否正确?

我问过的奥里利亚本的Gitter问题,其中埃里克Lieben建议使用@processContent(function)装饰,取代指定function内的内容,并返回true让Aurelia路上对其进行处理。

不幸的是,我不知道如何实际应用这些说明,并希望在这里找到一些替代方法或有关如何实际完成此操作的一些细节。


编辑

我创建了一个相应的feature request。尽管已经提供了可能的解决方案,但是我希望看到一些更简单的方法来解决这个问题;)

+0

'processContent'不会在这种情况下帮助,因为它不会有访问视图模型的属性(如'isLinkBtn') 。 –

回答

3

当您要重用HTML片段时,请使用撰写。这样做不是创建一个新的自定义元素。它只是在每个撰写元素的位置包含HTML。因此,包含的HTML的视图模型与构成它的元素的视图模型相同。

看看这个GistRun:https://gist.run/?id=36cf2435d39910ff709de05e5e1bedaf

定制link.html

<template> 
    <button if.bind="!isLinkBtn"> 
     <compose view="./custom-link-icon-and-text.html"></compose> 
    </button> 

    <a if.bind="isLinkBtn" href="#"> 
     <compose view="./custom-link-icon-and-text.html"></compose> 
    </a> 
</template> 

定制link.js

import {bindable} from 'aurelia-framework'; 

export class CustomLink { 
    @bindable() contentText; 
    @bindable() icon; 
    @bindable() isLinkBtn; 
} 

定制链接图标-and-text.html

<template> 
    <span class="btn-icon">${icon}</span> 
    <span class="btn-text">${contentText}</span> 
</template> 

consumer.html

<template> 
    <require from="./custom-link"></require> 
    <custom-link content-text="Here is a button"></custom-link> 
    <custom-link is-link-btn.bind="true" content-text="Here is a link"></custom-link> 
</template> 

您可能希望将这些拆分为单独的元素,如<custom-button><custom-link>,而不是使用is-link-btn属性控制他们的介绍。您可以使用相同的技术来重新使用常见的HTML部分,并使用装饰器进行合成以重用通用代码。

看到这个GistRun:https://gist.run/?id=e9572ad27cb61f16c529fb9425107a10

回应你的“不那么冗长”评论

你可以把它降低到一个文件,并使用上述GistRun技术和inlineView装饰避免compose

看到这个GistRun:https://gist.run/?id=4e325771c63d752ef1712c6d949313ce

所有您东东d是这样的一个文件:

定制links.js

import {bindable, inlineView} from 'aurelia-framework'; 

function customLinkElement() { 
    return function(target) { 
     bindable('contentText')(target); 
     bindable('icon')(target); 
    } 
} 


const tagTypes = {button: 'button', link: 'a'}; 


@inlineView(viewHtml(tagTypes.button)) 
@customLinkElement() 
export class CustomButton { 

} 


@inlineView(viewHtml(tagTypes.link)) 
@customLinkElement() 
export class CustomLink { 

} 


function viewHtml(tagType) { 
    let result = ` 
    <template> 
     <${tagType}${tagType === tagTypes.link ? ' href="#"' : ''}> 
      <span class="btn-icon">\${icon}</span> 
      <span class="btn-text">\${contentText}</span> 
     </${tagType}> 
    </template> 
    `; 

    return result; 
} 
+1

有一点需要记住的是,使用'compose'来引入小块HTML会比仅仅不进行DRY和内联代码的性能低得多。在这个问题的具体例子中,我可能倾向于重复HTML而不是使用'compose'。如果我们引入更大的HTML组合,那么这就更有意义了。你刚刚提到的答案是正确的。 –

+1

同意阿什利。如果不知道代码将运行的上下文,就不可能知道性能是否会成为问题。除非我知道运行时环境需要最高效率,否则我总是先开始使用DRY。然后,如果测试显示不可接受的性能,我会故意违反DRY以提高速度。 –

+0

我希望以一种不太“冗长”的方式来实现这一点,它不需要拆分元素shell('button'或'a')&内容,因为内容仅包含2个元素,它们“无法生存“独立,因此并不需要成为一个独立的组件。 – suamikim

1

对不起,我同时做两件事情,而看小胶质,对此我并不擅长显然:-)

对于你想最终完成的事情,这也可以吗?

我不是一个专家,或者在这个领域有很多知识,但从我的理解,这将完成你想要的。浏览器将查看角色属性并将其作为链接或按钮进行处理,并忽略实际的元素类型本身/不会在乎它是按钮还是锚点,它会像在角色中定义的类型那样操作。

然后,你可以像使用css的按钮或链接标签来设计它。

<a role.bind="type"><span>x</span><span>y</span></a> 

哪里类型是链接或按钮,看到以下内容:https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_link_role

+0

我想这会工作,即使我不能争辩为什么,我仍然希望尽可能明确地使用语义正确的标记。在技​​术上不可能使用正确标记的情况下(例如,由'divs'组成的自定义'comboboxes'等等),我会使用'role'。感谢任何方式的建议! – suamikim