<option>、<li>、<td> 的香草自定义元素中继器
Vanilla Custom Element repeater for <option>, <li>, <td>
我目前正在尝试实现一个中继器 WebComponent
以允许公司轻松创建前端而不依赖于任何 framework
(由架构决定)。
这是我当前的代码:
<ul>
<company-repeat datas='[{"name": "NameValeur", "value": "valeurId"}, {"name": "NameObject", "value": "objectId"}]'>
<li>${name}</option>
</company-repeat>
</ul>
<select name="" id="">
<company-repeat datas='[{"name": "NameValeur", "value": "valeurId"}, {"name": "NameObject", "value": "objectId"}]'>
<option value="${value}">${name}</option>
</company-repeat>
</select>
list
正常工作,因为它似乎对内部允许的标签没有限制,但 select 不允许 customElement
company-repeat
在其中并通过扩展,破坏功能并仅显示 <option value="${value}">${name}</option>
这是我的 WebComponent
的源代码
class CompanyRepeater extends HTMLElement {
connectedCallback() {
this.render();
}
render() {
let datas = JSON.parse(this.getAttribute('datas'));
let elementType = this.getAttribute('element');
this.template = this.innerHTML;
console.log(elementType);
let htmlContent = elementType !== null ? `<${elementType.toLowerCase()}>` : '';
datas.forEach(elem => {
htmlContent += this.interpolate(this.template, elem)}
);
htmlContent += elementType !== null ? `</${elementType.toLowerCase()}>` : '';
this.innerHTML = htmlContent;
}
interpolate(template, obj) {
for(var key in obj) {
const pattern = "${" + key + "}";
if(template.indexOf(pattern) > -1) {
template = template.replace(pattern, obj[key]);
delete(obj[key]);
}
};
return template;
}
}
customElements.define('company-repeat', CompanyRepeater);
我现在的问题是,无论父元素是什么,我怎样才能让它工作?我已经在我的转发器中添加了一个 属性 element
,但它不允许我声明更多属性,并且它会在 table.
中不起作用
这是唯一阻止我将所有内容移动到 WebComponent 的东西。
解决方案 1
将中继器放在您的元素周围。前任。对于最小的 <data-repeater>
自定义元素:
customElements.define('data-repeater', class extends HTMLElement
{
connectedCallback()
{
const parent = this.firstElementChild
const data = JSON.parse(this.dataset.values)
const interpolate = obj => parent.innerHTML.replace(
/${(\w+)}/g,
(match, key) => obj[key]
)
parent.innerHTML = data.map(interpolate).join('')
}
})
<data-repeater data-values='[{"label": "Item 1", "id":1}, {"label": "Item 2", "id": 2}]'>
<ul>
<li id="${id}">${label}</li>
</ul>
</data-repeater>
<data-repeater data-values='[{"name": "option 1", "value":1}, {"name": "option 2", "value": 2}]'>
<select>
<option value="${value}">${name}</option>
</select>
</data-repeater>
解决方案 2
使用自定义的内置元素。您需要为每个要扩展的标准元素选择一个新名称,但您可以在内部重用一个唯一的基础 class 来呈现元素:
<select is="repeat-option" data-values="[...]">
<option value="${value}">${name}</option>
</select>
customElements.define('select-repeater', class extends HTMLSelectElement {
connectedCallback() { render(this) }
}, { extends: 'select' })
customElements.define('ul-repeater', class extends HTMLUListElement {
connectedCallback() { render(this) }
}, { extends: 'ul' })
function render(view) {
const data = JSON.parse(view.dataset.values)
const interpolate = obj => view.innerHTML.replace(
/${(\w+)}/g,
(match, key) => obj[key]
)
view.innerHTML = data.map(interpolate).join('')
}
<script src="https://rawgit.com/WebReflection/document-register-element/master/build/document-register-element.js"></script>
<ul is="ul-repeater" data-values='[{"label": "Item 1", "id":1}, {"label": "Item 2", "id": 2}]'>
<li id="${id}">${label}</li>
</ul>
<select is="select-repeater" data-values='[{"name": "option 1", "value":1}, {"name": "option 2", "value": 2}]'>
<option value="${value}">${name}</option>
</select>
如果渲染因元素而异,您可以决定为渲染创建一个 class 并为每种渲染类型使用派生的 classes(select, ul, tr, td ), 如 .
我目前正在尝试实现一个中继器 WebComponent
以允许公司轻松创建前端而不依赖于任何 framework
(由架构决定)。
这是我当前的代码:
<ul>
<company-repeat datas='[{"name": "NameValeur", "value": "valeurId"}, {"name": "NameObject", "value": "objectId"}]'>
<li>${name}</option>
</company-repeat>
</ul>
<select name="" id="">
<company-repeat datas='[{"name": "NameValeur", "value": "valeurId"}, {"name": "NameObject", "value": "objectId"}]'>
<option value="${value}">${name}</option>
</company-repeat>
</select>
list
正常工作,因为它似乎对内部允许的标签没有限制,但 select 不允许 customElement
company-repeat
在其中并通过扩展,破坏功能并仅显示 <option value="${value}">${name}</option>
这是我的 WebComponent
class CompanyRepeater extends HTMLElement {
connectedCallback() {
this.render();
}
render() {
let datas = JSON.parse(this.getAttribute('datas'));
let elementType = this.getAttribute('element');
this.template = this.innerHTML;
console.log(elementType);
let htmlContent = elementType !== null ? `<${elementType.toLowerCase()}>` : '';
datas.forEach(elem => {
htmlContent += this.interpolate(this.template, elem)}
);
htmlContent += elementType !== null ? `</${elementType.toLowerCase()}>` : '';
this.innerHTML = htmlContent;
}
interpolate(template, obj) {
for(var key in obj) {
const pattern = "${" + key + "}";
if(template.indexOf(pattern) > -1) {
template = template.replace(pattern, obj[key]);
delete(obj[key]);
}
};
return template;
}
}
customElements.define('company-repeat', CompanyRepeater);
我现在的问题是,无论父元素是什么,我怎样才能让它工作?我已经在我的转发器中添加了一个 属性 element
,但它不允许我声明更多属性,并且它会在 table.
这是唯一阻止我将所有内容移动到 WebComponent 的东西。
解决方案 1
将中继器放在您的元素周围。前任。对于最小的 <data-repeater>
自定义元素:
customElements.define('data-repeater', class extends HTMLElement
{
connectedCallback()
{
const parent = this.firstElementChild
const data = JSON.parse(this.dataset.values)
const interpolate = obj => parent.innerHTML.replace(
/${(\w+)}/g,
(match, key) => obj[key]
)
parent.innerHTML = data.map(interpolate).join('')
}
})
<data-repeater data-values='[{"label": "Item 1", "id":1}, {"label": "Item 2", "id": 2}]'>
<ul>
<li id="${id}">${label}</li>
</ul>
</data-repeater>
<data-repeater data-values='[{"name": "option 1", "value":1}, {"name": "option 2", "value": 2}]'>
<select>
<option value="${value}">${name}</option>
</select>
</data-repeater>
解决方案 2
使用自定义的内置元素。您需要为每个要扩展的标准元素选择一个新名称,但您可以在内部重用一个唯一的基础 class 来呈现元素:
<select is="repeat-option" data-values="[...]">
<option value="${value}">${name}</option>
</select>
customElements.define('select-repeater', class extends HTMLSelectElement {
connectedCallback() { render(this) }
}, { extends: 'select' })
customElements.define('ul-repeater', class extends HTMLUListElement {
connectedCallback() { render(this) }
}, { extends: 'ul' })
function render(view) {
const data = JSON.parse(view.dataset.values)
const interpolate = obj => view.innerHTML.replace(
/${(\w+)}/g,
(match, key) => obj[key]
)
view.innerHTML = data.map(interpolate).join('')
}
<script src="https://rawgit.com/WebReflection/document-register-element/master/build/document-register-element.js"></script>
<ul is="ul-repeater" data-values='[{"label": "Item 1", "id":1}, {"label": "Item 2", "id": 2}]'>
<li id="${id}">${label}</li>
</ul>
<select is="select-repeater" data-values='[{"name": "option 1", "value":1}, {"name": "option 2", "value": 2}]'>
<option value="${value}">${name}</option>
</select>
如果渲染因元素而异,您可以决定为渲染创建一个 class 并为每种渲染类型使用派生的 classes(select, ul, tr, td ), 如