我目前正在使用自定义元素(Web组件)实现数据表元素。该表可以具有不同类型的单元格(文本,数字,日期等),用于呈现每一行。
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>
我还有一个MyTableCell
类,所有单元格元素都会扩展。这适用于共享通用功能,但样式可能很痛苦,因为每个单元格类型都是自己的html标记。目前,我在扩展MyTableCell
时添加了一个css类,但为了论证,我们可以说我不想这样做。
理想的解决方案是能够使用is
关键字扩展自定义元素,例如<my-table-cell is="my-table-cell-text">
,but that's only allowed for built in html elements。
我可以想到解决这个问题的3种方法:
语法类似于<input type="">
,但由于您不再扩展基类,而是创建相同元素的变体,这意味着需要更多自定义注册不同变体的方式,例如静态MyTableCell.registerType
一种可组合的方法,我将一个渲染器元素<my-table-renderer-text>
包装在一个通用的<my-table-cell>
中。这避免了自定义寄存器方法,但它更难编写并导致更多元素和更多样板代码,这反过来意味着性能损失。
两者的混合,用户在其中写入<my-table-cell type="text">
,并且单元格在内部使用document.createElement('my-table-rendener-'+ type)
之类的内容。这保留了选项1的更简单的语法,同时仍然避免使用自定义寄存器方法,但它与选项2具有相同的性能含义。
你能建议更好的选择吗?我错过了什么吗?
答案 0 :(得分:4)
可以做的是使用 Till_Date
2016/10
2016/10
2016/11
2016/11
2016/12
2016/8
自定义内置元素:
<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>
这样所有单元格都扩展了相同的//common cell
class DataCell extends HTMLTableCellElement {...}
//typed cell
class StringCell extends DataCell {
renderContent() { ... }
}
customElements.define( 'data-string', StringCell, { extends: 'td' } )
元素,共享一个共同的原型,但有自己的方法实现。
您可以覆盖共享方法,共享方法可以调用派生原型对象的特定方法。
请参阅此处的运行示例:
<td>
//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
}
注意:如果您不想要类型扩展,您也可以使用自定义标记。我们的想法是拥有一个共同的原型和共享它的不同自定义元素(感谢标准的原型继承)。
答案 1 :(得分:1)
注意:这个答案是从另一个人那里得到的,因为它本身相当广泛而且完全独立。
如果您使用带有(optionnal)type
属性的自主自定义元素(即自定义标记):
<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>
...你可以使用MVC模式:
通用和字符串视图的示例:
class CellView {
constructor ( view ) {
this.view = view
}
render () {
//default rendering
}
}
//String View
class CellStringView extends CellView {
render () {
console.info( 'special rendering', this.view )
this.view.innerHTML = '"' + this.view.textContent + '"'
}
}
在自定义元素定义中(可以将其视为控制器):
自定义元素 v1类:
的示例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()
}
}
以下是实时摘录:
//View (MVC View)
class CellView {
constructor(view) {
this.view = view
}
render() {}
}
//String View
class CellStringView extends CellView {
render() {
console.info('special rendering', this.view)
this.view.innerHTML = '"' + this.view.textContent + '"'
}
}
//Element (MVC controller)
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()
}
}
customElements.define('data-cell', CellElement)
data-table {
display: table ;
border-collapse: collapse ;
border: 1px solid gray ;
}
data-row {
display: table-row ;
}
data-cell {
display: table-cell ;
border: 1px solid #ccc ;
padding: 2px ;
}
<h4>Custom Table v1</h4>
<data-table>
<data-row>
<data-cell>Id</data-cell>
<data-cell>Name</data-cell>
<data-cell>Age</data-cell>
</data-row>
<data-row>
<data-cell>1</data-cell>
<data-cell type="string">An</data-cell>
<data-cell>20</data-cell>
</data-row>
<data-row>
<data-cell>2</data-cell>
<data-cell type="string">Bob</data-cell>
<data-cell>31</data-cell>
</data-row>
</data-table>