创建具有不同子类型的自定义元素 [英] Create a Custom Element with different sub-types

查看:97
本文介绍了创建具有不同子类型的自定义元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



例如

 < my-table> 
< my-table-cell-text column =name>< / my-table-cell-text>
< my-table-cell-date column =dobformat =YYYY-MM-DD>< / my-table-cell-date>
< my-table-cell-number column =salarydecimals =2>< / my-table-cell-number>
< / my-table>

我还有一个 MyTableCell 电池元件延伸。这对共享通用功能起作用,但是造型可能会很痛苦,因为每个单元格类型都是自己的html标签。目前,我在扩展 MyTableCell 时添加了一个css类,但是为了说明这一点,让我说我不想这样做。



理想的解决方案是使用关键字来扩展自定义元素,例如< my-table -cell is =my-table-cell-text> ,但只允许内置html元素






I可以想到解决这个问题的三种方法:


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


  2. 一个可组合的方法,我包装一个渲染器eleme nt,< 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 / 2017< / td>
< td is =data-number> 44< td>
< / tr>
< / table>

所有扩展程序共享相同的原型祖先。 v0 的示例:

  // common cell 
var cellProto = Object.create(HTMLTableCellElement.protoype)
cellProto.sharedMethod = function(){...}

//键入的单元格
var cellStringProto = Object.create(cellProto)
cellStringProto.specificMethod = function(){...}
cellStringProto.sharedMethod = function (){...}
document.registerElement('data-string',{prototype:ce llStringProto,extends:'td'})

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



可以覆盖共享方法,共享方法可以调用派生原型对象的具体方法。



看到一个正在运行的示例:



  // table var tableProto = Object.create(HTMLTableElement.prototype)tableProto.createdCallback = function(){console.info('data-table创建')} document.registerElement('data-table',{prototype:tableProto,extends:'table'})// cell var cellProto = Object.create(HTMLTableCellElement.prototype)cellProto.createdCallback = function() {console.info('cell created')} cellProto.attachedCallback = function(){console.info('cell attached')if(typeof this.renderContent ==='function')this.renderContent()} // cell string var cellStringProto = Object.create(cellProto)cellStringProto.createdCallback = function(){console.info('data-string created')} cellStringProto.renderContent = function(){console.info('data-string render')this .innerHTML ='''+ this.textContent.trim()+''} document.registerElement('data-string',{prototype:cellStringProto,extends:'td'}) pre> 

  table {border-collapse:collapse;} td,th {border:1px solid gray; padding:2px}  

 < h4>测试表扩展v0 ; / h4>< table is =data-table> < TR> < th> Id< th>名称< th>年龄< tr> < td> 1< td is =data-string> An< td> 20< tr& < td> 2< td is =data-string> Bob< td> 31  



注意:如果您不想输入扩展名,还可以使用自定义标签。这个想法是拥有共同的原型和不同的自定义元素(由于标准原型继承)。


I am currently implementing a data-table element using custom elements (web components). The table can have different types of cells (text, number, date, etc) that are used to render each row.

E.g

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

I also have a MyTableCell class which all cell elements extends. This works fine for sharing common functionality, however styling can be a pain, because each cell type is its own html tag. Currently, I am adding a css class when extending MyTableCell, but for argument's sake, lets say I don't want to do that.

The ideal solution would be to be able to extend a custom element, using the is keyword, e.g <my-table-cell is="my-table-cell-text">, but that's only allowed for built in html elements.


I can think of 3 approaches of solving this issue:

  1. Have syntax similar to <input type="">, but that's a lot more work, since you are no longer extending a base class, but rather creating variations of the same element and this means you need a custom way of registering the different variations, something like a static MyTableCell.registerType

  2. A composable approach, where I wrap a renderer element, <my-table-renderer-text>, inside a generic <my-table-cell>. This avoids the custom register method, but it's harder to write and results in more elements and more boilerplate code, which in turn means a performance hit.

  3. A mix of both, where the user writes <my-table-cell type="text"> and the cell uses something like document.createElement('my-table-rendener-'+ type) internally. This keeps the simpler syntax of option 1, while still avoiding the custom register method, but it has the same performance implications of option 2.


Can you suggest any better alternatives? Am I missing anything?

解决方案

What could be done is using <td> type extensions:

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

All extensions share the same prototype ancestor. Example with v0:

  //common cell
  var cellProto = Object.create( HTMLTableCellElement.protoype )
  cellProto.sharedMethod = function () { ... }

  //typed cell
  var cellStringProto = Object.create( cellProto )
  cellStringProto.specificMethod = function () { ... }
  cellStringProto.sharedMethod = function () { ... }
  document.registerElement( 'data-string', { prototype: cellStringProto, extends: 'td' } )

This way all cells extend the same <td> element, share a common prototype but have their own method implementations.

You can override shared method, and shared method can call specific method of the derived prototype object.

See a running example here:

    //table
    var tableProto = Object.create( HTMLTableElement.prototype )
    tableProto.createdCallback = function ()
    {
        console.info( 'data-table created' )
    }
    document.registerElement( 'data-table', { prototype: tableProto, extends: 'table' } )

    //cell
    var cellProto = Object.create( HTMLTableCellElement.prototype )
    cellProto.createdCallback = function ()
    {
        console.info( 'cell created' )
    }
    cellProto.attachedCallback = function ()
    {
        console.info( 'cell attached' )
        if ( typeof this.renderContent === 'function' ) 
            this.renderContent()
    }

    //cell string
    var cellStringProto = Object.create( cellProto )
    cellStringProto.createdCallback = function ()
    {
        console.info( 'data-string created' )
    }
    cellStringProto.renderContent = function ()
    {
        console.info( 'data-string render' )
        this.innerHTML = '"' + this.textContent.trim() + '"'
    }
    
    document.registerElement( 'data-string', { prototype: cellStringProto, extends: 'td' } )

table {
    border-collapse: collapse ;
}
td, th {
    border: 1px solid gray ;
    padding: 2px
}

<h4>Test Table Extension v0</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

Note: If you don't want type extension you can also do it with custom tags. The idea is to have a common prototype and different custom elements that share it (thanks to standard prototype inheritance).

这篇关于创建具有不同子类型的自定义元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆