Изменить тип элемента во время выполнения
Можно ли динамически определять тип элемента внутри шаблона пользовательских компонентов во время выполнения?
Я хотел бы избежать дублирования внутреннего содержимого button
а также a
элемент в следующем примере:
<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-элементы по умолчанию, а только пользовательские компоненты, правильно?
Я задал этот вопрос на Aurelia Gitter, где Эрик Либен предложил использовать @processContent(function)
декоратор, заменить содержимое в рамках данного function
и вернуться true
позволить Аурелии обработать это.
К сожалению, я не знаю, как на самом деле применять эти инструкции, и я надеюсь на некоторые альтернативные подходы здесь или некоторые детали о том, как на самом деле это сделать.
редактировать
Я создал соответствующий запрос функции. Несмотря на то, что были предоставлены возможные решения, я хотел бы увидеть более простой способ решить эту проблему;)
2 ответа
Если вы хотите повторно использовать фрагменты HTML, используйте compose. Это не создает новый пользовательский элемент. Он просто включает HTML-код в месте расположения каждого элемента compose. Таким образом, модель представления для включенного 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;
}
заказ канального значок-и-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
Ответ на ваш "менее многословный" комментарий
Вы можете записать его в один файл и избежать compose
используя методы в вышеупомянутом GistRun и inlineView
декоратор:
Смотрите этот GistRun: https://gist.run/?id=4e325771c63d752ef1712c6d949313ce
Все, что вам нужно, это один файл:
таможенно-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;
}
Извините, я делал 2 вещи одновременно, глядя на gitter, что я не очень хорошо, по-видимому:-)
Для вещи, которую вы хотели достичь в конце концов, это могло бы сработать?
Я не являюсь экспертом в этой области или обладаю большими знаниями в этой области, но, насколько я понимаю, это поможет вам достичь желаемого. Браузер будет смотреть на атрибут role и обрабатывать его как ссылку или кнопку, игнорируя сам фактический тип элемента / ему будет все равно, будет ли он кнопкой или привязкой, он будет действовать так, как если бы он имел тип, определенный в роли.
Затем вы можете стилизовать его как кнопку или тег ссылки с помощью 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