【问题标题】:Vanilla Custom Element repeater for <option>, <li>, <td><option>、<li>、<td> 的香草自定义元素中继器
【发布时间】:2017-03-29 07:00:39
【问题描述】:

我目前正在尝试实现一个转发器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 并且通过扩展,破坏该功能并仅显示 @987654327 @

这是我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 的唯一原因。

【问题讨论】:

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


    【解决方案1】:

    解决方案 1

    在您的元素周围放置中继器。前任。对于最小的&lt;data-repeater&gt; 自定义元素:

    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

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

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

    如果渲染因元素而有很大差异,您可以决定创建一个用于渲染的类,并为每种渲染类型(select、ul、tr、td)使用派生类,例如this example for tables

    【讨论】:

    • 我怀疑它会解决我的问题,它只是允许我不声明父元素,但如果我仍然想把它放在我的 HTML 中我想要的位置,问题会是一样的。
    • 还是同样的问题,如果我检查我的 DOM,company-repeat 元素不存在,因此,它甚至不会触发 connectedCallback
    • 采用第一个解决方案,我还在我的选项中添加了一个repeater 属性,以了解我应该重复哪个元素。谢谢:)
    猜你喜欢
    • 2019-02-03
    • 2015-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 2017-05-24
    • 2018-09-11
    相关资源
    最近更新 更多