Html 创建具有不同子类型的自定义图元

Html 创建具有不同子类型的自定义图元,html,css,dom,web-component,custom-element,Html,Css,Dom,Web Component,Custom Element,我目前正在使用自定义元素(web组件)实现一个数据表元素。该表可以有不同类型的单元格(文本、数字、日期等),用于呈现每一行 例如 我还有一个MyTableCell类,所有单元格元素都扩展了该类。这对于共享公共功能很好,但是样式设计可能会很麻烦,因为每个单元格类型都有自己的html标记。目前,我在扩展MyTableCell时添加了一个css类,但为了论证起见,假设我不想这样做 理想的解决方案是能够使用is关键字扩展自定义元素,例如 我可以想出三种解决这个问题的方法: 语法类似于,但这需要更多

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

例如


我还有一个
MyTableCell
类,所有单元格元素都扩展了该类。这对于共享公共功能很好,但是样式设计可能会很麻烦,因为每个单元格类型都有自己的html标记。目前,我在扩展
MyTableCell
时添加了一个css类,但为了论证起见,假设我不想这样做

理想的解决方案是能够使用
is
关键字扩展自定义元素,例如


我可以想出三种解决这个问题的方法:

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

  • 一种可组合的方法,其中我将渲染器元素
    包装在一个通用的
    中。这避免了自定义寄存器方法,但它更难编写,并导致更多元素和更多样板代码,这反过来意味着性能下降

  • 两者的混合,用户写入
    ,单元格在内部使用类似
    document.createElement('my-table-rendener-'+类型)
    。这保留了选项1的简单语法,同时仍然避免了自定义寄存器方法,但它具有与选项2相同的性能含义



  • 你能提出更好的选择吗?我遗漏了什么吗?

    可以做的是使用
    定制的内置元素

    <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>
    
    class CellElement extends HTMLElement {
        constructor () {
            super()
            //create cell
            switch ( this.getAttribute( 'type' ) )
            {
                case 'string': 
                    this.view = new CellStringView( this ) 
                    break
    
                default:
                    this.view = new CellView( this )
            }
        }
        connectedCallback () {
            //render cell
            this.view.render()
        }
    } 
    
    通过这种方式,所有单元扩展相同的
    元素,共享一个公共原型,但有自己的方法实现

    您可以重写共享方法,共享方法可以调用派生原型对象的特定方法

    请参见此处的运行示例:

    //表
    类DataTable扩展了HTMLTableElement{
    构造函数(){
    超级()
    console.info('data table created')
    }
    } 
    define('DataTable',DataTable,{extends:'table'});
    //细胞
    类DataCell扩展了HTMLTableCellElement{
    connectedCallback(){
    console.info('cell connected')
    if(typeof this.renderContent=='function')
    this.renderContent()
    }
    } 
    //细胞串
    类StringCell扩展了DataCell{
    renderContent()
    {
    console.info('datastringrender')
    this.innerHTML='“'+this.textContent.trim()+'”
    }
    } 
    定义('datastring',StringCell,{extends:'td'})
    表格{
    边界塌陷:塌陷;
    }
    td,th{
    边框:1px纯色灰色;
    填充:2件
    }
    测试表扩展v1
    身份证姓名年龄
    1和20
    2 Bob 31
    NB:这个答案与另一个答案是分开的,因为它本身相当广泛,完全独立

    如果使用具有(可选)
    类型
    属性的自治自定义元素(即自定义标记):

    <data-table>
        <data-row>    
            <data-cell>1</data-cell>       
            <data-cell type="string">An</data-cell>
            <data-cell type="number">20</data-cell>
        </data-row>
    </data-table>
    
    在自定义元素定义(可被视为控制器)中:

    • 创建时,实例化视图(或模型
    • 如果要渲染单元格(或处理数据),请调用视图(或模型)的(覆盖或不覆盖)方法
    自定义元素v1类的示例:

    <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>
    
    class CellElement extends HTMLElement {
        constructor () {
            super()
            //create cell
            switch ( this.getAttribute( 'type' ) )
            {
                case 'string': 
                    this.view = new CellStringView( this ) 
                    break
    
                default:
                    this.view = new CellView( this )
            }
        }
        connectedCallback () {
            //render cell
            this.view.render()
        }
    } 
    
    下面是一个实时片段:

    //视图(MVC视图)
    类CellView{
    构造函数(视图){
    this.view=视图
    }
    render(){}
    }
    //字符串视图
    类CellStringView扩展了CellView{
    render(){
    console.info('special rendering',this.view)
    this.view.innerHTML='“'+this.view.textContent+'”
    }
    }
    //元件(MVC控制器)
    类CellElement扩展了HtmleElement{
    构造函数(){
    超级()
    //创建单元
    开关(this.getAttribute('type')){
    大小写“string”:
    this.view=新的CellStringView(this)
    打破
    违约:
    this.view=新单元视图(this)
    }
    }
    connectedCallback(){
    //渲染单元
    this.view.render()
    }
    }
    自定义元素。定义('data-cell',CellElement)
    数据表{
    显示:表格;
    边界塌陷:塌陷;
    边框:1px纯色灰色;
    }
    数据行{
    显示:表格行;
    }
    数据单元{
    显示:表格单元格;
    边框:1px实心#ccc;
    填充:2px;
    }
    自定义表v1
    身份证件
    名称
    年龄
    1.
    一
    20
    2.
    上下快速移动
    31
    
    您想用v0或v1规范设计定制元素吗?我对这两种都很满意。目前正在使用v0,直到更多浏览器添加对v1的本机支持。据我所知,两个规范都有相同的限制,即不能使用
    is
    扩展自定义元素。我不明白下面的注释。使用自定义标记是我现有的解决方案(我的通用原型是上面提到的MyTableCell)。这可以用于共享功能,但有我试图避免的样式问题,因为所有单元格类型都定义自己的标记。我的节点是关于行为的。就样式而言,对于自定义标记,使用单个元素。它仍然不同于您的#2-3解决方案,因为您不需要在其中插入自定义元素。这与我的示例中的选项1基本相同,不同之处在于视图是在switch语句中预定义的。与选项1一样,如果希望允许用户定义自己的视图,则需要一种注册视图的方法,以便CellElement可以实例化视图。你以前的答案没有答案
    class CellElement extends HTMLElement {
        constructor () {
            super()
            //create cell
            switch ( this.getAttribute( 'type' ) )
            {
                case 'string': 
                    this.view = new CellStringView( this ) 
                    break
    
                default:
                    this.view = new CellView( this )
            }
        }
        connectedCallback () {
            //render cell
            this.view.render()
        }
    }