我正在为我们的内部框架编写可重用的组件,以抽象出一些猴子代码。大部分场景都是使用插槽实现的,效果很好。但是,某些场景需要在for循环内部渲染模板,不幸的是,那里不支持插槽。
我想出了以下(工作)代码:
<template>
<div class="form-group">
<label for.bind="titleSafe" class="control-label">{title}</label>
<select id.bind="titleSafe" value.bind="value" class="form-control">
<option repeat.for="item of itemsSource" >
<template replaceable part="item-template" containerless>${item}</template>
</option>
</select>
</div>
</template>
此代码有IMO的多个问题,使其成为将其纳入框架的不良选择:
因此我去寻找替代方案。经过一些研究,我想出了类似的东西:
<template>
<div class="form-group">
<label for.bind="titleSafe" class="control-label">{title}</label>
<select id.bind="titleSafe" value.bind="value" class="form-control">
<option repeat.for="item of itemsSource" >
<!-- I want to insert my custom element here -->
</option>
</select>
</div>
<slot></slot>
</template>
以上是我的select-item
自定义元素。然后我还会为可重复项的模板创建另一个自定义元素,比如select-item-template
,然后我会像这样使用这两个:
<select-item title="myTitle" items-source="myItems">
<select-item-template><span>${myItemsProperty}</span></select-item-template>
</select-item>
这种方法的优势在于您可以使用一个默认插槽创建复杂的“根”自定义元素。在这个插槽中,您可以定义多个自定义的'子'元素,根元素在初始化时可以搜索(我知道您可以使用@child和@children装饰器执行此操作,以便覆盖该部分)。我对如何在我的根自定义元素中使用这些自定义子元素的内容感到有点迷茫。我将如何在上面的示例中使用我的span
元素并准备它的内容以在中继?是否可以将重复的item
设置为模板的数据源,这样我就不必在模板中指定item
了?
我希望我没有把它弄得太冗长,但我想解释一下我的功能要求是什么。如果你有任何资源可以指出我正确的方向,我将非常感激!
答案 0 :(得分:8)
使用processContent
属性将元素内容转换为部件替换。该组件仍将在内部使用替换部件,但该组件的消费者不会接触到此实现细节。
https://gist.run?id=2686e551dc3b93c494fa9cc8a2aace09
<强> picker.html 强>
<template>
<label repeat.for="item of itemsSource" style="display: block">
<input type="radio" value.bind="item" checked.bind="value">
<template replaceable part="item-template">${item}</template>
</label>
</template>
<强> picker.js 强>
import {bindable, processContent} from 'aurelia-templating';
import {bindingMode} from 'aurelia-binding';
import {FEATURE} from 'aurelia-pal';
@processContent(makePartReplacementFromContent)
export class Picker {
@bindable itemsSource = null;
@bindable({ defaultBindingMode: bindingMode.twoWay }) value = null;
}
function makePartReplacementFromContent(viewCompiler, viewResources, element, behaviorInstruction) {
const content = element.firstElementChild;
if (content) {
// create the <template>
const template = document.createElement('template');
// support browsers that do not have a real <template> element implementation (IE)
FEATURE.ensureHTMLTemplateElement(template);
// indicate the part this <template> replaces.
template.setAttribute('replace-part', 'item-template');
// replace the element's content with the <template>
element.insertBefore(template, content);
element.removeChild(content);
template.content.appendChild(content);
return true;
}
}
<强>使用强>
<template>
<require from="picker"></require>
<h1>Default Item Template</h1>
<picker items-source.bind="colors" value.bind="color"></picker>
<h1>Custom Item Template</h1>
<picker items-source.bind="colors" value.bind="color">
<em css="color: ${item}">
${item}
</em>
</picker>
</template>