mirror of https://github.com/ElemeFE/element
Improve Table:
1. Add TableStore & TableLayout. 2. Remove customCriteria & customBackgroundColors. 3. Remove fixedColumnCount. 4. Add fixed prop for TableColumn. 5. Add selectable prop for TableColumn[type="selection"].pull/488/merge
parent
815bdd47d0
commit
b36da2f982
|
@ -15,10 +15,15 @@
|
||||||
- 修复 Loading 关闭后有几率滚动失效的问题
|
- 修复 Loading 关闭后有几率滚动失效的问题
|
||||||
- 修复 远程搜索的 Select 不能正确渲染默认初始值的问题
|
- 修复 远程搜索的 Select 不能正确渲染默认初始值的问题
|
||||||
- 修复 Switch 的 width 属性无效的问题
|
- 修复 Switch 的 width 属性无效的问题
|
||||||
|
- 优化 Table 性能,优化 Table 代码结构
|
||||||
|
- Table 增加属性 rowClassName
|
||||||
|
- TableColumn 增加 fixed 属性,可选值:true, false, left, right
|
||||||
|
- TableColumn[type="selection"] 增加 selectable 属性
|
||||||
|
|
||||||
#### 非兼容性更新
|
#### 非兼容性更新
|
||||||
|
|
||||||
- 全屏 Loading 现在默认不再锁定屏幕滚动。如果需要的话,可添加 `lock` 修饰符
|
- 全屏 Loading 现在默认不再锁定屏幕滚动。如果需要的话,可添加 `lock` 修饰符
|
||||||
|
- Table 删除属性 fixedColumnCount, customCriteria, customBackgroundColors
|
||||||
|
|
||||||
### 1.0.0-rc.7
|
### 1.0.0-rc.7
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,15 @@
|
||||||
|
|
||||||
formatter(row, column) {
|
formatter(row, column) {
|
||||||
return row.address;
|
return row.address;
|
||||||
|
},
|
||||||
|
|
||||||
|
tableRowClassName(row, index) {
|
||||||
|
if (index === 1) {
|
||||||
|
return 'info-row';
|
||||||
|
} else if (index === 3) {
|
||||||
|
return 'positive-row';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -132,6 +141,16 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.el-table .info-row {
|
||||||
|
background: #c9e5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table .positive-row {
|
||||||
|
background: #e2f0e4;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
## Table 表格
|
## Table 表格
|
||||||
|
|
||||||
用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。
|
用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。
|
||||||
|
@ -140,24 +159,24 @@
|
||||||
|
|
||||||
基础的表格展示用法。
|
基础的表格展示用法。
|
||||||
|
|
||||||
:::demo 当`el-table`元素中注入`data`对象数组后,在`el-table-column`中用`property`属性来对应对象中的键名即可填入数据,用`label`属性来定义表格的列名。可以使用`width`属性来定义列宽。
|
:::demo 当`el-table`元素中注入`data`对象数组后,在`el-table-column`中用`prop`属性来对应对象中的键名即可填入数据,用`label`属性来定义表格的列名。可以使用`width`属性来定义列宽。
|
||||||
```html
|
```html
|
||||||
<template>
|
<template>
|
||||||
<el-table
|
<el-table
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
style="width: 100%">
|
style="width: 100%">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址">
|
label="地址">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
@ -203,17 +222,17 @@
|
||||||
stripe
|
stripe
|
||||||
style="width: 100%">
|
style="width: 100%">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址">
|
label="地址">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
@ -257,17 +276,17 @@
|
||||||
border
|
border
|
||||||
style="width: 100%">
|
style="width: 100%">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址">
|
label="地址">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
@ -305,33 +324,52 @@
|
||||||
|
|
||||||
可将表格内容 highlight 显示,方便区分「成功、信息、警告、危险」等内容。
|
可将表格内容 highlight 显示,方便区分「成功、信息、警告、危险」等内容。
|
||||||
|
|
||||||
:::demo 为行添加自定义背景色,表明该行处于某种状态。若某一行拥有`custom-criteria`数组中的某个字段且值为`true`,则为该行添加`custom-background-colors`数组中对应的背景色。
|
:::demo 可以通过指定 Table 组件的 rowClassName 属性来为 Table 中的某一行添加 class,表明该行处于某种状态。
|
||||||
```html
|
```html
|
||||||
<template>
|
<template>
|
||||||
<el-table
|
<el-table
|
||||||
:data="tableData2"
|
:data="tableData2"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
:custom-criteria="['$info', '$positive']"
|
:row-class-name="tableRowClassName">
|
||||||
:custom-background-colors="['#C9E5F5', '#E2F0E4']">
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址">
|
label="地址">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.el-table .info-row {
|
||||||
|
background: #c9e5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table .positive-row {
|
||||||
|
background: #e2f0e4;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
|
methods: {
|
||||||
|
tableRowClassName(row, index) {
|
||||||
|
if (index === 1) {
|
||||||
|
return 'info-row';
|
||||||
|
} else if (index === 3) {
|
||||||
|
return 'positive-row';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tableData2: [{
|
tableData2: [{
|
||||||
|
@ -373,17 +411,17 @@
|
||||||
border
|
border
|
||||||
style="width: 100%">
|
style="width: 100%">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址">
|
label="地址">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
@ -433,41 +471,41 @@
|
||||||
|
|
||||||
横向内容过多时,可选择固定首列。
|
横向内容过多时,可选择固定首列。
|
||||||
|
|
||||||
:::demo 固定列需要使用`fixed-column-count`属性,它接受一个`Number`,表示左起要固定的列数。
|
:::demo 固定列需要使用`fixed`属性,它接受 Boolean 值或者`left` `right`,表示左边固定还是右边固定。
|
||||||
```html
|
```html
|
||||||
<template>
|
<template>
|
||||||
<el-table
|
<el-table
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:fixed-column-count="1"
|
|
||||||
border
|
border
|
||||||
style="width: 100%">
|
style="width: 100%">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
fixed
|
||||||
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
width="150">
|
width="150">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="province"
|
prop="province"
|
||||||
label="省份"
|
label="省份"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="city"
|
prop="city"
|
||||||
label="市区"
|
label="市区"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址"
|
label="地址"
|
||||||
width="300">
|
width="300">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="zip"
|
prop="zip"
|
||||||
label="邮编"
|
label="邮编"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -523,37 +561,37 @@
|
||||||
<template>
|
<template>
|
||||||
<el-table
|
<el-table
|
||||||
:data="tableData3"
|
:data="tableData3"
|
||||||
:fixed-column-count="1"
|
|
||||||
border
|
border
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
height="250">
|
height="250">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
fixed
|
||||||
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
width="150">
|
width="150">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="province"
|
prop="province"
|
||||||
label="省份"
|
label="省份"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="city"
|
prop="city"
|
||||||
label="市区"
|
label="市区"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址"
|
label="地址"
|
||||||
width="300">
|
width="300">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="zip"
|
prop="zip"
|
||||||
label="邮编"
|
label="邮编"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -639,17 +677,17 @@
|
||||||
width="50">
|
width="50">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址">
|
label="地址">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
@ -694,7 +732,7 @@
|
||||||
|
|
||||||
选择多行数据时使用 Checkbox。
|
选择多行数据时使用 Checkbox。
|
||||||
|
|
||||||
:::demo 除了`selection-mode`的设置外,多选与单选并没有太大差别,只是传入`selectionchange`事件中的参数从对象变成了对象数组。此外,需要提供一个列来显示多选框: 手动添加一个`el-table-column`,设`type`属性为`selection`即可。在本例中,为了方便说明其他属性,我们还使用了`inline-template`和`show-tooltip-when-overflow`:设置了`inline-template`属性后,可以通过调用`row`对象中的值取代`property`属性的设置;默认情况下若内容过多会折行显示,若需要单行显示可以使用`show-tooltip-when-overflow`属性,它接受一个`Boolean`,为`true`时多余的内容会在 hover 时以 tooltip 的形式显示出来。
|
:::demo 除了`selection-mode`的设置外,多选与单选并没有太大差别,只是传入`selectionchange`事件中的参数从对象变成了对象数组。此外,需要提供一个列来显示多选框: 手动添加一个`el-table-column`,设`type`属性为`selection`即可。在本例中,为了方便说明其他属性,我们还使用了`inline-template`和`show-tooltip-when-overflow`:设置了`inline-template`属性后,可以通过调用`row`对象中的值取代`prop`属性的设置;默认情况下若内容过多会折行显示,若需要单行显示可以使用`show-tooltip-when-overflow`属性,它接受一个`Boolean`,为`true`时多余的内容会在 hover 时以 tooltip 的形式显示出来。
|
||||||
```html
|
```html
|
||||||
<template>
|
<template>
|
||||||
<el-table
|
<el-table
|
||||||
|
@ -713,12 +751,12 @@
|
||||||
<div>{{ row.date }}</div>
|
<div>{{ row.date }}</div>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="120">
|
width="120">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址"
|
label="地址"
|
||||||
show-tooltip-when-overflow>
|
show-tooltip-when-overflow>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -784,18 +822,18 @@
|
||||||
border
|
border
|
||||||
style="width: 100%">
|
style="width: 100%">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="date"
|
prop="date"
|
||||||
label="日期"
|
label="日期"
|
||||||
sortable
|
sortable
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="name"
|
prop="name"
|
||||||
label="姓名"
|
label="姓名"
|
||||||
width="180">
|
width="180">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
property="address"
|
prop="address"
|
||||||
label="地址"
|
label="地址"
|
||||||
:formatter="formatter">
|
:formatter="formatter">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -843,9 +881,9 @@
|
||||||
| stripe | 是否为斑马纹 table | boolean | — | false |
|
| stripe | 是否为斑马纹 table | boolean | — | false |
|
||||||
| border | 是否带有纵向边框 | boolean | — | false |
|
| border | 是否带有纵向边框 | boolean | — | false |
|
||||||
| fit | 列的宽度是否自撑开 | boolean | — | true |
|
| fit | 列的宽度是否自撑开 | boolean | — | true |
|
||||||
|
| rowClassName | 行的 className 的回调,会传入 row, index。 | Function | - | - |
|
||||||
| selection-mode | 列表项选择模式 | string | single/multiple/none | none |
|
| selection-mode | 列表项选择模式 | string | single/multiple/none | none |
|
||||||
| allow-no-selection | 单选模式是否允许选项为空 | boolean | — | false |
|
| allow-no-selection | 单选模式是否允许选项为空 | boolean | — | false |
|
||||||
| fixed-column-count | 固定列的个数 | number | — | 0 |
|
|
||||||
|
|
||||||
### Table Events
|
### Table Events
|
||||||
| 事件名 | 说明 | 参数 |
|
| 事件名 | 说明 | 参数 |
|
||||||
|
@ -859,12 +897,14 @@
|
||||||
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|
||||||
|---------- |-------------- |---------- |-------------------------------- |-------- |
|
|---------- |-------------- |---------- |-------------------------------- |-------- |
|
||||||
| label | 显示的标题 | string | — | — |
|
| label | 显示的标题 | string | — | — |
|
||||||
| property | 对应列内容的字段名 | string | — | — |
|
| prop | 对应列内容的字段名,也可以使用 property 属性 | string | — | — |
|
||||||
| width | 对应列的宽度 | string | — | — |
|
| width | 对应列的宽度 | string | — | — |
|
||||||
|
| fixed | 列是否固定在左侧或者右侧 | string, boolean | true, left, right | - |
|
||||||
| sortable | 对应列是否可以排序 | boolean | — | false |
|
| sortable | 对应列是否可以排序 | boolean | — | false |
|
||||||
| resizable | 对应列是否可以通过拖动改变宽度(如果需要,需在 el-table 上设置 border 属性为真) | boolean | — | false |
|
| resizable | 对应列是否可以通过拖动改变宽度(如果需要,需在 el-table 上设置 border 属性为真) | boolean | — | false |
|
||||||
| type | 对应列的类型。如果设置了 `selection` 则显示多选框,如果设置了 `index` 则显示该行的索引(从 1 开始计算) | string | selection/index | — |
|
| type | 对应列的类型。如果设置了 `selection` 则显示多选框,如果设置了 `index` 则显示该行的索引(从 1 开始计算) | string | selection/index | — |
|
||||||
| formatter | 用来格式化内容,在 formatter 执行的时候,会传入 row 和 column | function | — | — |
|
| formatter | 用来格式化内容,在 formatter 执行的时候,会传入 row 和 column | function | — | — |
|
||||||
| show-tooltip-when-overflow | 当过长被隐藏时显示 tooltip | Boolean | — | false |
|
| show-tooltip-when-overflow | 当过长被隐藏时显示 tooltip | Boolean | — | false |
|
||||||
| inline-template | 指定该属性后可以自定义 column 模板,参考多选的时间列,通过 row 获取行信息,JSX 里通过 _self 获取当前上下文。此时不需要配置 property 属性 | — | — |
|
| inline-template | 指定该属性后可以自定义 column 模板,参考多选的时间列,通过 row 获取行信息,JSX 里通过 _self 获取当前上下文。此时不需要配置 prop 属性 | — | — |
|
||||||
| align | 对齐方式 | String | left, center, right | left |
|
| align | 对齐方式 | String | left, center, right | left |
|
||||||
|
| selectable | 仅对 type=selection 的列有效,类型为 Function,Function 的返回值用来决定这一行的 CheckBox 是否可以勾选 | Function | - |
|
|
@ -11,7 +11,7 @@
|
||||||
"repository": "https://github.com/element-component/element/tree/master/packages/dialog",
|
"repository": "https://github.com/element-component/element/tree/master/packages/dialog",
|
||||||
"author": "elemefe",
|
"author": "elemefe",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"dependencies": {
|
||||||
"throttle-debounce": "^1.0.1"
|
"throttle-debounce": "^1.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
const getColumnById = function(grid, columnId) {
|
import { getValueByPath, getCell } from './util';
|
||||||
|
|
||||||
|
const getColumnById = function(table, columnId) {
|
||||||
let column = null;
|
let column = null;
|
||||||
grid.columns.forEach(function(item) {
|
table.columns.forEach(function(item) {
|
||||||
if (item.id === columnId) {
|
if (item.id === columnId) {
|
||||||
column = item;
|
column = item;
|
||||||
}
|
}
|
||||||
|
@ -8,26 +10,24 @@ const getColumnById = function(grid, columnId) {
|
||||||
return column;
|
return column;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getColumnByCell = function(grid, cell) {
|
const getColumnByCell = function(table, cell) {
|
||||||
const matches = (cell.className || '').match(/grid_[^\s]+/gm);
|
const matches = (cell.className || '').match(/table_[^\s]+/gm);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
return getColumnById(grid, matches[0]);
|
return getColumnById(table, matches[0]);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
import { getValueByPath, getCell, orderBy, getChild } from './util';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
columns: {},
|
store: {
|
||||||
data: {},
|
required: true
|
||||||
fixed: {},
|
},
|
||||||
selection: {
|
layout: {
|
||||||
default() {
|
required: true
|
||||||
return [];
|
},
|
||||||
}
|
rowClassName: [String, Function],
|
||||||
}
|
fixed: String
|
||||||
},
|
},
|
||||||
|
|
||||||
render(h) {
|
render(h) {
|
||||||
|
@ -37,17 +37,20 @@ export default {
|
||||||
cellspacing="0"
|
cellspacing="0"
|
||||||
cellpadding="0"
|
cellpadding="0"
|
||||||
border="0">
|
border="0">
|
||||||
|
{
|
||||||
|
this._l(this.columns, column =>
|
||||||
|
<colgroup
|
||||||
|
name={ column.id }
|
||||||
|
width={ column.realWidth || column.width }
|
||||||
|
/>)
|
||||||
|
}
|
||||||
<tbody>
|
<tbody>
|
||||||
{
|
{
|
||||||
this._l(this.data, (row, $index) =>
|
this._l(this.data, (row, $index) =>
|
||||||
<tr
|
<tr
|
||||||
on-click={ ($event) => this.handleClick($event, row) }
|
on-click={ ($event) => this.handleClick($event, row) }
|
||||||
on-mouseenter={ _ => this.handleMouseEnter($index) }
|
on-mouseenter={ _ => this.handleMouseEnter($index) }
|
||||||
style={ this.getCustomStyle(row) }
|
class={ this.getRowClass(row, $index) }>
|
||||||
class={{
|
|
||||||
'current-row': row === this.$parent.selected,
|
|
||||||
'hover': this.$parent.$parent.hoverRowIndex === $index
|
|
||||||
}}>
|
|
||||||
{
|
{
|
||||||
this._l(this.columns, (column) =>
|
this._l(this.columns, (column) =>
|
||||||
<td
|
<td
|
||||||
|
@ -57,11 +60,14 @@ export default {
|
||||||
on-mouseleave={ this.handleCellMouseLeave }>
|
on-mouseleave={ this.handleCellMouseLeave }>
|
||||||
{
|
{
|
||||||
column.template
|
column.template
|
||||||
? column.template.call(this._renderProxy, h, { row, column, $index, _self: this.$parent.$vnode.context })
|
? column.template.call(this._renderProxy, h, { row, column, $index, store: this.store, _self: this.$parent.$vnode.context })
|
||||||
: <div class="cell">{ this.$getPropertyText(row, column.property, column.id) }</div>
|
: <div class="cell">{ this.getCellContent(row, column.property, column.id) }</div>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
).concat(this.fixed ? <td class="gutter" /> : '')
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
!this.fixed && this.layout.scrollY && this.layout.gutterWidth ? <td class="gutter" /> : ''
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
|
@ -71,93 +77,104 @@ export default {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
data() {
|
||||||
|
return this.store.states.data;
|
||||||
|
},
|
||||||
|
hoverRowIndex() {
|
||||||
|
return this.store.states.hoverRow;
|
||||||
|
},
|
||||||
|
currentRow() {
|
||||||
|
return this.store.states.currentRow;
|
||||||
|
},
|
||||||
|
columns() {
|
||||||
|
if (this.fixed === true || this.fixed === 'left') {
|
||||||
|
return this.store.states.fixedColumns;
|
||||||
|
} else if (this.fixed === 'right') {
|
||||||
|
return this.store.states.rightFixedColumns;
|
||||||
|
}
|
||||||
|
return this.store.states.columns;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
criteria: this.$parent.customCriteria,
|
|
||||||
colors: this.$parent.customBackgroundColors,
|
|
||||||
tooltipDisabled: true
|
tooltipDisabled: true
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
filters: {
|
|
||||||
orderBy
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
getRowClass(row, index) {
|
||||||
|
const classes = [];
|
||||||
|
if (row === this.currentRow) {
|
||||||
|
classes.push('current-row');
|
||||||
|
}
|
||||||
|
if (this.hoverRowIndex === index) {
|
||||||
|
classes.push('hover-row');
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowClassName = this.rowClassName;
|
||||||
|
if (typeof rowClassName === 'string') {
|
||||||
|
classes.push(rowClassName);
|
||||||
|
} else if (typeof rowClassName === 'function') {
|
||||||
|
classes.push(rowClassName.apply(null, [row, index]) || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return classes.join(' ');
|
||||||
|
},
|
||||||
|
|
||||||
getColumnWhiteSpaceStyle(column) {
|
getColumnWhiteSpaceStyle(column) {
|
||||||
return column.showTooltipWhenOverflow ? { 'white-space': 'nowrap' } : {};
|
return column.showTooltipWhenOverflow ? { 'white-space': 'nowrap' } : {};
|
||||||
},
|
},
|
||||||
|
|
||||||
checkProperty(row) {
|
|
||||||
if (this.criteria && this.criteria.length > 0) {
|
|
||||||
for (let i = 0, len = this.criteria.length; i < len; i++) {
|
|
||||||
if (row[this.criteria[i]] === true) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
getCustomStyle(row) {
|
|
||||||
if (!this.criteria || !this.colors || this.criteria.length !== this.colors.length) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
let criterionIndex = this.checkProperty(row);
|
|
||||||
return criterionIndex > -1 ? { 'background-color': this.colors[criterionIndex] } : {};
|
|
||||||
},
|
|
||||||
|
|
||||||
handleCellMouseEnter(event, row) {
|
handleCellMouseEnter(event, row) {
|
||||||
let grid = this.$parent;
|
const table = this.$parent;
|
||||||
const cell = getCell(event);
|
const cell = getCell(event);
|
||||||
|
|
||||||
if (cell) {
|
if (cell) {
|
||||||
const column = getColumnByCell(grid, cell);
|
const column = getColumnByCell(table, cell);
|
||||||
const hoverState = grid.hoverState = { cell: cell, column: column, row: row };
|
const hoverState = table.hoverState = { cell, column, row };
|
||||||
grid.$emit('cellmouseenter', hoverState.row, hoverState.column, hoverState.cell, event);
|
table.$emit('cellmouseenter', hoverState.row, hoverState.column, hoverState.cell, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否text-overflow, 如果是就显示tooltip
|
// 判断是否text-overflow, 如果是就显示tooltip
|
||||||
const cellChild = getChild(event);
|
const cellChild = event.target.querySelector('.cell');
|
||||||
|
|
||||||
this.tooltipDisabled = cellChild.scrollWidth <= cellChild.offsetWidth;
|
this.tooltipDisabled = cellChild.scrollWidth <= cellChild.offsetWidth;
|
||||||
},
|
},
|
||||||
|
|
||||||
handleCellMouseLeave(event) {
|
handleCellMouseLeave(event) {
|
||||||
let grid = this.$parent;
|
|
||||||
const cell = getCell(event);
|
const cell = getCell(event);
|
||||||
|
|
||||||
if (cell) {
|
if (cell) {
|
||||||
const oldHoverState = grid.hoverState;
|
const table = this.$parent;
|
||||||
grid.$emit('cellmouseleave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
|
const oldHoverState = table.hoverState;
|
||||||
|
table.$emit('cellmouseleave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleMouseEnter(index) {
|
handleMouseEnter(index) {
|
||||||
this.$parent.hoverRowIndex = index;
|
this.store.commit('setHoverRow', index);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleClick(event, row) {
|
handleClick(event, row) {
|
||||||
let grid = this.$parent;
|
const table = this.$parent;
|
||||||
const cell = getCell(event);
|
const cell = getCell(event);
|
||||||
|
|
||||||
if (cell) {
|
if (cell) {
|
||||||
const column = getColumnByCell(grid, cell);
|
const column = getColumnByCell(table, cell);
|
||||||
if (column) {
|
if (column) {
|
||||||
grid.$emit('cellclick', row, column, cell, event);
|
table.$emit('cellclick', row, column, cell, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grid.selectionMode === 'single') {
|
this.store.commit('setSelectedRow', row);
|
||||||
grid.selected = row;
|
|
||||||
}
|
|
||||||
|
|
||||||
grid.$emit('rowclick', row, event);
|
table.$emit('rowclick', row, event);
|
||||||
},
|
},
|
||||||
|
|
||||||
$getPropertyText(row, property, columnId) {
|
getCellContent(row, property, columnId) {
|
||||||
let grid = this.$parent;
|
const column = getColumnById(this.$parent, columnId);
|
||||||
const column = getColumnById(grid, columnId);
|
|
||||||
if (column && column.formatter) {
|
if (column && column.formatter) {
|
||||||
return column.formatter(row, column);
|
return column.formatter(row, column);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,20 +28,39 @@ const defaults = {
|
||||||
|
|
||||||
const forced = {
|
const forced = {
|
||||||
selection: {
|
selection: {
|
||||||
headerTemplate: function(h) { return <div><el-checkbox nativeOn-click={ this.toggleAllSelection } domProps-value={ this.allSelected } on-input={ ($event) => this.$emit('allselectedchange', $event) } /></div>; },
|
headerTemplate: function(h) {
|
||||||
template: function(h, { row }) { return <el-checkbox domProps-value={ row.$selected } on-input={ ($event) => {row.$selected = $event;} } />; },
|
return <div><el-checkbox
|
||||||
|
nativeOn-click={ this.toggleAllSelection }
|
||||||
|
domProps-value={ this.isAllSelected }
|
||||||
|
on-input={ (value) => { this.$emit('allselectedchange', value); } } />
|
||||||
|
</div>;
|
||||||
|
},
|
||||||
|
template: function(h, { row, column, store, $index }) {
|
||||||
|
return <el-checkbox
|
||||||
|
domProps-value={ row.$selected }
|
||||||
|
disabled={ column.selectable ? !column.selectable.call(null, row, $index) : false }
|
||||||
|
on-input={ (value) => { row.$selected = value; store.commit('rowSelectedChanged', row); } } />;
|
||||||
|
},
|
||||||
sortable: false,
|
sortable: false,
|
||||||
resizable: false
|
resizable: false
|
||||||
},
|
},
|
||||||
index: {
|
index: {
|
||||||
// headerTemplate: function(h) { return <div>#</div>; },
|
// headerTemplate: function(h) { return <div>#</div>; },
|
||||||
headerTemplate: function(h, label) { return <div>{ label || '#' }</div>; },
|
headerTemplate: function(h, label) {
|
||||||
template: function(h, { row, $index }) { return <div>{ $index + 1 }</div>; },
|
return <div>{ label || '#' }</div>;
|
||||||
|
},
|
||||||
|
template: function(h, { row, $index }) {
|
||||||
|
return <div>{ $index + 1 }</div>;
|
||||||
|
},
|
||||||
sortable: false
|
sortable: false
|
||||||
},
|
},
|
||||||
filter: {
|
filter: {
|
||||||
headerTemplate: function(h) { return <div>#</div>; },
|
headerTemplate: function(h) {
|
||||||
template: function(h, { row, column }) { return <el-tag type="primary" style="height: 16px; line-height: 16px; min-width: 40px; text-align: center">{ row[column.property] }</el-tag>; },
|
return <div>#</div>;
|
||||||
|
},
|
||||||
|
template: function(h, { row, column }) {
|
||||||
|
return <el-tag type="primary" style="height: 16px; line-height: 16px; min-width: 40px; text-align: center">{ row[column.property] }</el-tag>;
|
||||||
|
},
|
||||||
resizable: false
|
resizable: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -60,6 +79,12 @@ const getDefaultColumn = function(type, options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!column.minWidth) {
|
||||||
|
column.minWidth = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
column.realWidth = column.width || column.minWidth;
|
||||||
|
|
||||||
return column;
|
return column;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,6 +98,7 @@ export default {
|
||||||
},
|
},
|
||||||
label: String,
|
label: String,
|
||||||
property: String,
|
property: String,
|
||||||
|
prop: String,
|
||||||
width: {},
|
width: {},
|
||||||
minWidth: {},
|
minWidth: {},
|
||||||
template: String,
|
template: String,
|
||||||
|
@ -89,7 +115,9 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
formatter: Function
|
fixed: [Boolean, String],
|
||||||
|
formatter: Function,
|
||||||
|
selectable: Function
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {},
|
render() {},
|
||||||
|
@ -112,16 +140,25 @@ export default {
|
||||||
ElTag
|
ElTag
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
owner() {
|
||||||
|
let parent = this.$parent;
|
||||||
|
while (parent && !parent.tableId) {
|
||||||
|
parent = parent.$parent;
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.customRender = this.$options.render;
|
this.customRender = this.$options.render;
|
||||||
this.$options.render = (h) => h('div');
|
this.$options.render = (h) => h('div');
|
||||||
|
|
||||||
let columnId = this.columnId = (this.$parent.gridId || (this.$parent.columnId + '_')) + 'column_' + columnIdSeed++;
|
let columnId = this.columnId = (this.$parent.tableId || (this.$parent.columnId + '_')) + 'column_' + columnIdSeed++;
|
||||||
|
|
||||||
let parent = this.$parent;
|
let parent = this.$parent;
|
||||||
if (!parent.gridId) {
|
let owner = this.owner;
|
||||||
this.isChildColumn = true;
|
this.isChildColumn = owner !== parent;
|
||||||
}
|
|
||||||
|
|
||||||
let type = this.type;
|
let type = this.type;
|
||||||
|
|
||||||
|
@ -139,17 +176,15 @@ export default {
|
||||||
if (isNaN(minWidth)) {
|
if (isNaN(minWidth)) {
|
||||||
minWidth = 80;
|
minWidth = 80;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
minWidth = 80;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let isColumnGroup = false;
|
let isColumnGroup = false;
|
||||||
let template;
|
let template;
|
||||||
|
|
||||||
let property = this.property;
|
let property = this.prop || this.property;
|
||||||
if (property) {
|
if (property) {
|
||||||
template = function(h, { row }, parent) {
|
template = function(h, { row }, parent) {
|
||||||
return <span>{ parent.$getPropertyText(row, property, columnId) }</span>;
|
return <span>{ parent.getCellContent(row, property, columnId) }</span>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,11 +198,12 @@ export default {
|
||||||
width,
|
width,
|
||||||
isColumnGroup,
|
isColumnGroup,
|
||||||
align: this.align ? 'is-' + this.align : null,
|
align: this.align ? 'is-' + this.align : null,
|
||||||
realWidth: width || minWidth,
|
|
||||||
sortable: this.sortable,
|
sortable: this.sortable,
|
||||||
resizable: this.resizable,
|
resizable: this.resizable,
|
||||||
showTooltipWhenOverflow: this.showTooltipWhenOverflow,
|
showTooltipWhenOverflow: this.showTooltipWhenOverflow,
|
||||||
formatter: this.formatter
|
formatter: this.formatter,
|
||||||
|
selectable: this.selectable,
|
||||||
|
fixed: this.fixed
|
||||||
});
|
});
|
||||||
|
|
||||||
objectAssign(column, forced[type] || {});
|
objectAssign(column, forced[type] || {});
|
||||||
|
@ -186,7 +222,7 @@ export default {
|
||||||
|
|
||||||
return _self.customRender.call(data);
|
return _self.customRender.call(data);
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
return _self.showTooltipWhenOverflow
|
return _self.showTooltipWhenOverflow
|
||||||
? <el-tooltip
|
? <el-tooltip
|
||||||
|
@ -203,31 +239,8 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
destroyed() {
|
||||||
if (!this.$parent) {
|
if (!this.$parent) return;
|
||||||
return;
|
this.owner.store.commit('removeColumn', this.columnConfig);
|
||||||
}
|
|
||||||
let columns = this.$parent.columns;
|
|
||||||
if (columns) {
|
|
||||||
let columnId = this.columnId;
|
|
||||||
for (let i = 0, j = columns.length; i < j; i++) {
|
|
||||||
let column = columns[i];
|
|
||||||
|
|
||||||
if (column.id === columnId) {
|
|
||||||
columns.splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isChildColumn) {
|
|
||||||
if (this.$parent.$parent.$ready) {
|
|
||||||
this.$parent.$parent.debouncedReRender();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.$parent.$ready) {
|
|
||||||
this.$parent.debouncedReRender();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -237,6 +250,12 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
prop(newVal) {
|
||||||
|
if (this.columnConfig) {
|
||||||
|
this.columnConfig.property = newVal;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
property(newVal) {
|
property(newVal) {
|
||||||
if (this.columnConfig) {
|
if (this.columnConfig) {
|
||||||
this.columnConfig.property = newVal;
|
this.columnConfig.property = newVal;
|
||||||
|
@ -245,8 +264,8 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
let parent = this.$parent;
|
const owner = this.owner;
|
||||||
let columnConfig = this.columnConfig;
|
const parent = this.$parent;
|
||||||
let columnIndex;
|
let columnIndex;
|
||||||
|
|
||||||
if (!this.isChildColumn) {
|
if (!this.isChildColumn) {
|
||||||
|
@ -255,18 +274,6 @@ export default {
|
||||||
columnIndex = [].indexOf.call(parent.$el.children, this.$el);
|
columnIndex = [].indexOf.call(parent.$el.children, this.$el);
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.columns.splice(columnIndex, 0, columnConfig);
|
owner.store.commit('insertColumn', this.columnConfig, columnIndex);
|
||||||
|
|
||||||
if (this.isChildColumn) {
|
|
||||||
parent.columnConfig.columns = parent.columns;
|
|
||||||
|
|
||||||
if (parent.$parent.$ready) {
|
|
||||||
parent.$parent.debouncedReRender();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (parent.$ready) {
|
|
||||||
parent.debouncedReRender();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,47 +16,58 @@ export default {
|
||||||
<colgroup
|
<colgroup
|
||||||
name={ column.id }
|
name={ column.id }
|
||||||
width={ column.realWidth || column.width }
|
width={ column.realWidth || column.width }
|
||||||
/>).concat(
|
/>)
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
{
|
|
||||||
this._l(this.columns, column =>
|
|
||||||
<th
|
|
||||||
on-mousemove={ ($event) => this.handleMouseMove($event, column) }
|
|
||||||
on-mouseout={ this.handleMouseOut }
|
|
||||||
on-mousedown={ ($event) => this.handleMouseDown($event, column) }
|
|
||||||
on-click={ ($event) => this.handleHeaderClick($event, column) }
|
|
||||||
class={ [column.id, column.direction, column.align] }>
|
|
||||||
{
|
|
||||||
[
|
|
||||||
column.headerTemplate
|
|
||||||
? column.headerTemplate.call(this._renderProxy, h, column.label)
|
|
||||||
: <div>{ column.label }</div>,
|
|
||||||
column.sortable
|
|
||||||
? <div class="caret-wrapper">
|
|
||||||
<i class="sort-caret ascending"></i>
|
|
||||||
<i class="sort-caret descending"></i>
|
|
||||||
</div>
|
|
||||||
: ''
|
|
||||||
]
|
|
||||||
}
|
|
||||||
</th>
|
|
||||||
).concat(this.$parent.showVScrollBar && this.$parent.currentGutterWidth ? <th class="gutter"
|
|
||||||
style={{ width: this.$parent.currentGutterWidth + 'px' }}></th> : '')
|
|
||||||
}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
!this.fixed && this.layout.gutterWidth
|
||||||
|
? <colgroup name="gutter" width={ this.layout.scrollY ? this.layout.gutterWidth : '' }></colgroup>
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{
|
||||||
|
this._l(this.columns, column =>
|
||||||
|
<th
|
||||||
|
on-mousemove={ ($event) => this.handleMouseMove($event, column) }
|
||||||
|
on-mouseout={ this.handleMouseOut }
|
||||||
|
on-mousedown={ ($event) => this.handleMouseDown($event, column) }
|
||||||
|
on-click={ ($event) => this.handleHeaderClick($event, column) }
|
||||||
|
class={ [column.id, column.direction, column.align] }>
|
||||||
|
{
|
||||||
|
[
|
||||||
|
column.headerTemplate
|
||||||
|
? column.headerTemplate.call(this._renderProxy, h, column.label)
|
||||||
|
: <div>{ column.label }</div>,
|
||||||
|
column.sortable
|
||||||
|
? <div class="caret-wrapper">
|
||||||
|
<i class="sort-caret ascending"></i>
|
||||||
|
<i class="sort-caret descending"></i>
|
||||||
|
</div>
|
||||||
|
: ''
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</th>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
!this.fixed && this.layout.gutterWidth
|
||||||
|
? <th class="gutter" style={{ width: this.layout.scrollY ? this.layout.gutterWidth + 'px' : '0' }}></th>
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
columns: {},
|
columns: {},
|
||||||
fixed: Boolean,
|
fixed: String,
|
||||||
allSelected: {
|
store: {
|
||||||
default: Boolean
|
required: true
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
required: true
|
||||||
},
|
},
|
||||||
border: Boolean
|
border: Boolean
|
||||||
},
|
},
|
||||||
|
@ -66,9 +77,24 @@ export default {
|
||||||
ElTag
|
ElTag
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isAllSelected() {
|
||||||
|
return this.store.states.isAllSelected;
|
||||||
|
},
|
||||||
|
|
||||||
|
columns() {
|
||||||
|
if (this.fixed === true || this.fixed === 'left') {
|
||||||
|
return this.store.states.fixedColumns;
|
||||||
|
} else if (this.fixed === 'right') {
|
||||||
|
return this.store.states.rightFixedColumns;
|
||||||
|
}
|
||||||
|
return this.store.states.columns;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
toggleAllSelection($event) {
|
toggleAllSelection() {
|
||||||
this.$parent.toggleAllSelection($event);
|
this.store.commit('toggleAllSelection');
|
||||||
},
|
},
|
||||||
|
|
||||||
handleMouseDown(event, column) {
|
handleMouseDown(event, column) {
|
||||||
|
@ -77,19 +103,19 @@ export default {
|
||||||
|
|
||||||
this.$parent.resizeProxyVisible = true;
|
this.$parent.resizeProxyVisible = true;
|
||||||
|
|
||||||
const gridEl = this.$parent.$el;
|
const tableEl = this.$parent.$el;
|
||||||
const gridLeft = gridEl.getBoundingClientRect().left;
|
const tableLeft = tableEl.getBoundingClientRect().left;
|
||||||
const columnEl = this.$el.querySelector(`th.${column.id}`);
|
const columnEl = this.$el.querySelector(`th.${column.id}`);
|
||||||
const columnRect = columnEl.getBoundingClientRect();
|
const columnRect = columnEl.getBoundingClientRect();
|
||||||
const minLeft = columnRect.left - gridLeft + 30;
|
const minLeft = columnRect.left - tableLeft + 30;
|
||||||
|
|
||||||
columnEl.classList.add('noclick');
|
columnEl.classList.add('noclick');
|
||||||
|
|
||||||
this.dragState = {
|
this.dragState = {
|
||||||
startMouseLeft: event.clientX,
|
startMouseLeft: event.clientX,
|
||||||
startLeft: columnRect.right - gridLeft,
|
startLeft: columnRect.right - tableLeft,
|
||||||
startColumnLeft: columnRect.left - gridLeft,
|
startColumnLeft: columnRect.left - tableLeft,
|
||||||
gridLeft: gridLeft
|
tableLeft
|
||||||
};
|
};
|
||||||
|
|
||||||
const resizeProxy = this.$parent.$refs.resizeProxy;
|
const resizeProxy = this.$parent.$refs.resizeProxy;
|
||||||
|
@ -98,22 +124,20 @@ export default {
|
||||||
document.onselectstart = function() { return false; };
|
document.onselectstart = function() { return false; };
|
||||||
document.ondragstart = function() { return false; };
|
document.ondragstart = function() { return false; };
|
||||||
|
|
||||||
const mousemove = (event) => {
|
const handleMouseMove = (event) => {
|
||||||
const deltaLeft = event.clientX - this.dragState.startMouseLeft;
|
const deltaLeft = event.clientX - this.dragState.startMouseLeft;
|
||||||
const proxyLeft = this.dragState.startLeft + deltaLeft;
|
const proxyLeft = this.dragState.startLeft + deltaLeft;
|
||||||
|
|
||||||
resizeProxy.style.left = Math.max(minLeft, proxyLeft) + 'px';
|
resizeProxy.style.left = Math.max(minLeft, proxyLeft) + 'px';
|
||||||
};
|
};
|
||||||
|
|
||||||
const mouseup = () => {
|
const handleMouseUp = () => {
|
||||||
if (this.dragging) {
|
if (this.dragging) {
|
||||||
const finalLeft = parseInt(resizeProxy.style.left, 10);
|
const finalLeft = parseInt(resizeProxy.style.left, 10);
|
||||||
const columnWidth = finalLeft - this.dragState.startColumnLeft;
|
const columnWidth = finalLeft - this.dragState.startColumnLeft;
|
||||||
column.width = column.realWidth = columnWidth;
|
column.width = column.realWidth = columnWidth;
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.store.scheduleLayout();
|
||||||
this.$parent.$calcColumns();
|
|
||||||
});
|
|
||||||
|
|
||||||
document.body.style.cursor = '';
|
document.body.style.cursor = '';
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
|
@ -123,8 +147,8 @@ export default {
|
||||||
this.$parent.resizeProxyVisible = false;
|
this.$parent.resizeProxyVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.removeEventListener('mousemove', mousemove);
|
document.removeEventListener('mousemove', handleMouseMove);
|
||||||
document.removeEventListener('mouseup', mouseup);
|
document.removeEventListener('mouseup', handleMouseUp);
|
||||||
document.onselectstart = null;
|
document.onselectstart = null;
|
||||||
document.ondragstart = null;
|
document.ondragstart = null;
|
||||||
|
|
||||||
|
@ -133,8 +157,8 @@ export default {
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('mousemove', mousemove);
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
document.addEventListener('mouseup', mouseup);
|
document.addEventListener('mouseup', handleMouseUp);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -146,13 +170,14 @@ export default {
|
||||||
if (!this.dragging && this.border) {
|
if (!this.dragging && this.border) {
|
||||||
let rect = target.getBoundingClientRect();
|
let rect = target.getBoundingClientRect();
|
||||||
|
|
||||||
|
var bodyStyle = document.body.style;
|
||||||
if (rect.width > 12 && rect.right - event.pageX < 8) {
|
if (rect.width > 12 && rect.right - event.pageX < 8) {
|
||||||
document.body.style.cursor = 'col-resize';
|
bodyStyle.cursor = 'col-resize';
|
||||||
this.draggingColumn = column;
|
this.draggingColumn = column;
|
||||||
} else if (!this.dragging) {
|
} else if (!this.dragging) {
|
||||||
document.body.style.cursor = '';
|
bodyStyle.cursor = '';
|
||||||
this.draggingColumn = null;
|
this.draggingColumn = null;
|
||||||
if (column.sortable) document.body.style.cursor = 'pointer';
|
if (column.sortable) bodyStyle.cursor = 'pointer';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -176,14 +201,14 @@ export default {
|
||||||
|
|
||||||
if (!column.sortable) return;
|
if (!column.sortable) return;
|
||||||
|
|
||||||
const grid = this.$parent;
|
const sortCondition = this.store.states.sortCondition;
|
||||||
|
|
||||||
if (grid.sortingColumn !== column) {
|
if (sortCondition.column !== column) {
|
||||||
if (grid.sortingColumn) {
|
if (sortCondition.column) {
|
||||||
grid.sortingColumn.direction = '';
|
sortCondition.column.direction = '';
|
||||||
}
|
}
|
||||||
grid.sortingColumn = column;
|
sortCondition.column = column;
|
||||||
grid.sortingProperty = column.property;
|
sortCondition.property = column.property;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!column.direction) {
|
if (!column.direction) {
|
||||||
|
@ -192,25 +217,12 @@ export default {
|
||||||
column.direction = 'descending';
|
column.direction = 'descending';
|
||||||
} else {
|
} else {
|
||||||
column.direction = '';
|
column.direction = '';
|
||||||
grid.sortingColumn = null;
|
sortCondition.column = null;
|
||||||
grid.sortingProperty = null;
|
sortCondition.property = null;
|
||||||
}
|
}
|
||||||
|
sortCondition.direction = column.direction === 'descending' ? -1 : 1;
|
||||||
|
|
||||||
grid.sortingDirection = column.direction === 'descending' ? -1 : 1;
|
this.store.commit('changeSortCondition');
|
||||||
},
|
|
||||||
|
|
||||||
$setVisibleFilter(property) {
|
|
||||||
if (this.visibleFilter) {
|
|
||||||
this.visibleFilter = null;
|
|
||||||
} else {
|
|
||||||
this.visibleFilter = property;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
visibleFilter(val) {
|
|
||||||
this.$parent.visibleFilter = val;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -218,9 +230,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
draggingColumn: null,
|
draggingColumn: null,
|
||||||
dragging: false,
|
dragging: false,
|
||||||
dragState: {},
|
dragState: {}
|
||||||
columnsMap: null,
|
|
||||||
visibleFilter: null
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
import { getScrollBarWidth } from './util';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
let GUTTER_WIDTH;
|
||||||
|
|
||||||
|
class TableLayout {
|
||||||
|
constructor(options) {
|
||||||
|
this.table = null;
|
||||||
|
this.store = null;
|
||||||
|
this.columns = null;
|
||||||
|
this.fit = true;
|
||||||
|
|
||||||
|
this.scrollX = false;
|
||||||
|
this.scrollY = false;
|
||||||
|
this.bodyWidth = null;
|
||||||
|
this.fixedWidth = null;
|
||||||
|
this.rightFixedWidth = null;
|
||||||
|
this.tableHeight = null;
|
||||||
|
this.headerHeight = 44; // Table Header Height
|
||||||
|
this.viewportHeight = null; // Table Height - Scroll Bar Height
|
||||||
|
this.bodyHeight = null; // Table Height - Table Header Height
|
||||||
|
this.fixedBodyHeight = null; // Table Height - Table Header Height - Scroll Bar Height
|
||||||
|
|
||||||
|
if (GUTTER_WIDTH === undefined) {
|
||||||
|
GUTTER_WIDTH = getScrollBarWidth();
|
||||||
|
}
|
||||||
|
this.gutterWidth = GUTTER_WIDTH;
|
||||||
|
|
||||||
|
for (let name in options) {
|
||||||
|
if (options.hasOwnProperty(name)) {
|
||||||
|
this[name] = options[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.table) {
|
||||||
|
throw new Error('table is required for Table Layout');
|
||||||
|
}
|
||||||
|
if (!this.store) {
|
||||||
|
throw new Error('store is required for Table Layout');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syncHeight() {
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
const { bodyWrapper, fixedBodyWrapper } = this.table.$refs;
|
||||||
|
|
||||||
|
// 若非固定列中的某行内容被撑高, 需要固定列中对应行高度与其保持一致
|
||||||
|
const bodyHeight = bodyWrapper.offsetHeight;
|
||||||
|
const fixedBodyHeight = fixedBodyWrapper.offsetHeight;
|
||||||
|
|
||||||
|
if (bodyHeight !== fixedBodyHeight) {
|
||||||
|
const rows = bodyWrapper.querySelectorAll('tr');
|
||||||
|
const fixedRows = fixedBodyWrapper.querySelectorAll('tr');
|
||||||
|
|
||||||
|
[].forEach.call(rows, (row, i) => {
|
||||||
|
const fixedRow = fixedRows[i];
|
||||||
|
const rowHeight = row.offsetHeight;
|
||||||
|
const fixedRowHeight = fixedRow.offsetHeight;
|
||||||
|
if (rowHeight !== fixedRowHeight) {
|
||||||
|
fixedRow.style.height = rowHeight + 'px';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateScrollY() {
|
||||||
|
const bodyWrapper = this.table.$refs.bodyWrapper;
|
||||||
|
if (this.table.$el && bodyWrapper) {
|
||||||
|
const body = bodyWrapper.querySelector('.el-table__body');
|
||||||
|
|
||||||
|
this.scrollY = body.offsetHeight > bodyWrapper.offsetHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setHeight(height) {
|
||||||
|
if (typeof height === 'string' && /^\d+$/.test(height)) {
|
||||||
|
height = Number(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
const el = this.table.$el;
|
||||||
|
if (!isNaN(height) && el) {
|
||||||
|
el.style.height = height + 'px';
|
||||||
|
|
||||||
|
this.updateHeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHeight() {
|
||||||
|
const height = this.tableHeight = this.table.$el.clientHeight;
|
||||||
|
const { headerWrapper } = this.table.$refs;
|
||||||
|
if (!headerWrapper) return;
|
||||||
|
const headerHeight = this.headerHeight = headerWrapper.offsetHeight;
|
||||||
|
const bodyHeight = this.bodyHeight = height - headerHeight;
|
||||||
|
this.fixedBodyHeight = this.scrollX ? bodyHeight - this.gutterWidth : bodyHeight;
|
||||||
|
this.viewportHeight = this.scrollX ? height - this.gutterWidth : height;
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
const fit = this.fit;
|
||||||
|
const columns = this.table.columns;
|
||||||
|
const bodyWidth = this.table.$el.clientWidth;
|
||||||
|
let bodyMinWidth = 0;
|
||||||
|
|
||||||
|
const flattenColumns = [];
|
||||||
|
columns.forEach((column) => {
|
||||||
|
if (column.isColumnGroup) {
|
||||||
|
flattenColumns.push.apply(flattenColumns, column.columns);
|
||||||
|
} else {
|
||||||
|
flattenColumns.push(column);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let flexColumns = flattenColumns.filter((column) => typeof column.width !== 'number');
|
||||||
|
|
||||||
|
if (flexColumns.length > 0 && fit) {
|
||||||
|
flattenColumns.forEach((column) => {
|
||||||
|
bodyMinWidth += column.width || column.minWidth || 80;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bodyMinWidth < bodyWidth - this.gutterWidth) { // DON'T HAVE SCROLL BAR
|
||||||
|
this.scrollX = false;
|
||||||
|
|
||||||
|
const totalFlexWidth = bodyWidth - this.gutterWidth - bodyMinWidth;
|
||||||
|
|
||||||
|
if (flexColumns.length === 1) {
|
||||||
|
flexColumns[0].realWidth = (flexColumns[0].minWidth || 80) + totalFlexWidth;
|
||||||
|
} else {
|
||||||
|
const allColumnsWidth = flexColumns.reduce((prev, column) => prev + (column.minWidth || 80), 0);
|
||||||
|
const flexWidthPerPixel = totalFlexWidth / allColumnsWidth;
|
||||||
|
let noneFirstWidth = 0;
|
||||||
|
|
||||||
|
flexColumns.forEach((column, index) => {
|
||||||
|
if (index === 0) return;
|
||||||
|
const flexWidth = Math.floor((column.minWidth || 80) * flexWidthPerPixel);
|
||||||
|
noneFirstWidth += flexWidth;
|
||||||
|
column.realWidth = (column.minWidth || 80) + flexWidth;
|
||||||
|
});
|
||||||
|
|
||||||
|
flexColumns[0].realWidth = (flexColumns[0].minWidth || 80) + totalFlexWidth - noneFirstWidth;
|
||||||
|
}
|
||||||
|
} else { // HAVE HORIZONTAL SCROLL BAR
|
||||||
|
this.scrollX = true;
|
||||||
|
flexColumns.forEach(function(column) {
|
||||||
|
column.realWidth = column.minWidth;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bodyWidth = Math.max(bodyMinWidth, bodyWidth);
|
||||||
|
} else {
|
||||||
|
flattenColumns.forEach((column) => {
|
||||||
|
if (!column.width && !column.minWidth) {
|
||||||
|
column.realWidth = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyMinWidth += column.realWidth;
|
||||||
|
});
|
||||||
|
this.scrollX = bodyMinWidth > bodyWidth;
|
||||||
|
|
||||||
|
this.bodyWidth = bodyMinWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixedColumns = this.store.states.fixedColumns;
|
||||||
|
|
||||||
|
if (fixedColumns.length > 0) {
|
||||||
|
let fixedWidth = 0;
|
||||||
|
fixedColumns.forEach(function(column) {
|
||||||
|
fixedWidth += column.realWidth;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fixedWidth = fixedWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rightFixedColumns = this.store.states.rightFixedColumns;
|
||||||
|
if (rightFixedColumns.length > 0) {
|
||||||
|
let rightFixedWidth = 0;
|
||||||
|
rightFixedColumns.forEach(function(column) {
|
||||||
|
rightFixedWidth += column.realWidth;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.rightFixedWidth = rightFixedWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TableLayout;
|
|
@ -0,0 +1,176 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
import debounce from 'throttle-debounce/debounce';
|
||||||
|
import { orderBy } from './util';
|
||||||
|
|
||||||
|
const TableStore = function(table, initialState = {}) {
|
||||||
|
if (!table) {
|
||||||
|
throw new Error('Table is required.');
|
||||||
|
}
|
||||||
|
this.table = table;
|
||||||
|
|
||||||
|
this.states = {
|
||||||
|
_columns: [],
|
||||||
|
columns: [],
|
||||||
|
fixedColumns: [],
|
||||||
|
rightFixedColumns: [],
|
||||||
|
_data: null,
|
||||||
|
data: null,
|
||||||
|
sortCondition: {
|
||||||
|
column: null,
|
||||||
|
property: null,
|
||||||
|
direction: null
|
||||||
|
},
|
||||||
|
isAllSelected: false,
|
||||||
|
selection: null,
|
||||||
|
allowNoSelection: false,
|
||||||
|
selectionMode: 'none',
|
||||||
|
selectable: null,
|
||||||
|
currentRow: null,
|
||||||
|
hoverRow: null
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let prop in initialState) {
|
||||||
|
if (initialState.hasOwnProperty(prop) && this.states.hasOwnProperty(prop)) {
|
||||||
|
this.states[prop] = initialState[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TableStore.prototype.mutations = {
|
||||||
|
setData(states, data) {
|
||||||
|
states._data = data;
|
||||||
|
if (data && data[0] && typeof data[0].$selected === 'undefined') {
|
||||||
|
data.forEach((item) => Vue.set(item, '$selected', false));
|
||||||
|
}
|
||||||
|
states.data = orderBy((data || []), states.sortCondition.property, states.sortCondition.direction);
|
||||||
|
this.updateSelectedRow();
|
||||||
|
|
||||||
|
if (states.fixedColumns.length > 0 || states.rightFixedColumns.length > 0) Vue.nextTick(() => this.table.syncHeight());
|
||||||
|
Vue.nextTick(() => this.table.updateScrollY());
|
||||||
|
},
|
||||||
|
|
||||||
|
changeSortCondition(states) {
|
||||||
|
states.data = orderBy((states._data || []), states.sortCondition.property, states.sortCondition.direction);
|
||||||
|
|
||||||
|
if (states.fixedColumns.length > 0 || states.rightFixedColumns.length > 0) Vue.nextTick(() => this.table.syncHeight());
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (column.type === 'selection') {
|
||||||
|
states.selectable = column.selectable;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scheduleLayout();
|
||||||
|
},
|
||||||
|
|
||||||
|
removeColumn(states, column) {
|
||||||
|
let _columns = states._columns;
|
||||||
|
if (_columns) {
|
||||||
|
_columns.splice(_columns.indexOf(column), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scheduleLayout();
|
||||||
|
},
|
||||||
|
|
||||||
|
setHoverRow(states, row) {
|
||||||
|
states.hoverRow = row;
|
||||||
|
},
|
||||||
|
|
||||||
|
rowSelectedChanged(states) {
|
||||||
|
let isAllSelected = true;
|
||||||
|
const data = states.data || [];
|
||||||
|
for (let i = 0, j = data.length; i < j; i++) {
|
||||||
|
const item = data[i];
|
||||||
|
if (states.selectable) {
|
||||||
|
if (states.selectable.call(null, item, i) && !item.$selected) {
|
||||||
|
isAllSelected = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!item.$selected) {
|
||||||
|
isAllSelected = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
states.isAllSelected = isAllSelected;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleAllSelection: debounce(10, function(states) {
|
||||||
|
const data = states.data || [];
|
||||||
|
const value = !states.isAllSelected;
|
||||||
|
data.forEach((item, index) => {
|
||||||
|
if (states.selectable) {
|
||||||
|
if (states.selectable.call(null, item, index)) {
|
||||||
|
item.$selected = value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.$selected = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
states.isAllSelected = value;
|
||||||
|
}),
|
||||||
|
|
||||||
|
setSelectedRow(states, row) {
|
||||||
|
if (states.selectionMode === 'single') {
|
||||||
|
states.currentRow = row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TableStore.prototype.updateColumns = function() {
|
||||||
|
const states = this.states;
|
||||||
|
const _columns = states._columns || [];
|
||||||
|
states.fixedColumns = _columns.filter((column) => column.fixed === true || column.fixed === 'left');
|
||||||
|
states.rightFixedColumns = _columns.filter((column) => column.fixed === 'right');
|
||||||
|
|
||||||
|
if (states.fixedColumns.length > 0 && _columns[0] && _columns[0].type === 'selection' && !_columns[0].fixed) {
|
||||||
|
_columns[0].fixed = true;
|
||||||
|
states.fixedColumns.unshift(_columns[0]);
|
||||||
|
}
|
||||||
|
states.columns = [].concat(states.fixedColumns).concat(_columns.filter((column) => !column.fixed)).concat(states.rightFixedColumns);
|
||||||
|
};
|
||||||
|
|
||||||
|
TableStore.prototype.updateSelectedRow = function() {
|
||||||
|
const states = this.states;
|
||||||
|
const table = this.table;
|
||||||
|
const data = states.data || [];
|
||||||
|
if (states.selectionMode === 'single') {
|
||||||
|
const oldSelectedRow = states.currentRow;
|
||||||
|
if (oldSelectedRow === null && !states.allowNoSelection) {
|
||||||
|
states.currentRow = data[0];
|
||||||
|
if (states.currentRow !== oldSelectedRow) {
|
||||||
|
table.$emit('selectionchange', states.currentRow);
|
||||||
|
}
|
||||||
|
} else if (data.indexOf(oldSelectedRow) === -1) {
|
||||||
|
if (!states.allowNoSelection) {
|
||||||
|
states.currentRow = data[0];
|
||||||
|
} else {
|
||||||
|
states.currentRow = null;
|
||||||
|
}
|
||||||
|
if (states.currentRow !== oldSelectedRow) {
|
||||||
|
table.$emit('selectionchange', states.currentRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TableStore.prototype.scheduleLayout = function() {
|
||||||
|
this.table.debouncedLayout();
|
||||||
|
};
|
||||||
|
|
||||||
|
TableStore.prototype.commit = function(name, ...args) {
|
||||||
|
const mutations = this.mutations;
|
||||||
|
if (mutations[name]) {
|
||||||
|
mutations[name].apply(this, [this.states].concat(args));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TableStore;
|
|
@ -1,38 +1,99 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="el-table" :class="{ 'el-table--fit': fit, 'el-table--striped': stripe, 'el-table--border': border }" @mouseleave="handleMouseLeave($event)">
|
<div class="el-table"
|
||||||
|
:class="{ 'el-table--fit': fit, 'el-table--striped': stripe, 'el-table--border': border }"
|
||||||
|
@mouseleave="handleMouseLeave($event)">
|
||||||
<div class="hidden-columns" ref="hiddenColumns"><slot></slot></div>
|
<div class="hidden-columns" ref="hiddenColumns"><slot></slot></div>
|
||||||
<div class="el-table__header-wrapper">
|
<div class="el-table__header-wrapper" ref="headerWrapper">
|
||||||
<table-header :columns="columns" :all-selected="allSelected" @allselectedchange="handleAllSelectedChange" :selection="selection" :style="{ width: bodyWidth ? bodyWidth + 'px' : '' }" :border="border"></table-header>
|
<table-header
|
||||||
|
:store="store"
|
||||||
|
:layout="layout"
|
||||||
|
:border="border"
|
||||||
|
:style="{ width: layout.bodyWidth ? layout.bodyWidth + 'px' : '' }">
|
||||||
|
</table-header>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-table__body-wrapper">
|
<div class="el-table__body-wrapper" ref="bodyWrapper"
|
||||||
<table-body :columns="columns" :selection="selection" :data="filterData" :style="{ width: bodyWidth ? bodyWidth - (showVScrollBar ? currentGutterWidth : 0 ) + 'px' : '' }"></table-body>
|
:style="{ height: layout.bodyHeight ? layout.bodyHeight + 'px' : '' }">
|
||||||
|
<table-body
|
||||||
|
:store="store"
|
||||||
|
:layout="layout"
|
||||||
|
:row-class-name="rowClassName"
|
||||||
|
:style="{ width: layout.bodyWidth ? layout.bodyWidth - (layout.scrollY ? layout.gutterWidth : 0 ) + 'px' : '' }">
|
||||||
|
</table-body>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-table__fixed" :style="{ width: fixedBodyWidth ? fixedBodyWidth + 'px' : '' }" ref="fixed">
|
<div class="el-table__fixed" ref="fixedWrapper"
|
||||||
<div class="el-table__fixed-header-wrapper" v-if="fixedColumnCount > 0">
|
:style="{
|
||||||
<table-header :columns="fixedColumns" :all-selected="allSelected" @allselectedchange="handleAllSelectedChange" :selection="selection" :style="{ width: fixedBodyWidth ? fixedBodyWidth + 'px' : '' }" :border="border"></table-header>
|
width: layout.fixedWidth ? layout.fixedWidth + 'px' : '',
|
||||||
|
height: layout.viewportHeight ? layout.viewportHeight + 'px' : ''
|
||||||
|
}">
|
||||||
|
<div class="el-table__fixed-header-wrapper" ref="fixedHeaderWrapper"
|
||||||
|
v-if="fixedColumns.length > 0">
|
||||||
|
<table-header
|
||||||
|
fixed="left"
|
||||||
|
:border="border"
|
||||||
|
:store="store"
|
||||||
|
:layout="layout"
|
||||||
|
:style="{ width: layout.fixedWidth ? layout.fixedWidth + 'px' : '' }"></table-header>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-table__fixed-body-wrapper" v-if="fixedColumnCount > 0" :style="{ top: headerHeight + 'px' }">
|
<div class="el-table__fixed-body-wrapper" ref="fixedBodyWrapper"
|
||||||
<table-body :columns="fixedColumns" fixed :selection="selection" :data="filterData" :style="{ width: fixedBodyWidth ? fixedBodyWidth + 'px' : '' }"></table-body>
|
v-if="fixedColumns.length > 0"
|
||||||
|
:style="{
|
||||||
|
top: layout.headerHeight + 'px',
|
||||||
|
height: layout.fixedBodyHeight ? layout.fixedBodyHeight + 'px' : ''
|
||||||
|
}">
|
||||||
|
<table-body
|
||||||
|
fixed="left"
|
||||||
|
:store="store"
|
||||||
|
:layout="layout"
|
||||||
|
:row-class-name="rowClassName"
|
||||||
|
:style="{ width: layout.fixedWidth ? layout.fixedWidth + 'px' : '' }">
|
||||||
|
</table-body>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="el-table__fixed-right" ref="rightFixedWrapper"
|
||||||
|
:style="{
|
||||||
|
width: layout.rightFixedWidth ? layout.rightFixedWidth + 'px' : '',
|
||||||
|
height: layout.viewportHeight ? layout.viewportHeight + 'px' : '',
|
||||||
|
right: layout.scrollY ? layout.gutterWidth + 'px' : ''
|
||||||
|
}">
|
||||||
|
<div class="el-table__fixed-header-wrapper" ref="rightFixedHeaderWrapper"
|
||||||
|
v-if="rightFixedColumns.length > 0">
|
||||||
|
<table-header
|
||||||
|
fixed="right"
|
||||||
|
:border="border"
|
||||||
|
:store="store"
|
||||||
|
:layout="layout"
|
||||||
|
:style="{ width: layout.rightFixedWidth ? layout.rightFixedWidth + 'px' : '' }"></table-header>
|
||||||
|
</div>
|
||||||
|
<div class="el-table__fixed-body-wrapper" ref="rightFixedBodyWrapper"
|
||||||
|
v-if="rightFixedColumns.length > 0"
|
||||||
|
:style="{
|
||||||
|
top: layout.headerHeight + 'px',
|
||||||
|
height: layout.fixedBodyHeight ? layout.fixedBodyHeight + 'px' : ''
|
||||||
|
}">
|
||||||
|
<table-body
|
||||||
|
fixed="right"
|
||||||
|
:store="store"
|
||||||
|
:layout="layout"
|
||||||
|
:row-class-name="rowClassName"
|
||||||
|
:style="{ width: layout.rightFixedWidth ? layout.rightFixedWidth + 'px' : '' }">
|
||||||
|
</table-body>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-table__column-resize-proxy" ref="resizeProxy" v-show="resizeProxyVisible"></div>
|
<div class="el-table__column-resize-proxy" ref="resizeProxy" v-show="resizeProxyVisible"></div>
|
||||||
<slot name="bottom"></slot>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script type="text/babel">
|
<script type="text/babel">
|
||||||
import throttle from 'throttle-debounce/throttle';
|
import throttle from 'throttle-debounce/throttle';
|
||||||
import debounce from 'throttle-debounce/debounce';
|
import debounce from 'throttle-debounce/debounce';
|
||||||
import { getScrollBarWidth, orderBy } from './util';
|
|
||||||
import objectAssign from 'object-assign';
|
|
||||||
import { addResizeListener, removeResizeListener } from './resize-event';
|
import { addResizeListener, removeResizeListener } from './resize-event';
|
||||||
|
import TableStore from './table-store';
|
||||||
let gridIdSeed = 1;
|
import TableLayout from './table-layout';
|
||||||
let GUTTER_WIDTH;
|
|
||||||
|
|
||||||
import TableBody from './table-body';
|
import TableBody from './table-body';
|
||||||
import TableHeader from './table-header';
|
import TableHeader from './table-header';
|
||||||
|
|
||||||
|
let tableIdSeed = 1;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'el-table',
|
name: 'el-table',
|
||||||
|
|
||||||
|
@ -53,39 +114,18 @@
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
|
||||||
stripe: {
|
stripe: Boolean,
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
|
|
||||||
border: {
|
border: Boolean,
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
|
|
||||||
fixedColumnCount: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
|
|
||||||
selectionMode: {
|
selectionMode: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'none'
|
default: 'none'
|
||||||
},
|
},
|
||||||
|
|
||||||
selection: {},
|
allowNoSelection: Boolean,
|
||||||
|
|
||||||
allowNoSelection: {
|
rowClassName: [String, Function]
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
|
|
||||||
gutterWidth: {
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
|
|
||||||
customCriteria: Array,
|
|
||||||
customBackgroundColors: Array
|
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
@ -94,371 +134,131 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
handleAllSelectedChange(val) {
|
|
||||||
this.allSelected = val;
|
|
||||||
},
|
|
||||||
|
|
||||||
doOnDataChange(data) {
|
|
||||||
data = data || [];
|
|
||||||
|
|
||||||
if (this.selectionMode === 'single') {
|
|
||||||
const oldSelection = this.selected;
|
|
||||||
if (oldSelection === null) {
|
|
||||||
if (!this.allowNoSelection) {
|
|
||||||
this.selected = data[0];
|
|
||||||
if (this.selected !== oldSelection) {
|
|
||||||
this.$emit('selectionchange', this.selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (data.indexOf(oldSelection) === -1) {
|
|
||||||
if (!this.allowNoSelection) {
|
|
||||||
this.selected = data[0];
|
|
||||||
} else {
|
|
||||||
this.selected = null;
|
|
||||||
}
|
|
||||||
if (this.selected !== oldSelection) {
|
|
||||||
this.$emit('selectionchange', this.selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleAllSelection() {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.tableData.forEach(item => {
|
|
||||||
item.$selected = this.allSelected;
|
|
||||||
});
|
|
||||||
}, 0);
|
|
||||||
},
|
|
||||||
|
|
||||||
$calcColumns() {
|
|
||||||
let fit = this.fit;
|
|
||||||
let columns = this.columns;
|
|
||||||
|
|
||||||
let bodyWidth = this.$el.clientWidth;
|
|
||||||
let bodyMinWidth = 0;
|
|
||||||
|
|
||||||
let flattenColumns = [];
|
|
||||||
|
|
||||||
columns.forEach((column) => {
|
|
||||||
if (column.isColumnGroup) {
|
|
||||||
flattenColumns.push.apply(flattenColumns, column.columns);
|
|
||||||
} else {
|
|
||||||
flattenColumns.push(column);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (fit) {
|
|
||||||
let flexColumns = [];
|
|
||||||
// let definedWidthColumnsWidth = 0;
|
|
||||||
// let definedMinWidthSum = 0;
|
|
||||||
|
|
||||||
flattenColumns.forEach((column) => {
|
|
||||||
// definedMinWidthSum += column.minWidth || 80;
|
|
||||||
bodyMinWidth += column.width || column.minWidth || 80;
|
|
||||||
|
|
||||||
if (typeof column.width === 'number') {
|
|
||||||
// definedWidthColumnsWidth += column.width;
|
|
||||||
} else {
|
|
||||||
flexColumns.push(column);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (bodyMinWidth < bodyWidth - this.currentGutterWidth) { // do not have scroll bar.
|
|
||||||
let flexWidthTotal = bodyWidth - this.currentGutterWidth - columns.length - bodyMinWidth;
|
|
||||||
let flexWidthPerColumn = Math.floor(flexWidthTotal / flexColumns.length);
|
|
||||||
let flexWidthFirstColumn = flexWidthTotal - flexWidthPerColumn * flexColumns.length + flexWidthPerColumn;
|
|
||||||
|
|
||||||
flexColumns.forEach((column, index) => {
|
|
||||||
if (index === 0) {
|
|
||||||
column.realWidth = (column.minWidth || 80) + flexWidthFirstColumn;
|
|
||||||
} else {
|
|
||||||
column.realWidth = (column.minWidth || 80) + flexWidthPerColumn;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else { // need horizontal scroll bar.
|
|
||||||
this.showHScrollBar = true;
|
|
||||||
flexColumns.forEach(function(column) {
|
|
||||||
column.realWidth = column.minWidth;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.bodyWidth = Math.max(bodyMinWidth, bodyWidth);
|
|
||||||
} else {
|
|
||||||
flattenColumns.forEach((column) => {
|
|
||||||
if (!column.width && !column.minWidth) {
|
|
||||||
column.realWidth = 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
bodyMinWidth += column.realWidth;
|
|
||||||
});
|
|
||||||
this.showHScrollBar = bodyMinWidth > bodyWidth;
|
|
||||||
|
|
||||||
this.bodyWidth = bodyMinWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.styleNode) {
|
|
||||||
let styleSheet = this.styleNode.sheet;
|
|
||||||
|
|
||||||
if (!styleSheet) return;
|
|
||||||
for (let i = 0, j = styleSheet.cssRules.length; i < j; i++) {
|
|
||||||
styleSheet.deleteRule(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
columns.forEach(function(column) {
|
|
||||||
const addRule = function(rule) {
|
|
||||||
styleSheet.insertRule(rule, styleSheet.cssRules.length);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (column.isColumnGroup) {
|
|
||||||
let childColumns = column.columns;
|
|
||||||
let groupWidth = 0;
|
|
||||||
childColumns.forEach(function(childColumn) {
|
|
||||||
groupWidth += childColumn.realWidth;
|
|
||||||
addRule(`.${childColumn.id}, .${childColumn.id} > div { width: ${childColumn.realWidth}px; }`);
|
|
||||||
});
|
|
||||||
|
|
||||||
addRule(`.${column.id}, .${column.id} > div { width: ${groupWidth}px; }`);
|
|
||||||
} else {
|
|
||||||
addRule(`.${column.id}, .${column.id} > div { width: ${column.realWidth}px; }`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.fixedColumnCount > 0) {
|
|
||||||
let fixedBodyWidth = 0;
|
|
||||||
let fixedColumnCount = this.fixedColumnCount;
|
|
||||||
columns.forEach(function(column, index) {
|
|
||||||
if (index < fixedColumnCount) {
|
|
||||||
fixedBodyWidth += column.realWidth;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.fixedBodyWidth = fixedBodyWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.headerHeight = this.$el.querySelector('.el-table__header-wrapper').offsetHeight;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
$calcHeight(height) {
|
|
||||||
if (typeof height === 'string' && /^\d+$/.test(height)) {
|
|
||||||
height = Number(height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNaN(height) && this.$el) {
|
|
||||||
const headerHeight = this.headerHeight = this.$el.querySelector('.el-table__header-wrapper').offsetHeight;
|
|
||||||
const bodyHeight = (height - headerHeight);
|
|
||||||
const gridWrapper = this.$el.querySelector('.el-table__body-wrapper');
|
|
||||||
gridWrapper.style.height = bodyHeight + 'px';
|
|
||||||
this.$el.style.height = height + 'px';
|
|
||||||
if (this.$refs.fixed) {
|
|
||||||
this.$refs.fixed.style.height = height + 'px';
|
|
||||||
}
|
|
||||||
const fixedBodyWrapper = this.$el.querySelector('.el-table__fixed-body-wrapper');
|
|
||||||
if (fixedBodyWrapper) {
|
|
||||||
fixedBodyWrapper.style.height = (this.showHScrollBar ? gridWrapper.offsetHeight - this.currentGutterWidth : gridWrapper.offsetHeight) + 'px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleMouseLeave() {
|
handleMouseLeave() {
|
||||||
this.hoverRowIndex = null;
|
this.store.commit('setHoverRow', null);
|
||||||
const hoverState = this.hoverState;
|
if (this.hoverState) this.hoverState = null;
|
||||||
if (hoverState) {
|
|
||||||
this.hoverState = null;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updateScrollInfo() {
|
updateScrollY() {
|
||||||
this.$nextTick(() => {
|
this.layout.updateScrollY();
|
||||||
if (this.$el) {
|
},
|
||||||
let gridBodyWrapper = this.$el.querySelector('.el-table__body-wrapper');
|
|
||||||
let gridBody = this.$el.querySelector('.el-table__body-wrapper .el-table__body');
|
|
||||||
|
|
||||||
this.showVScrollBar = gridBody.offsetHeight > gridBodyWrapper.offsetHeight;
|
syncHeight() {
|
||||||
}
|
this.layout.syncHeight();
|
||||||
|
},
|
||||||
|
|
||||||
|
bindEvents() {
|
||||||
|
const { bodyWrapper, headerWrapper } = this.$refs;
|
||||||
|
const refs = this.$refs;
|
||||||
|
bodyWrapper.addEventListener('scroll', function() {
|
||||||
|
headerWrapper.scrollLeft = this.scrollLeft;
|
||||||
|
if (refs.fixedBodyWrapper) refs.fixedBodyWrapper.scrollTop = this.scrollTop;
|
||||||
|
if (refs.rightFixedBodyWrapper) refs.rightFixedBodyWrapper.scrollTop = this.scrollTop;
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
doRender() {
|
if (this.fit) {
|
||||||
let bodyWrapper = this.$el.querySelector('.el-table__body-wrapper');
|
|
||||||
let headerWrapper = this.$el.querySelector('.el-table__header-wrapper');
|
|
||||||
const el = this.$el;
|
|
||||||
|
|
||||||
if (!this.$ready) {
|
|
||||||
bodyWrapper.addEventListener('scroll', function() {
|
|
||||||
headerWrapper.scrollLeft = this.scrollLeft;
|
|
||||||
let fixedBodyWrapper = el.querySelector('.el-table__fixed-body-wrapper');
|
|
||||||
if (fixedBodyWrapper) {
|
|
||||||
fixedBodyWrapper.scrollTop = this.scrollTop;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$calcColumns();
|
|
||||||
|
|
||||||
if (!this.$ready && this.fit) {
|
|
||||||
this.windowResizeListener = throttle(50, () => {
|
this.windowResizeListener = throttle(50, () => {
|
||||||
this.$calcColumns();
|
if (this.$ready) this.doLayout();
|
||||||
});
|
});
|
||||||
addResizeListener(this.$el, this.windowResizeListener);
|
addResizeListener(this.$el, this.windowResizeListener);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
doLayout() {
|
||||||
|
this.store.updateColumns();
|
||||||
|
this.layout.update();
|
||||||
|
this.updateScrollY();
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.height) {
|
if (this.height) {
|
||||||
this.$calcHeight(this.height);
|
this.layout.setHeight(this.height);
|
||||||
|
} else if (this.shouldUpdateHeight) {
|
||||||
|
this.layout.updateHeight();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.gridId = 'grid_' + gridIdSeed + '_';
|
this.tableId = 'el-table_' + tableIdSeed + '_';
|
||||||
|
this.debouncedLayout = debounce(50, () => this.doLayout());
|
||||||
if (GUTTER_WIDTH === undefined) {
|
|
||||||
GUTTER_WIDTH = getScrollBarWidth();
|
|
||||||
}
|
|
||||||
this.currentGutterWidth = GUTTER_WIDTH;
|
|
||||||
|
|
||||||
this.debouncedReRender = debounce(50, () => {
|
|
||||||
this.doRender();
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
shouldUpdateHeight() {
|
||||||
|
return typeof this.height === 'number' ||
|
||||||
|
this.fixedColumns.length > 0 ||
|
||||||
|
this.rightFixedColumns.length > 0;
|
||||||
|
},
|
||||||
|
|
||||||
selection() {
|
selection() {
|
||||||
if (this.selectionMode === 'multiple') {
|
if (this.selectionMode === 'multiple') {
|
||||||
const data = this.tableData || [];
|
const data = this.tableData || [];
|
||||||
return data.filter(item => item.$selected === true);
|
return data.filter(item => item.$selected === true);
|
||||||
} else if (this.selectionMode === 'single') {
|
} else if (this.selectionMode === 'single') {
|
||||||
return this.selected;
|
return this.store.currentRow;
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
columns() {
|
||||||
|
return this.store.states.columns;
|
||||||
|
},
|
||||||
|
|
||||||
|
tableData() {
|
||||||
|
return this.store.states.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
fixedColumns() {
|
fixedColumns() {
|
||||||
const columns = this.columns || [];
|
return this.store.states.fixedColumns;
|
||||||
const fixedColumnCount = this.fixedColumnCount;
|
|
||||||
return columns.filter(function(item, index) {
|
|
||||||
return index < fixedColumnCount;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
filterData() {
|
rightFixedColumns() {
|
||||||
return orderBy(this.tableData, this.sortingProperty, this.sortingDirection);
|
return this.store.states.rightFixedColumns;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
fixedColumnCount() {
|
|
||||||
this.debouncedReRender();
|
|
||||||
},
|
|
||||||
|
|
||||||
selection(val) {
|
selection(val) {
|
||||||
this.$emit('selectionchange', val);
|
this.$emit('selectionchange', val);
|
||||||
if (this.selectionMode === 'multiple') {
|
|
||||||
this.allSelected = this.tableData.length > 0 && val.length === this.tableData.length;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
visibleFilter(val) {
|
|
||||||
this.$broadcast('toggleFilterPopup', val);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
height(value) {
|
height(value) {
|
||||||
this.$calcHeight(value);
|
this.layout.setHeight(value);
|
||||||
},
|
},
|
||||||
|
|
||||||
data: {
|
data: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(val) {
|
handler(val) {
|
||||||
if (val && this.selectionMode === 'multiple') {
|
this.store.commit('setData', val);
|
||||||
this.tableData = val.map(item => objectAssign({ '$selected': false }, item));
|
|
||||||
} else {
|
|
||||||
this.tableData = val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
tableData(newVal) {
|
|
||||||
this.$nextTick(_ => this.doRender());
|
|
||||||
this.doOnDataChange(newVal);
|
|
||||||
this.updateScrollInfo();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
destroyed() {
|
||||||
if (this.styleNode) {
|
if (this.windowResizeListener) removeResizeListener(this.$el, this.windowResizeListener);
|
||||||
this.styleNode.parentNode.removeChild(this.styleNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.windowResizeListener) {
|
|
||||||
removeResizeListener(this.$el, this.windowResizeListener);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
const styleNode = document.createElement('style');
|
this.bindEvents();
|
||||||
styleNode.type = 'text/css';
|
this.doLayout();
|
||||||
styleNode.rel = 'stylesheet';
|
|
||||||
styleNode.title = 'Grid Column Style';
|
|
||||||
document.getElementsByTagName('head')[0].appendChild(styleNode);
|
|
||||||
|
|
||||||
this.styleNode = styleNode;
|
|
||||||
|
|
||||||
this.doRender();
|
|
||||||
|
|
||||||
this.$ready = true;
|
this.$ready = true;
|
||||||
if (this.tableData) {
|
|
||||||
this.doOnDataChange(this.tableData);
|
|
||||||
}
|
|
||||||
this.updateScrollInfo();
|
|
||||||
if (this.fixedColumnCount > 0) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
const style = this.$refs.fixed.style;
|
|
||||||
if (!style) return;
|
|
||||||
// style.height = this.$el.clientHeight + 'px';
|
|
||||||
// 存在横向滚动条的时候应该要减去滚动条的高度
|
|
||||||
style.height = (this.showHScrollBar ? this.$el.clientHeight - this.currentGutterWidth : this.$el.clientHeight) + 'px';
|
|
||||||
// 若非固定列中的某行内容被撑高, 需要固定列中对应行高度与其保持一致
|
|
||||||
let bodyHeight = this.$el.querySelector('.el-table__body-wrapper').offsetHeight;
|
|
||||||
let fixedBodyHeight = this.$el.querySelector('.el-table__fixed-body-wrapper').offsetHeight;
|
|
||||||
if (bodyHeight !== fixedBodyHeight) {
|
|
||||||
let bodyTrs = this.$el.querySelector('.el-table__body-wrapper').querySelectorAll('tr');
|
|
||||||
let fixedBodyTrs = this.$el.querySelector('.el-table__fixed-body-wrapper').querySelectorAll('tr');
|
|
||||||
bodyTrs.forEach((tr, index) => {
|
|
||||||
let trHeight = tr.offsetHeight;
|
|
||||||
let fixedTrHeight = fixedBodyTrs[index].offsetHeight;
|
|
||||||
if (trHeight !== fixedTrHeight) {
|
|
||||||
fixedBodyTrs[index].style.height = trHeight + 'px';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
const store = new TableStore(this, {
|
||||||
|
allowNoSelection: this.allowNoSelection,
|
||||||
|
selectionMode: this.selectionMode
|
||||||
|
});
|
||||||
|
const layout = new TableLayout({
|
||||||
|
store,
|
||||||
|
table: this,
|
||||||
|
fit: this.fit
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
tableData: this.data,
|
store,
|
||||||
showHScrollBar: false,
|
layout,
|
||||||
showVScrollBar: false,
|
resizeProxyVisible: false
|
||||||
hoverRowIndex: null,
|
|
||||||
headerHeight: 35,
|
|
||||||
selected: null,
|
|
||||||
allSelected: false,
|
|
||||||
columns: [],
|
|
||||||
resizeProxyVisible: false,
|
|
||||||
bodyWidth: '',
|
|
||||||
fixedBodyWidth: '',
|
|
||||||
sortingColumn: null,
|
|
||||||
sortingProperty: null,
|
|
||||||
sortingDirection: 1,
|
|
||||||
visibleFilter: null,
|
|
||||||
currentGutterWidth: this.gutterWidth
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
var scrollBarWidth;
|
let scrollBarWidth;
|
||||||
|
|
||||||
export const getScrollBarWidth = () => {
|
export const getScrollBarWidth = () => {
|
||||||
if (scrollBarWidth !== undefined) return scrollBarWidth;
|
if (scrollBarWidth !== undefined) return scrollBarWidth;
|
||||||
|
@ -75,7 +75,3 @@ export const orderBy = function(array, sortKey, reverse) {
|
||||||
return a === b ? 0 : a > b ? order : -order;
|
return a === b ? 0 : a > b ? order : -order;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getChild = function(event) {
|
|
||||||
return event.target.querySelector('.cell');
|
|
||||||
};
|
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
@e fixed {
|
@e fixed, fixed-right {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -123,6 +123,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@e fixed-right {
|
||||||
|
top: 0;
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
box-shadow: -1px 0 8px #d3d4d6;
|
||||||
|
}
|
||||||
|
|
||||||
@e fixed-header-wrapper {
|
@e fixed-header-wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
Loading…
Reference in New Issue