html - 创建具有不同子类型的自定义元素

标签 html css dom web-component custom-element

我目前正在使用自定义元素(网络组件)实现数据表元素。表格可以包含用于呈现每一行的不同类型的单元格(文本、数字、日期等)。

例如

<my-table>
    <my-table-cell-text column="name"></my-table-cell-text>
    <my-table-cell-date column="dob" format="YYYY-MM-DD"></my-table-cell-date>
    <my-table-cell-number column="salary" decimals="2"></my-table-cell-number >
</my-table>

我还有一个 MyTableCell所有单元格元素扩展的类。这对于共享通用功能来说效果很好,但是样式可能会很麻烦,因为每个单元格类型都是它自己的 html 标签。目前,我在扩展 MyTableCell 时添加了一个 css 类,但为了争论起见,假设我不想那样做。

理想的解决方案是能够扩展自定义元素,使用 is关键字,例如 <my-table-cell is="my-table-cell-text"> , but that's only allowed for built in html elements .


我可以想到 3 种方法来解决这个问题:

  1. 语法类似于 <input type=""> ,但这需要做更多的工作,因为您不再扩展基类,而是创建同一元素的变体,这意味着您需要一种自定义方式来注册不同的变体,例如静态 MyTableCell.registerType

  2. 一种可组合的方法,我包装了一个渲染器元素,<my-table-renderer-text> , 在通用 <my-table-cell> 内.这避免了自定义寄存器方法,但更难编写并导致更多元素和更多样板代码,这反过来又意味着性能下降。

  3. 两者的混合,用户在其中写入 <my-table-cell type="text">并且单元格使用类似 document.createElement('my-table-rendener-'+ type) 的东西在内部。这保留了选项 1 的更简单语法,同时仍然避免了自定义寄存器方法,但它具有与选项 2 相同的性能影响。


您能推荐更好的选择吗?我错过了什么吗?

最佳答案

可以做的是使用 <td>自定义内置元素:

<table is="data-table>
   <tr>
       <td is="data-string">Bob</td>
       <td is="data-date">11/1/2017</td>
       <td is="data-number">44<td>
   </tr>
</table>

所有扩展共享同一个原型(prototype)祖先。示例:

//common cell
class DataCell extends HTMLTableCellElement {...}

//typed cell
class StringCell extends DataCell {
    renderContent() { ... }
} 
customElements.define( 'data-string', StringCell, { extends: 'td' } )

这样所有单元格都扩展相同的 <td>元素,共享一个通用原型(prototype),但有自己的方法实现。

可以覆盖共享方法,共享方法可以调用派生原型(prototype)对象的特定方法。

在此处查看运行示例:

//table
class DataTable extends HTMLTableElement {
    constructor() { 
        super()
        console.info( 'data-table created' )
    }
} 
customElements.define( 'data-table', DataTable, { extends: 'table' } );

//cell
class DataCell extends HTMLTableCellElement {
    connectedCallback() { 
        console.info( 'cell connected' )
        if ( typeof this.renderContent === 'function' ) 
            this.renderContent()
    }
} 

//cell string
class StringCell extends DataCell {
    renderContent()
    {
        console.info( 'data-string render' )
        this.innerHTML = '"' + this.textContent.trim() + '"'
    }
} 
customElements.define( 'data-string', StringCell, { extends: 'td' } )
table {
    border-collapse: collapse ;
}
td, th {
    border: 1px solid gray ;
    padding: 2px
}
<h4>Test Table Extension v1</h4>
<table is="data-table">
    <tr>
        <th>Id      <th>Name    <th>Age
    <tr>    
        <td>1       <td is="data-string">An      <td>20
    <tr>
        <td>2       <td is="data-string">Bob     <td>31

注意:如果您不想要类型扩展,您也可以使用自定义标签来实现。这个想法是拥有一个通用原型(prototype)和共享它的不同自定义元素(由于标准原型(prototype)继承)。

关于html - 创建具有不同子类型的自定义元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41585527/

相关文章:

javascript - 读取二进制文件并进行 base64 编码

html - 我们可以在图像上使用 <figcaption> 而不使用 <figure>

javascript - JS to keep css selector hover state on - css animation, 已经尝试了多个答案但没有成功

javascript - DOM & JavaScript - 什么时候获取 JavaScript 文件的合适时机?

javascript - 使用 DOM 获取要从 div 中删除的选中复选框的值

javascript - 如何创建一个 Kendo UI jQuery kendoDropDownList 仍然允许用户输入?

javascript - 在单个页面上绘制多个 Canvas

html - Firefox 与 Chrome CSS 填充和边距差异

html - 如何更改 "Browse"按钮文本

java - 获取具有相同父级的 HTML 节点 - JAVA