【问题标题】:Change element type at runtime在运行时更改元素类型
【发布时间】:2017-03-02 13:45:30
【问题描述】:

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

我想避免在以下示例中重复 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>

我知道使用 &lt;compose view="${widget.type}-view.html"&gt;&lt;/compose&gt; 进行动态组合,但据我所知,这不允许我创建默认 HTML 元素,而只能创建自定义组件,对吗?

我在 Aurelia Gitter 上问过这个问题,Erik Lieben 建议使用 @processContent(function) 装饰器,替换给定 function 中的内容并返回 true 以让 Aurelia 处理它。

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


编辑

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

【问题讨论】:

  • processContent 在这种情况下无济于事,因为它无法访问视图模型的属性(如 isLinkBtn)。

标签: aurelia aurelia-templating


【解决方案1】:

当您想重用 HTML sn-ps 时,请使用 compose。这样做不会创建新的自定义元素。它只是在每个 compose 元素的位置包含 HTML。因此,包含的 HTML 的视图模型与组成它的元素相同。

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

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

custom-link.js

import {bindable} from 'aurelia-framework';

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

custom-link-icon-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>

您可能希望将它们拆分为单独的元素,例如 &lt;custom-button&gt;&lt;custom-link&gt;,而不是使用 is-link-btn 属性控制它们的呈现。您可以使用相同的技术来重用常见的 HTML 部分,并使用装饰器组合来重用公共代码。

请参阅此 GistRun:https://gist.run/?id=e9572ad27cb61f16c529fb9425107a10

回复您的“不那么冗长”的评论

您可以使用上述GistRuninlineView 装饰器中的技术将其归为一个文件并避免compose

查看此 GistRun:https://gist.run/?id=4e325771c63d752ef1712c6d949313ce

您只需要这个文件:

custom-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;
}

【讨论】:

  • 要记住的一点是,使用compose 引入一小段 HTML 会比不干和内联代码的性能低很多。在这个问题的具体示例中,我可能倾向于重复 HTML 而不是使用compose。如果我们引入更大的 HTML 块 w/compose,那么这更有意义。您给出的答案是正确的,只是我刚才提到的警告。
  • 同意阿什利。如果不知道代码运行的上下文,就不可能判断性能是否会成为问题。我总是从使用 DRY 开始,除非我知道运行时环境需要最高效率。然后,如果测试显示不可接受的性能,我将在必要时故意违反 DRY 以提高速度。
  • 我希望有一种不那么“冗长”的方式来实现这一点,它不需要拆分元素外壳(buttona)和内容,因为内容仅包含 2 “不能独立存在”的元素,因此不需要成为一个单独的组件。
【解决方案2】:

抱歉,我一边看 gitter,一边同时做两件事,我显然不擅长 :-)

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

我不是 a11y 专家,也不是该领域的很多知识,但据我了解,这将实现您想要的。浏览器将查看角色属性并将其作为链接或按钮处理,并忽略实际的元素类型本身/不关心它是按钮还是锚点,它的行为就像它是角色中定义的类型一样。

然后你可以把它设置成一个按钮或带有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

【讨论】:

  • 我想这会起作用,尽管我实际上无法争论为什么,但我仍然希望尽可能明确地使用语义正确的标签。我会在技术上无法使用正确标签的情况下使用role(例如,由divs 或类似的东西组成的自定义comboboxes)。感谢您的建议!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多