香草定制元素中继器<option>,<li>,

时间:2017-03-29 07:00:39

标签: javascript html dom web-component custom-element

我目前正在尝试实施转发器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正确地工作,因为它似乎对内部允许的标记没有限制,但是选择不允许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,但是它不允许我声明更多的属性,并且它将不会在表中工作。

这是阻止我将所有内容移动到WebComponent的唯一方法。

1 个答案:

答案 0 :(得分:5)

解决方案1 ​​

将转发器放在元素周围。防爆。最小<data-repeater>自定义元素:

&#13;
&#13;
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('')
  }
})
&#13;
<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>
&#13;
&#13;
&#13;

解决方案2

使用自定义的内置元素。您需要为要扩展的每个标准元素选择一个新名称,但是您可以在内部重用一个唯一的基类来呈现元素:

<select is="repeat-option" data-values="[...]">
   <option value="${value}">${name}</option>
</select>

&#13;
&#13;
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('')
}
&#13;
<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>
&#13;
&#13;
&#13;

如果渲染因元素而异,您可以决定创建一个渲染类,并为渲染的每个类型使用派生类(select,ul,tr,td),就像在this example for tables中一样。