mirror of https://github.com/ElemeFE/element
Table: add header group feature. (#1312)
parent
c3aba68ecc
commit
2f3f5eabc1
|
@ -683,6 +683,115 @@ When you have huge chunks of data to put in a table, you can fix the header and
|
|||
```
|
||||
:::
|
||||
|
||||
### Grouping table head
|
||||
|
||||
When the data structure is complex, you can use group header to show the data hierarchy.
|
||||
|
||||
:::demo Only need to place el-table-column inside a el-table-column, you can achieve group header.
|
||||
```html
|
||||
<template>
|
||||
<el-table
|
||||
:data="tableData3"
|
||||
border
|
||||
style="width: 100%">
|
||||
<el-table-column
|
||||
prop="date"
|
||||
label="Date"
|
||||
width="150">
|
||||
</el-table-column>
|
||||
<el-table-column label="Delivery Info">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="Name"
|
||||
width="120">
|
||||
</el-table-column>
|
||||
<el-table-column label="Address Info">
|
||||
<el-table-column
|
||||
prop="state"
|
||||
label="State"
|
||||
width="120">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="city"
|
||||
label="City"
|
||||
width="120">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="Address"
|
||||
width="300">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="zip"
|
||||
label="Zip"
|
||||
width="120">
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData3: [{
|
||||
date: '2016-05-03',
|
||||
name: 'Tom',
|
||||
state: 'California',
|
||||
city: 'Los Angeles',
|
||||
address: 'No. 189, Grove St, Los Angeles',
|
||||
zip: 'CA 90036'
|
||||
}, {
|
||||
date: '2016-05-02',
|
||||
name: 'Tom',
|
||||
state: 'California',
|
||||
city: 'Los Angeles',
|
||||
address: 'No. 189, Grove St, Los Angeles',
|
||||
zip: 'CA 90036'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: 'Tom',
|
||||
state: 'California',
|
||||
city: 'Los Angeles',
|
||||
address: 'No. 189, Grove St, Los Angeles',
|
||||
zip: 'CA 90036'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: 'Tom',
|
||||
state: 'California',
|
||||
city: 'Los Angeles',
|
||||
address: 'No. 189, Grove St, Los Angeles',
|
||||
zip: 'CA 90036'
|
||||
}, {
|
||||
date: '2016-05-08',
|
||||
name: 'Tom',
|
||||
state: 'California',
|
||||
city: 'Los Angeles',
|
||||
address: 'No. 189, Grove St, Los Angeles',
|
||||
zip: 'CA 90036'
|
||||
}, {
|
||||
date: '2016-05-06',
|
||||
name: 'Tom',
|
||||
state: 'California',
|
||||
city: 'Los Angeles',
|
||||
address: 'No. 189, Grove St, Los Angeles',
|
||||
zip: 'CA 90036'
|
||||
}, {
|
||||
date: '2016-05-07',
|
||||
name: 'Tom',
|
||||
state: 'California',
|
||||
city: 'Los Angeles',
|
||||
address: 'No. 189, Grove St, Los Angeles',
|
||||
zip: 'CA 90036'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### Single select
|
||||
|
||||
Single row selection is supported.
|
||||
|
|
|
@ -689,6 +689,115 @@
|
|||
```
|
||||
:::
|
||||
|
||||
### 多级表头
|
||||
|
||||
数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。
|
||||
|
||||
:::demo 只需要在 el-table-column 里面嵌套 el-table-column,就可以实现多级表头。
|
||||
```html
|
||||
<template>
|
||||
<el-table
|
||||
:data="tableData3"
|
||||
border
|
||||
style="width: 100%">
|
||||
<el-table-column
|
||||
prop="date"
|
||||
label="日期"
|
||||
width="150">
|
||||
</el-table-column>
|
||||
<el-table-column label="配送信息">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="姓名"
|
||||
width="120">
|
||||
</el-table-column>
|
||||
<el-table-column label="地址">
|
||||
<el-table-column
|
||||
prop="province"
|
||||
label="省份"
|
||||
width="120">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="city"
|
||||
label="市区"
|
||||
width="120">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="address"
|
||||
label="地址"
|
||||
width="300">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="zip"
|
||||
label="邮编"
|
||||
width="120">
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tableData3: [{
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-08',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-06',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-07',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### 单选
|
||||
|
||||
选择单行数据时使用色块表示。
|
||||
|
|
|
@ -126,11 +126,13 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
render() {},
|
||||
render() {
|
||||
return (<div>{ this._t('default') }</div>);
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isChildColumn: false,
|
||||
isSubColumn: false,
|
||||
columns: []
|
||||
};
|
||||
},
|
||||
|
@ -158,13 +160,15 @@ export default {
|
|||
|
||||
created() {
|
||||
this.customRender = this.$options.render;
|
||||
this.$options.render = (h) => h('div');
|
||||
this.$options.render = (h) => {
|
||||
return (<div>{ this._t('default') }</div>);
|
||||
};
|
||||
|
||||
let columnId = this.columnId = (this.$parent.tableId || (this.$parent.columnId + '_')) + 'column_' + columnIdSeed++;
|
||||
|
||||
let parent = this.$parent;
|
||||
let owner = this.owner;
|
||||
this.isChildColumn = owner !== parent;
|
||||
this.isSubColumn = owner !== parent;
|
||||
|
||||
let type = this.type;
|
||||
|
||||
|
@ -326,12 +330,12 @@ export default {
|
|||
const parent = this.$parent;
|
||||
let columnIndex;
|
||||
|
||||
if (!this.isChildColumn) {
|
||||
if (!this.isSubColumn) {
|
||||
columnIndex = [].indexOf.call(parent.$refs.hiddenColumns.children, this.$el);
|
||||
} else {
|
||||
columnIndex = [].indexOf.call(parent.$el.children, this.$el);
|
||||
}
|
||||
|
||||
owner.store.commit('insertColumn', this.columnConfig, columnIndex);
|
||||
owner.store.commit('insertColumn', this.columnConfig, columnIndex, this.isSubColumn ? parent.columnConfig : null);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,10 +3,75 @@ import ElTag from 'element-ui/packages/tag';
|
|||
import Vue from 'vue';
|
||||
import FilterPanel from './filter-panel.vue';
|
||||
|
||||
const getAllColumns = (columns) => {
|
||||
const result = [];
|
||||
columns.forEach((column) => {
|
||||
if (column.children) {
|
||||
result.push(column);
|
||||
result.push.apply(result, getAllColumns(column.children));
|
||||
} else {
|
||||
result.push(column);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
const convertToRows = (originColumns) => {
|
||||
let maxLevel = 1;
|
||||
const traverse = (column, parent) => {
|
||||
if (parent) {
|
||||
column.level = parent.level + 1;
|
||||
if (maxLevel < column.level) {
|
||||
maxLevel = column.level;
|
||||
}
|
||||
}
|
||||
if (column.children) {
|
||||
let childrenMax = 1;
|
||||
let colSpan = 0;
|
||||
column.children.forEach((subColumn) => {
|
||||
const temp = traverse(subColumn, column);
|
||||
if (temp > childrenMax) {
|
||||
childrenMax = temp;
|
||||
}
|
||||
colSpan += subColumn.colSpan;
|
||||
});
|
||||
column.colSpan = colSpan;
|
||||
} else {
|
||||
column.colSpan = 1;
|
||||
}
|
||||
};
|
||||
|
||||
originColumns.forEach((column) => {
|
||||
column.level = 1;
|
||||
traverse(column);
|
||||
});
|
||||
|
||||
const rows = [];
|
||||
for (let i = 0; i < maxLevel; i++) {
|
||||
rows.push([]);
|
||||
}
|
||||
|
||||
const allColumns = getAllColumns(originColumns);
|
||||
|
||||
allColumns.forEach((column) => {
|
||||
if (!column.children) {
|
||||
column.rowSpan = maxLevel - column.level + 1;
|
||||
} else {
|
||||
column.rowSpan = 1;
|
||||
}
|
||||
rows[column.level - 1].push(column);
|
||||
});
|
||||
|
||||
return rows;
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'el-table-header',
|
||||
|
||||
render(h) {
|
||||
const originColumns = this.store.states.originColumns;
|
||||
const columnRows = convertToRows(originColumns, this.columns);
|
||||
|
||||
return (
|
||||
<table
|
||||
class="el-table__header"
|
||||
|
@ -26,44 +91,50 @@ export default {
|
|||
: ''
|
||||
}
|
||||
<thead>
|
||||
<tr>
|
||||
{
|
||||
this._l(this.columns, (column, cellIndex) =>
|
||||
<th
|
||||
on-mousemove={ ($event) => this.handleMouseMove($event, column) }
|
||||
on-mouseout={ this.handleMouseOut }
|
||||
on-mousedown={ ($event) => this.handleMouseDown($event, column) }
|
||||
on-click={ ($event) => this.handleClick($event, column) }
|
||||
class={ [column.id, column.order, column.align, column.className || '', this.isCellHidden(cellIndex) ? 'is-hidden' : ''] }>
|
||||
<div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : ''] }>
|
||||
{
|
||||
column.renderHeader
|
||||
? column.renderHeader.call(this._renderProxy, h, { column, $index: cellIndex, store: this.store, _self: this.$parent.$vnode.context })
|
||||
: column.label
|
||||
{
|
||||
this._l(columnRows, (columns) =>
|
||||
<tr>
|
||||
{
|
||||
this._l(columns, (column, cellIndex) =>
|
||||
<th
|
||||
colspan={ column.colSpan }
|
||||
rowspan={ column.rowSpan }
|
||||
on-mousemove={ ($event) => this.handleMouseMove($event, column) }
|
||||
on-mouseout={ this.handleMouseOut }
|
||||
on-mousedown={ ($event) => this.handleMouseDown($event, column) }
|
||||
on-click={ ($event) => this.handleClick($event, column) }
|
||||
class={ [column.id, column.order, column.align, column.className || '', this.isCellHidden(cellIndex) ? 'is-hidden' : '', !column.children ? 'is-leaf' : ''] }>
|
||||
<div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : ''] }>
|
||||
{
|
||||
column.renderHeader
|
||||
? column.renderHeader.call(this._renderProxy, h, { column, $index: cellIndex, store: this.store, _self: this.$parent.$vnode.context })
|
||||
: column.label
|
||||
}
|
||||
{
|
||||
column.sortable
|
||||
? <span class="caret-wrapper" on-click={ ($event) => this.handleHeaderClick($event, column) }>
|
||||
<i class="sort-caret ascending"></i>
|
||||
<i class="sort-caret descending"></i>
|
||||
</span>
|
||||
: ''
|
||||
}
|
||||
{
|
||||
column.filterable
|
||||
? <span class="el-table__column-filter-trigger" on-click={ ($event) => this.handleFilterClick($event, column) }><i class={ ['el-icon-arrow-down', column.filterOpened ? 'el-icon-arrow-up' : ''] }></i></span>
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
</th>
|
||||
)
|
||||
}
|
||||
{
|
||||
column.sortable
|
||||
? <span class="caret-wrapper" on-click={ ($event) => this.handleHeaderClick($event, column) }>
|
||||
<i class="sort-caret ascending"></i>
|
||||
<i class="sort-caret descending"></i>
|
||||
</span>
|
||||
!this.fixed && this.layout.gutterWidth
|
||||
? <th class="gutter" style={{ width: this.layout.scrollY ? this.layout.gutterWidth + 'px' : '0' }}></th>
|
||||
: ''
|
||||
}
|
||||
{
|
||||
column.filterable
|
||||
? <span class="el-table__column-filter-trigger" on-click={ ($event) => this.handleFilterClick($event, column) }><i class={ ['el-icon-arrow-down', column.filterOpened ? 'el-icon-arrow-up' : ''] }></i></span>
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
</th>
|
||||
)
|
||||
}
|
||||
{
|
||||
!this.fixed && this.layout.gutterWidth
|
||||
? <th class="gutter" style={{ width: this.layout.scrollY ? this.layout.gutterWidth + 'px' : '0' }}></th>
|
||||
: ''
|
||||
}
|
||||
</tr>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
</thead>
|
||||
</table>
|
||||
);
|
||||
|
@ -168,6 +239,7 @@ export default {
|
|||
},
|
||||
|
||||
handleMouseDown(event, column) {
|
||||
if (column.children && column.children.length > 0) return;
|
||||
/* istanbul ignore if */
|
||||
if (this.draggingColumn && this.border) {
|
||||
this.dragging = true;
|
||||
|
@ -234,6 +306,7 @@ export default {
|
|||
},
|
||||
|
||||
handleMouseMove(event, column) {
|
||||
if (column.children && column.children.length > 0) return;
|
||||
let target = event.target;
|
||||
while (target && target.tagName !== 'TH') {
|
||||
target = target.parentNode;
|
||||
|
|
|
@ -52,6 +52,7 @@ const TableStore = function(table, initialState = {}) {
|
|||
this.states = {
|
||||
rowKey: null,
|
||||
_columns: [],
|
||||
originColumns: [],
|
||||
columns: [],
|
||||
fixedColumns: [],
|
||||
rightFixedColumns: [],
|
||||
|
@ -159,13 +160,19 @@ TableStore.prototype.mutations = {
|
|||
Vue.nextTick(() => this.table.updateScrollY());
|
||||
},
|
||||
|
||||
insertColumn(states, column, index) {
|
||||
let _columns = states._columns;
|
||||
if (typeof index !== 'undefined') {
|
||||
_columns.splice(index, 0, column);
|
||||
} else {
|
||||
_columns.push(column);
|
||||
insertColumn(states, column, index, parent) {
|
||||
let array = states._columns;
|
||||
if (parent) {
|
||||
array = parent.children;
|
||||
if (!array) array = parent.children = [];
|
||||
}
|
||||
|
||||
if (typeof index !== 'undefined') {
|
||||
array.splice(index, 0, column);
|
||||
} else {
|
||||
array.push(column);
|
||||
}
|
||||
|
||||
if (column.type === 'selection') {
|
||||
states.selectable = column.selectable;
|
||||
states.reserveSelection = column.reserveSelection;
|
||||
|
@ -236,6 +243,18 @@ TableStore.prototype.mutations = {
|
|||
})
|
||||
};
|
||||
|
||||
const doFlattenColumns = (columns) => {
|
||||
const result = [];
|
||||
columns.forEach((column) => {
|
||||
if (column.children) {
|
||||
result.push.apply(result, doFlattenColumns(column.children));
|
||||
} else {
|
||||
result.push(column);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
TableStore.prototype.updateColumns = function() {
|
||||
const states = this.states;
|
||||
const _columns = states._columns || [];
|
||||
|
@ -246,7 +265,8 @@ TableStore.prototype.updateColumns = function() {
|
|||
_columns[0].fixed = true;
|
||||
states.fixedColumns.unshift(_columns[0]);
|
||||
}
|
||||
states.columns = [].concat(states.fixedColumns).concat(_columns.filter((column) => !column.fixed)).concat(states.rightFixedColumns);
|
||||
states.originColumns = [].concat(states.fixedColumns).concat(_columns.filter((column) => !column.fixed)).concat(states.rightFixedColumns);
|
||||
states.columns = doFlattenColumns(states.originColumns);
|
||||
states.isComplex = states.fixedColumns.length > 0 || states.rightFixedColumns.length > 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@
|
|||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
|
||||
@when center {
|
||||
text-align: center;
|
||||
|
@ -101,10 +100,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
& th.is-leaf, td {
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
}
|
||||
|
||||
@modifier border {
|
||||
& th, td {
|
||||
border-right: 1px solid var(--table-border-color);
|
||||
}
|
||||
|
||||
& th {
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
& th {
|
||||
|
|
|
@ -985,6 +985,112 @@ describe('Table', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('multi level column', () => {
|
||||
it('should works', done => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<el-table :data="testData">
|
||||
<el-table-column prop="name" />
|
||||
<el-table-column label="group">
|
||||
<el-table-column prop="release"/>
|
||||
<el-table-column prop="director"/>
|
||||
</el-table-column>
|
||||
<el-table-column prop="runtime"/>
|
||||
</el-table>
|
||||
`,
|
||||
|
||||
created() {
|
||||
this.testData = null;
|
||||
}
|
||||
}, true);
|
||||
|
||||
setTimeout(_ => {
|
||||
const trs = vm.$el.querySelectorAll('.el-table__header tr');
|
||||
expect(trs.length).equal(2);
|
||||
const firstRowHeader = trs[0].querySelectorAll('th .cell').length;
|
||||
const secondRowHeader = trs[1].querySelectorAll('th .cell').length;
|
||||
expect(firstRowHeader).to.equal(3);
|
||||
expect(secondRowHeader).to.equal(2);
|
||||
|
||||
expect(trs[0].querySelector('th:first-child').getAttribute('rowspan')).to.equal('2');
|
||||
expect(trs[0].querySelector('th:nth-child(2)').getAttribute('colspan')).to.equal('2');
|
||||
destroyVM(vm);
|
||||
done();
|
||||
}, DELAY);
|
||||
});
|
||||
|
||||
it('should works', done => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<el-table :data="testData">
|
||||
<el-table-column prop="name" />
|
||||
<el-table-column label="group">
|
||||
<el-table-column label="group's group">
|
||||
<el-table-column prop="release" />
|
||||
<el-table-column prop="runtime"/>
|
||||
</el-table-column>
|
||||
<el-table-column prop="director" />
|
||||
</el-table-column>
|
||||
<el-table-column prop="runtime"/>
|
||||
</el-table>
|
||||
`,
|
||||
|
||||
created() {
|
||||
this.testData = null;
|
||||
}
|
||||
}, true);
|
||||
|
||||
setTimeout(_ => {
|
||||
const trs = vm.$el.querySelectorAll('.el-table__header tr');
|
||||
expect(trs.length).equal(3);
|
||||
const firstRowHeader = trs[0].querySelectorAll('th .cell').length;
|
||||
const secondRowHeader = trs[1].querySelectorAll('th .cell').length;
|
||||
const thirdRowHeader = trs[2].querySelectorAll('th .cell').length;
|
||||
expect(firstRowHeader).to.equal(3);
|
||||
expect(secondRowHeader).to.equal(2);
|
||||
expect(thirdRowHeader).to.equal(2);
|
||||
|
||||
expect(trs[0].querySelector('th:first-child').getAttribute('rowspan')).to.equal('3');
|
||||
expect(trs[0].querySelector('th:nth-child(2)').getAttribute('colspan')).to.equal('3');
|
||||
expect(trs[1].querySelector('th:first-child').getAttribute('colspan')).to.equal('2');
|
||||
expect(trs[1].querySelector('th:nth-child(2)').getAttribute('rowspan')).to.equal('2');
|
||||
|
||||
destroyVM(vm);
|
||||
done();
|
||||
}, DELAY);
|
||||
});
|
||||
|
||||
it('should work in one column', done => {
|
||||
const vm = createVue({
|
||||
template: `
|
||||
<el-table :data="testData">
|
||||
<el-table-column label="group">
|
||||
<el-table-column prop="release"/>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
`,
|
||||
|
||||
created() {
|
||||
this.testData = null;
|
||||
}
|
||||
}, true);
|
||||
|
||||
setTimeout(_ => {
|
||||
const trs = vm.$el.querySelectorAll('.el-table__header tr');
|
||||
expect(trs.length).equal(2);
|
||||
const firstRowLength = trs[0].querySelectorAll('th .cell').length;
|
||||
const secondRowLength = trs[1].querySelectorAll('th .cell').length;
|
||||
expect(firstRowLength).to.equal(1);
|
||||
expect(secondRowLength).to.equal(1);
|
||||
|
||||
expect(trs[0].querySelector('th:first-child').getAttribute('rowspan')).to.equal('1');
|
||||
expect(trs[0].querySelector('th:first-child').getAttribute('colspan')).to.equal('1');
|
||||
destroyVM(vm);
|
||||
done();
|
||||
}, DELAY);
|
||||
});
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
const createTable = function(prop = '', opts) {
|
||||
return createVue({
|
||||
|
|
Loading…
Reference in New Issue