Commit f6bab114 authored by hetech's avatar hetech Committed by luckyCao

Table: add new features for Table and optimize code (#15709)

parent 99d613fc
......@@ -1332,7 +1332,7 @@ When the row content is too long and you do not want to display the horizontal s
### Tree data and lazy mode
:::demo You can display tree structure data. When using it, the prop `row-key` is required. Also, child row data can be loaded asynchronously. Set `lazy` property of Table to true and the function `load`. Specify `hasChildren` attribute in row to determine which row contains children.
:::demo You can display tree structure data. When row contains the `children` field, it is treated as nested data. For rendering nested data, the prop `row-key` is required。Also, child row data can be loaded asynchronously. Set `lazy` property of Table to true and the function `load`. Specify `hasChildren` attribute in row to determine which row contains children. Both `children` and `hasChildren` can be configured via `tree-props`.
```html
<template>
......@@ -1340,11 +1340,12 @@ When the row content is too long and you do not want to display the horizontal s
<el-table
:data="tableData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
row-key="id">
default-expand-all>
<el-table-column
prop="date"
label="Date"
label="date"
sortable
width="180">
</el-table-column>
......@@ -1363,7 +1364,7 @@ When the row content is too long and you do not want to display the horizontal s
border
lazy
:load="load"
>
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column
prop="date"
label="Date"
......@@ -1429,17 +1430,19 @@ When the row content is too long and you do not want to display the horizontal s
},
methods: {
load(tree, treeNode, resolve) {
resolve([
{
id: 31,
date: '2016-05-01',
name: 'wangxiaohu'
}, {
id: 32,
date: '2016-05-01',
name: 'wangxiaohu'
}
])
setTimeout(() => {
resolve([
{
id: 31,
date: '2016-05-01',
name: 'wangxiaohu'
}, {
id: 32,
date: '2016-05-01',
name: 'wangxiaohu'
}
])
}, 1000)
}
},
}
......@@ -1825,7 +1828,7 @@ You can customize row index in `type=index` columns.
| header-cell-style | function that returns custom style for a cell in table header, or an object assigning custom style for every cell in table header | Function({row, column, rowIndex, columnIndex})/Object | — | — |
| row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on or display tree data. When its type is String, multi-level access is supported, e.g. `user.info.id`, but `user.info[0].id` is not supported, in which case `Function` should be used. | Function(row)/String | — | — |
| empty-text | Displayed text when data is empty. You can customize this area with `slot="empty"` | String | — | No Data |
| default-expand-all | whether expand all rows by default, only works when the table has a column type="expand" | Boolean | — | false |
| default-expand-all | whether expand all rows by default, works when the table has a column type="expand" or contains tree structure data | Boolean | — | false |
| expand-row-keys | set expanded rows by this prop, prop's value is the keys of expand rows, you should set row-key before using this prop | Array | — | |
| default-sort | set the default sort column and order. property `prop` is used to set default sort column, property `order` is used to set default sort order | Object | `order`: ascending, descending | if `prop` is set, and `order` is not set, then `order` is default to ascending |
| tooltip-effect | tooltip `effect` property | String | dark/light | | dark |
......@@ -1836,7 +1839,8 @@ You can customize row index in `type=index` columns.
| select-on-indeterminate | controls the behavior of master checkbox in multi-select tables when only some rows are selected (but not all). If true, all rows will be selected, else deselected. | Boolean | — | true |
| indent | horizontal indentation of tree data | Number | — | 16 |
| lazy | whether to lazy loading data | Boolean| — | — |
| load | method for loading child row data, only works when `lazy` is true | Function({ row, treeNode, resolve }) | — | — |
| load | method for loading child row data, only works when `lazy` is true | Function(row, treeNode, resolve) | — | — |
| tree-props | configuration for rendering nested data| Object | — | { hasChildren: 'hasChildren', children: 'children' } |
### Table Events
| Event Name | Description | Parameters |
......@@ -1857,7 +1861,7 @@ You can customize row index in `type=index` columns.
| filter-change | column's key. If you need to use the filter-change event, this attribute is mandatory to identify which column is being filtered | filters |
| current-change | triggers when current row changes | currentRow, oldCurrentRow |
| header-dragend | triggers after changing a column's width by dragging the column header's border | newWidth, oldWidth, column, event |
| expand-change | triggers when user expands or collapses a row | row, expandedRows |
| expand-change | triggers when user expands or collapses a row (for expandable table, second param is expandedRows; for tree Table, second param is expanded) | row, (expandedRows \| expanded) |
### Table Methods
| Method | Description | Parameters |
......@@ -1865,7 +1869,7 @@ You can customize row index in `type=index` columns.
| clearSelection | used in multiple selection Table, clear user selection | — |
| toggleRowSelection | used in multiple selection Table, toggle if a certain row is selected. With the second parameter, you can directly set if this row is selected | row, selected |
| toggleAllSelection | used in multiple selection Table, toggle the selected state of all rows | - |
| toggleRowExpansion | used in expandable Table, toggle if a certain row is expanded. With the second parameter, you can directly set if this row is expanded or collapsed | row, expanded |
| toggleRowExpansion | used in expandable Table or tree Table, toggle if a certain row is expanded. With the second parameter, you can directly set if this row is expanded or collapsed | row, expanded |
| setCurrentRow | used in single selection Table, set a certain row selected. If called without any parameter, it will clear selection. | row |
| clearSort | clear sorting, restore data to the original order | — |
| clearFilter | clear filters of the columns whose `columnKey` are passed in. If no params, clear all filters | columnKeys |
......
......@@ -1334,7 +1334,7 @@ Cuando el contenido de la fila es demasiado largo y busca no mostrar la barra de
### Datos tree y modo lazy
:::demo Puede mostrar la estructura de datos tipo tree。Cuando se usa, la prop`row-key` es requerida。Entonces, los datos de las filas de los hijos pueden ser cargados asincrónicamente. Poner la propiedad `lazy` de Table a true y la función `load`. Especifique el atributo `hasChildren` en la fila para determinar qué fila contiene hijos.
:::demo You can display tree structure data. When row contains the `children` field, it is treated as nested data. For rendering nested data, the prop `row-key` is required。Also, child row data can be loaded asynchronously. Set `lazy` property of Table to true and the function `load`. Specify `hasChildren` attribute in row to determine which row contains children. Both `children` and `hasChildren` can be configured via `tree-props`.
```html
<template>
......@@ -1342,8 +1342,9 @@ Cuando el contenido de la fila es demasiado largo y busca no mostrar la barra de
<el-table
:data="tableData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
row-key="id">
default-expand-all>
<el-table-column
prop="date"
label="日期"
......@@ -1365,7 +1366,7 @@ Cuando el contenido de la fila es demasiado largo y busca no mostrar la barra de
border
lazy
:load="load"
>
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column
prop="date"
label="date"
......@@ -1431,17 +1432,19 @@ Cuando el contenido de la fila es demasiado largo y busca no mostrar la barra de
},
methods: {
load(tree, treeNode, resolve) {
resolve([
{
id: 31,
date: '2016-05-01',
name: 'wangxiaohu'
}, {
id: 32,
date: '2016-05-01',
name: 'wangxiaohu'
}
])
setTimeout(() => {
resolve([
{
id: 31,
date: '2016-05-01',
name: 'wangxiaohu'
}, {
id: 32,
date: '2016-05-01',
name: 'wangxiaohu'
}
])
}, 1000)
}
},
}
......@@ -1841,7 +1844,8 @@ Puede personalizar el índice de la fila con la propiedad `type=index` de las co
| select-on-indeterminate | controla el comportamiento del checkbox maestro en tablas de selección múltiple cuando sólo se seleccionan algunas filas (pero no todas). Si es true, todas las filas serán seleccionadas, de lo contrario deseleccionadas. | Boolean | — | true |
| indent | indentación horizontal de los datos en formato tree | Number | — | 16 |
| lazy | si se realiza un lazy loading de los datos | Boolean | — | — |
| load | metodo para cargar las filas de los hijos, solamente funciona cuando `lazy`es true | Function({ row, treeNode, resolve }) | — | — |
| load | metodo para cargar las filas de los hijos, solamente funciona cuando `lazy`es true | Function(row, treeNode, resolve) | — | — |
| tree-props | configuration for rendering nested data | Object | — | { hasChildren: 'hasChildren', children: 'children' } |
### Eventos de la tabla
| Nombre del evento | Descripción | Parámetros |
......@@ -1862,7 +1866,7 @@ Puede personalizar el índice de la fila con la propiedad `type=index` de las co
| filter-change | clave de la columna. Si necesitas utilizar el evento filter-change, este atributo es obligatorio para identificar cuál columna está siendo filtrada | filters |
| current-change | se dispara cuando la fila actual cambia | currentRow, oldCurrentRow |
| header-dragend | se dispara después de modificar el ancho de una columna arrastrando el borde de la cabecera. | newWidth, oldWidth, column, event |
| expand-change | se dispara cuando el usuario expande o colapsa una fila | row, expandedRows |
| expand-change | triggers when user expands or collapses a row (for expandable table, second param is expandedRows; for tree Table, second param is expanded) | row, (expandedRows \| expanded) |
### Métodos de la tabla
| Metodo | Descripción | Parametros |
......@@ -1870,7 +1874,7 @@ Puede personalizar el índice de la fila con la propiedad `type=index` de las co
| clearSelection | utilizado en selección múltiple de la tabla, limpiar selección | — |
| toggleRowSelection | utilizado en selección múltiple de la tabla, alterna si una cierta fila es seleccionada. Con el segundo parámetro, puede directamente establecer si la fila es seleccionada | row, selected |
| toggleAllSelection | usado en Table de seleccion multiple, cambia los estados de seleccion de todas las filas. | - |
| toggleRowExpansion | utilizado en tabla expandible, alterna si una cierta fila es expandida. Con el segundo parámetro, puede directamente establecer si esta fila es expandida o colapsada | row, expanded |
| toggleRowExpansion | used in expandable Table or tree Table, toggle if a certain row is expanded. With the second parameter, you can directly set if this row is expanded or collapsed | row, expanded |
| setCurrentRow | utilizado en tabla con selección sencilla, establece una cierta fila seleccionada. Si es llamado sin ningún parámetro, este puede limpiar la selección | row |
| clearSort | limpiar ordenamiento, restaurar datos a orden original | — |
| clearFilter | Se utiliza para borrar todas las condiciones de filtro cuando no se pasan parámetros, los datos se restaurarán a un estado sin filtrar, o se puede pasar una matriz de columnas para borrar las condiciones de filtro de la columna especificada. | columnKey |
......
......@@ -1335,7 +1335,7 @@ Lorsque le contenu d'une ligne est trop long et que vous ne souhaitez pas affich
### Arborescence et lazy loading
:::demo Vous pouvez afficher les données en arborescence, la propriété `row-key` devenant dans ce cas obligatoire. Les données enfants peuvent aussi être chargées de manière asynchrone. Mettez la propriété `lazy` à `true` and utilisez la fonction `load`. Spécifiez l'attribut `hasChildren` pour déterminer quelle ligne contient les enfants.
:::demo You can display tree structure data. When row contains the `children` field, it is treated as nested data. For rendering nested data, the prop `row-key` is required。Also, child row data can be loaded asynchronously. Set `lazy` property of Table to true and the function `load`. Specify `hasChildren` attribute in row to determine which row contains children. Both `children` and `hasChildren` can be configured via `tree-props`.
```html
<template>
......@@ -1343,11 +1343,12 @@ Lorsque le contenu d'une ligne est trop long et que vous ne souhaitez pas affich
<el-table
:data="tableData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
row-key="id">
default-expand-all>
<el-table-column
prop="date"
label="Date"
label="date"
sortable
width="180">
</el-table-column>
......@@ -1366,7 +1367,7 @@ Lorsque le contenu d'une ligne est trop long et que vous ne souhaitez pas affich
border
lazy
:load="load"
>
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column
prop="date"
label="Date"
......@@ -1432,17 +1433,19 @@ Lorsque le contenu d'une ligne est trop long et que vous ne souhaitez pas affich
},
methods: {
load(tree, treeNode, resolve) {
resolve([
{
id: 31,
date: '2016-05-01',
name: 'wangxiaohu'
}, {
id: 32,
date: '2016-05-01',
name: 'wangxiaohu'
}
])
setTimeout(() => {
resolve([
{
id: 31,
date: '2016-05-01',
name: 'wangxiaohu'
}, {
id: 32,
date: '2016-05-01',
name: 'wangxiaohu'
}
])
}, 1000)
}
},
}
......@@ -1832,7 +1835,7 @@ Vous pouvez personnaliser les indices des colonnes de type `index`.
| header-cell-style | Fonction qui retourne un style pour chaque cellule de header. Peut aussi être un objet assignant un style à chaque cellule de header. | Function({row, column, rowIndex, columnIndex})/Object | — | — |
| row-key | Clé de chaque ligne, utilisée pour optimiser le rendu. Requise si `reserve-selection` est activé. Quand c'est un `String`, l'accès multi-niveaux est supporté, e.g. `user.info.id`, mais `user.info[0].id` n'est pas supporté. Dans ce dernier cas une `Function` devrait être utilisée. | Function(row)/String | — | — |
| empty-text | Texte à afficher quand il n'y a pas de données. Vous pouvez changer cette zone grâce à `slot="empty"`. | String | — | No Data |
| default-expand-all | Si toutes les lignes sont étendues par défaut, ne marche que si des lignes ont type="expand". | Boolean | — | false |
| default-expand-all | whether expand all rows by default, works when the table has a column type="expand" or contains tree structure data | Boolean | — | false |
| expand-row-keys | Détermine les lignes qui sont étendues, contient les clés des lignes correspondantes. Vous devriez configurer `row-key` avant celle-ci. | Array | — | |
| default-sort | Détermine l'ordre de tri par défaut. La propriété `prop` détermine la colonne par défaut, `order` détermine l'ordre par défaut. | Object | `order`: ascending, descending | Si `order` est absent, son défaut sera `ascending`. |
| tooltip-effect | Propriété `effect` de Tooltip. | String | dark/light | | dark |
......@@ -1841,9 +1844,10 @@ Vous pouvez personnaliser les indices des colonnes de type `index`.
| summary-method | La méthode pour calculer la somme. | Function({ columns, data }) | — | — |
| span-method | Méthode qui retourne les valeurs de colspan et rowspan. | Function({ row, column, rowIndex, columnIndex }) | — | — |
| select-on-indeterminate | Contrôle le comportement de la checkbox globale dans les tables avec sélection multiple lorsque seulement certaines lignes sont sélectionnées. Si `true`, toutes les lignes sont sélectionnées. | Boolean | — | true |
| indent | Indentation horizontale de l'arborescence. | Number | — | 16 |
| lazy | Si le lazy loading doit être utilisé. | Boolean | — | — |
| load | Méthode a utiliser pour le lazy loading, ne fonctionne que lorsque `lazy` est `true`. | Function({ row, treeNode, resolve }) | — | — |
| indent | horizontal indentation of tree data | Number | — | 16 |
| lazy | whether to lazy loading data | Boolean | — | — |
| load | method for loading child row data, only works when `lazy` is true | Function({ row, treeNode, resolve }) | — | — |
| tree-props | configuration for rendering nested data | Object | — | { hasChildren: 'hasChildren', children: 'children' } |
### Évènements de Table
......@@ -1865,7 +1869,7 @@ Vous pouvez personnaliser les indices des colonnes de type `index`.
| filter-change | column's key. If you need to use the filter-change event, this attribute is mandatory to identify which column is being filtered. | filters |
| current-change | Se déclenche quand la ligne sélectionnée change. | currentRow, oldCurrentRow |
| header-dragend | Se déclenche après un changement de taille de colonne en déplaçant la ligne verticale du header. | newWidth, oldWidth, column, event |
| expand-change | Se déclenche quand l'utilisateur étend ou réduit une ligne. | row, expandedRows |
| expand-change | triggers when user expands or collapses a row (for expandable table, second param is expandedRows; for tree Table, second param is expanded) | row, (expandedRows \| expanded) |
### Méthodes de Table
......@@ -1874,7 +1878,7 @@ Vous pouvez personnaliser les indices des colonnes de type `index`.
| clearSelection | Dans les tables avec sélection multiple, efface la sélection. | — |
| toggleRowSelection | Dans les tables avec sélection multiple, change la sélection d'une ligne. Grâce au deuxième paramètre vous pouvez directement décider si cette ligne est sélectionnée. | row, selected |
| toggleAllSelection | Utilisé dans les tables à sélection multiples, sélectionne toutes les lignes. | - |
| toggleRowExpansion | Pour les lignes extensibles, change l'état de la ligne. Grâce au deuxième paramètre vous pouvez directement décider si cette ligne est étendue. | row, expanded |
| toggleRowExpansion | used in expandable Table or tree Table, toggle if a certain row is expanded. With the second parameter, you can directly set if this row is expanded or collapsed | row, expanded |
| setCurrentRow | Dans les tables à sélection simple, sélectionne une ligne. Sans paramètre la sélection est effacé. | row |
| clearSort | Efface le tri. | — |
| clearFilter | Efface les filtres des colonnes dont les `columnKey` sont passées. Si aucun paramètre, efface tout les filtres. | columnKeys |
......
......@@ -1277,7 +1277,7 @@
### 树形数据与懒加载
:::demo 支持树类型的数据。此时,必须要指定 `row-key`。支持子节点数据异步加载。设置 Table 的 `lazy` 属性为 true 与 加载函数 `load` ,指定 row 中的 `hasChildren` 来确定哪些行是包含子节点
:::demo 支持树类型的数据的显示。当 row 中包含 `children` 字段时,被视为树形数据。渲染树形数据时,必须要指定 `row-key`。支持子节点数据异步加载。设置 Table 的 `lazy` 属性为 true 与加载函数 `load` 。通过指定 row 中的 `hasChildren` 字段来指定哪些行是包含子节点。`children``hasChildren` 都可以通过 `tree-props` 配置
```html
<template>
......@@ -1285,8 +1285,10 @@
<el-table
:data="tableData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
row-key="id">
default-expand-all
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column
prop="date"
label="日期"
......@@ -1312,7 +1314,7 @@
border
lazy
:load="load"
>
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column
prop="date"
label="日期"
......@@ -1392,19 +1394,21 @@
},
methods: {
load(tree, treeNode, resolve) {
resolve([
{
id: 31,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
id: 32,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}
])
setTimeout(() => {
resolve([
{
id: 31,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
id: 32,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}
])
}, 1000)
}
},
}
......@@ -1867,7 +1871,7 @@
| header-cell-style | 表头单元格的 style 的回调方法,也可以使用一个固定的 Object 为所有表头单元格设置一样的 Style。 | Function({row, column, rowIndex, columnIndex})/Object | — | — |
| row-key | 行数据的 Key,用来优化 Table 的渲染;在使用 reserve-selection 功能与显示树形数据时,该属性是必填的。类型为 String 时,支持多层访问:`user.info.id`,但不支持 `user.info[0].id`,此种情况请使用 `Function`。 | Function(row)/String | — | — |
| empty-text | 空数据时显示的文本内容,也可以通过 `slot="empty"` 设置 | String | — | 暂无数据 |
| default-expand-all | 是否默认展开所有行,当 Table 中存在 type="expand" 的 Column 的时候有效 | Boolean | — | false |
| default-expand-all | 是否默认展开所有行,当 Tale 包含展开行存在或者为树形表格时有效 | Boolean | — | false |
| expand-row-keys | 可以通过该属性设置 Table 目前的展开行,需要设置 row-key 属性才能使用,该属性为展开行的 keys 数组。| Array | — | |
| default-sort | 默认的排序列的 prop 和顺序。它的`prop`属性指定默认的排序的列,`order`指定默认排序的顺序| Object | `order`: ascending, descending | 如果只指定了`prop`, 没有指定`order`, 则默认顺序是ascending |
| tooltip-effect | tooltip `effect` 属性 | String | dark/light | | dark |
......@@ -1878,7 +1882,8 @@
| select-on-indeterminate | 在多选表格中,当仅有部分行被选中时,点击表头的多选框时的行为。若为 true,则选中所有行;若为 false,则取消选择所有行 | Boolean | — | true |
| indent | 展示树形数据时,树节点的缩进 | Number | — | 16 |
| lazy | 是否懒加载子节点数据 | Boolean | — | — |
| load | 加载子节点数据的函数,lazy 为 true 时生效 | Function({ row, treeNode, resolve }) | — | — |
| load | 加载子节点数据的函数,lazy 为 true 时生效,函数第二个参数包含了节点的层级信息 | Function(row, treeNode, resolve) | — | — |
| tree-props | 渲染嵌套数据的配置选项 | Object | — | { hasChildren: 'hasChildren', children: 'children' } |
### Table Events
| 事件名 | 说明 | 参数 |
......@@ -1899,7 +1904,7 @@
| filter-change | 当表格的筛选条件发生变化的时候会触发该事件,参数的值是一个对象,对象的 key 是 column 的 columnKey,对应的 value 为用户选择的筛选条件的数组。 | filters |
| current-change | 当表格的当前行发生变化的时候会触发该事件,如果要高亮当前行,请打开表格的 highlight-current-row 属性 | currentRow, oldCurrentRow |
| header-dragend | 当拖动表头改变了列的宽度的时候会触发该事件 | newWidth, oldWidth, column, event |
| expand-change | 当用户对某一行展开或者关闭的时候会触发该事件 | row, expandedRows |
| expand-change | 当用户对某一行展开或者关闭的时候会触发该事件(展开行时,回调的第二个参数为 expandedRows;树形表格时第二参数为 expanded) | row, (expandedRows \| expanded) |
### Table Methods
| 方法名 | 说明 | 参数 |
......@@ -1907,7 +1912,7 @@
| clearSelection | 用于多选表格,清空用户的选择 | — |
| toggleRowSelection | 用于多选表格,切换某一行的选中状态,如果使用了第二个参数,则是设置这一行选中与否(selected 为 true 则选中) | row, selected |
| toggleAllSelection | 用于多选表格,切换所有行的选中状态 | - |
| toggleRowExpansion | 用于可展开表格,切换某一行的展开状态,如果使用了第二个参数,则是设置这一行展开与否(expanded 为 true 则展开) | row, expanded |
| toggleRowExpansion | 用于可展开表格与树形表格,切换某一行的展开状态,如果使用了第二个参数,则是设置这一行展开与否(expanded 为 true 则展开) | row, expanded |
| setCurrentRow | 用于单选表格,设定某一行为选中行,如果调用时不加参数,则会取消目前高亮行的选中状态。 | row |
| clearSort | 用于清空排序条件,数据会恢复成未排序的状态 | — |
| clearFilter | 不传入参数时用于清空所有过滤条件,数据会恢复成未过滤的状态,也可传入由columnKey组成的数组以清除指定列的过滤条件 | columnKey |
......
import { getPropByPath } from 'element-ui/src/utils/util';
export const cellStarts = {
default: {
order: ''
},
selection: {
width: 48,
minWidth: 48,
realWidth: 48,
order: '',
className: 'el-table-column--selection'
},
expand: {
width: 48,
minWidth: 48,
realWidth: 48,
order: ''
},
index: {
width: 48,
minWidth: 48,
realWidth: 48,
order: ''
}
};
// 这些选项不应该被覆盖
export const cellForced = {
selection: {
renderHeader: function(h, { store }) {
return <el-checkbox
disabled={ store.states.data && store.states.data.length === 0 }
indeterminate={ store.states.selection.length > 0 && !this.isAllSelected }
nativeOn-click={ this.toggleAllSelection }
value={ this.isAllSelected } />;
},
renderCell: function(h, { row, column, store, $index }) {
return <el-checkbox
nativeOn-click={ (event) => event.stopPropagation() }
value={ store.isSelected(row) }
disabled={ column.selectable ? !column.selectable.call(null, row, $index) : false }
on-input={ () => { store.commit('rowSelectedChanged', row); } } />;
},
sortable: false,
resizable: false
},
index: {
renderHeader: function(h, { column }) {
return column.label || '#';
},
renderCell: function(h, { $index, column }) {
let i = $index + 1;
const index = column.index;
if (typeof index === 'number') {
i = $index + index;
} else if (typeof index === 'function') {
i = index($index);
}
return <div>{ i }</div>;
},
sortable: false
},
expand: {
renderHeader: function(h, { column }) {
return column.label || '';
},
renderCell: function(h, { row, store }) {
const classes = ['el-table__expand-icon'];
if (store.states.expandRows.indexOf(row) > -1) {
classes.push('el-table__expand-icon--expanded');
}
const callback = function(e) {
e.stopPropagation();
store.toggleRowExpansion(row);
};
return (<div class={ classes }
on-click={callback}>
<i class='el-icon el-icon-arrow-right'></i>
</div>);
},
sortable: false,
resizable: false,
className: 'el-table__expand-column'
}
};
export function defaultRenderCell(h, { row, column, $index }) {
const property = column.property;
const value = property && getPropByPath(row, property).v;
if (column && column.formatter) {
return column.formatter(row, column, value, $index);
}
return value;
}
export function treeCellPrefix(h, { row, treeNode, store }) {
if (!treeNode) return null;
const ele = [];
const callback = function(e) {
e.stopPropagation();
store.loadOrToggle(row);
};
if (treeNode.indent) {
ele.push(<span class="el-table__indent" style={{'padding-left': treeNode.indent + 'px'}}></span>);
}
if (typeof treeNode.expanded === 'boolean' && !treeNode.noLazyChildren) {
const expandClasses = ['el-table__expand-icon', treeNode.expanded ? 'el-table__expand-icon--expanded' : ''];
let iconClasses = ['el-icon-arrow-right'];
if (treeNode.loading) {
iconClasses = ['el-icon-loading'];
}
ele.push(<div class={ expandClasses }
on-click={ callback }>
<i class={ iconClasses }></i>
</div>);
} else {
ele.push(<span class="el-table__placeholder"></span>);
}
return ele;
}
......@@ -72,17 +72,6 @@
}
},
customRender(h) {
return (<div class="el-table-filter">
<div class="el-table-filter__content">
</div>
<div class="el-table-filter__bottom">
<button on-click={ this.handleConfirm }>{ this.t('el.table.confirmFilter') }</button>
<button on-click={ this.handleReset }>{ this.t('el.table.resetFilter') }</button>
</div>
</div>);
},
methods: {
isActive(filter) {
return filter.value === this.filterValue;
......
import { arrayFind } from 'element-ui/src/utils/util';
import { getRowIdentity } from '../util';
export default {
data() {
return {
states: {
current: null
}
};
},
methods: {
setCurrentRowKey(key) {
this.assertRowKey();
const { states } = this;
const { data = [], rowKey } = states;
const currentRow = arrayFind(data, item => getRowIdentity(item, rowKey) === key);
states.currentRow = currentRow ? currentRow : null;
},
updateCurrentRow() {
const { states, table } = this;
const { rowKey } = states;
// data 为 null 时,结构时的默认值会被忽略
const data = states.data || [];
const oldCurrentRow = states.currentRow;
// 当 currentRow 不在 data 中时尝试更新数据
if (data.indexOf(oldCurrentRow) === -1 && oldCurrentRow) {
let newCurrentRow = null;
if (rowKey) {
newCurrentRow = arrayFind(data, item => {
return getRowIdentity(item, rowKey) === getRowIdentity(oldCurrentRow, rowKey);
});
}
states.currentRow = newCurrentRow;
if (newCurrentRow !== oldCurrentRow) {
table.$emit('current-change', null, oldCurrentRow);
}
}
}
}
};
import { toggleRowStatus, getKeysMap, getRowIdentity } from '../util';
export default {
data() {
return {
states: {
defaultExpandAll: false,
expandRows: []
}
};
},
methods: {
updateExpandRows() {
const { data = [], rowKey, defaultExpandAll, expandRows } = this.states;
if (defaultExpandAll) {
this.states.expandRows = data.slice();
} else if (rowKey) {
// TODO:这里的代码可以优化
const expandRowsMap = getKeysMap(expandRows, rowKey);
this.states.expandRows = data.reduce((prev, row) => {
const rowId = getRowIdentity(row, rowKey);
const rowInfo = expandRowsMap[rowId];
if (rowInfo) {
prev.push(row);
}
return prev;
}, []);
} else {
this.states.expandRows = [];
}
},
toggleRowExpansion(row, expanded) {
const changed = toggleRowStatus(this.states.expandRows, row, expanded);
if (changed) {
this.table.$emit('expand-change', row, this.states.expandRows.slice());
this.scheduleLayout();
}
},
setExpandRowKeys(rowKeys) {
this.assertRowKey();
// TODO:这里的代码可以优化
const { data, rowKey } = this.states;
const keysMap = getKeysMap(data, rowKey);
this.states.expandRows = rowKeys.reduce((prev, cur) => {
const info = keysMap[cur];
if (info) {
prev.push(info.row);
}
return prev;
}, []);
},
isRowExpanded(row) {
const { expandRows = [], rowKey } = this.states;
if (rowKey) {
const expandMap = getKeysMap(expandRows, rowKey);
return !!expandMap[getRowIdentity(row, rowKey)];
}
return expandRows.indexOf(row) !== -1;
}
}
};
import Store from './index';
export function createStore(table, initialState = {}) {
if (!table) {
throw new Error('Table is required.');
}
const store = new Store();
store.table = table;
Object.keys(initialState).forEach(key => {
store.states[key] = initialState[key];
});
return store;
}
export function mapStates(mapper) {
const res = {};
Object.keys(mapper).forEach(key => {
const value = mapper[key];
let fn;
if (typeof value === 'string') {
fn = function() {
return this.store.states[value];
};
} else if (typeof value === 'function') {
fn = function() {
return value.call(this, this.store.states);
};
} else {
console.error('invalid value type');
}
if (fn) {
res[key] = fn;
}
});
return res;
};
import Vue from 'vue';
import Watcher from './watcher';
import { arrayFind } from 'element-ui/src/utils/util';
Watcher.prototype.mutations = {
setData(states, data) {
const dataInstanceChanged = states._data !== data;
states._data = data;
this.execQuery();
// 数据变化,更新部分数据。
// 没有使用 computed,而是手动更新部分数据 https://github.com/vuejs/vue/issues/6660#issuecomment-331417140
this.updateCurrentRow();
this.updateExpandRows();
if (!states.reserveSelection) {
if (dataInstanceChanged) {
this.clearSelection();
} else {
this.cleanSelection();
}
} else {
this.assertRowKey();
this.updateSelectionByRowKey();
}
this.updateAllSelected();
this.updateTableScrollY();
},
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;
}
if (this.table.$ready) {
this.updateColumns(); // hack for dynamics insert column
this.scheduleLayout();
}
},
removeColumn(states, column, parent) {
let array = states._columns;
if (parent) {
array = parent.children;
if (!array) array = parent.children = [];
}
if (array) {
array.splice(array.indexOf(column), 1);
}
if (this.table.$ready) {
this.updateColumns(); // hack for dynamics remove column
this.scheduleLayout();
}
},
sort(states, options) {
const { prop, order } = options;
if (prop) {
// TODO:nextTick 是否有必要?
Vue.nextTick(() => {
const column = arrayFind(states.columns, column => column.property === prop);
if (column) {
column.order = order;
this.updateSort(column, prop, order);
this.commit('changeSortCondition');
}
});
}
},
changeSortCondition(states, options) {
// 修复 pr https://github.com/ElemeFE/element/pull/15012 导致的 bug
const { sortingColumn: column, sortProp: prop, sortOrder: order } = states;
if (order === null) {
states.sortingColumn = null;
states.sortProp = null;
}
const ingore = { filter: true };
this.execQuery(ingore);
if (!options || !options.silent) {
this.table.$emit('sort-change', {
column,
prop,
order
});
}
this.updateTableScrollY();
},
filterChange(states, options) {
let { column, values, silent } = options;
const newFilters = this.updateFilters(column, values);
this.execQuery();
if (!silent) {
this.table.$emit('filter-change', newFilters);
}
this.updateTableScrollY();
},
toggleAllSelection() {
this.toggleAllSelection();
},
rowSelectedChanged(states, row) {
this.toggleRowSelection(row);
this.updateAllSelected();
},
setHoverRow(states, row) {
states.hoverRow = row;
},
setCurrentRow(states, row) {
const oldCurrentRow = states.currentRow;
states.currentRow = row;
if (oldCurrentRow !== row) {
this.table.$emit('current-change', row, oldCurrentRow);
}
}
};
Watcher.prototype.commit = function(name, ...args) {
const mutations = this.mutations;
if (mutations[name]) {
mutations[name].apply(this, [this.states].concat(args));
} else {
throw new Error(`Action not found: ${name}`);
}
};
Watcher.prototype.updateTableScrollY = function() {
Vue.nextTick(this.table.updateScrollY);
};
export default Watcher;
import { walkTreeNode, getRowIdentity } from '../util';
export default {
data() {
return {
states: {
// defaultExpandAll 存在于 expand.js 中,这里不重复添加
// TODO: 拆分为独立的 TreeTale,在 expand 中,展开行的记录是放在 expandRows 中,统一用法
expandRowKeys: [],
treeData: {},
indent: 16,
lazy: false,
lazyTreeNodeMap: {},
lazyColumnIdentifier: 'hasChildren',
childrenColumnName: 'children'
}
};
},
computed: {
// 嵌入型的数据,watch 无法是检测到变化 https://github.com/ElemeFE/element/issues/14998
// TODO: 使用 computed 解决该问题,是否会造成性能问题?
// @return { id: { level, children } }
normalizedData() {
if (!this.states.rowKey) return {};
const data = this.states.data || [];
return this.normalize(data);
},
// @return { id: { children } }
// 针对懒加载的情形,不处理嵌套数据
normalizedLazyNode() {
const { rowKey, lazyTreeNodeMap, lazyColumnIdentifier } = this.states;
const keys = Object.keys(lazyTreeNodeMap);
const res = {};
if (!keys.length) return res;
keys.forEach(key => {
if (lazyTreeNodeMap[key].length) {
const item = { children: [] };
lazyTreeNodeMap[key].forEach(row => {
const currentRowKey = getRowIdentity(row, rowKey);
item.children.push(currentRowKey);
if (row[lazyColumnIdentifier] && !res[currentRowKey]) {
res[currentRowKey] = { children: [] };
}
});
res[key] = item;
}
});
return res;
}
},
watch: {
normalizedData: 'updateTreeData',
// expandRowKeys 在 TreeTable 中也有使用
expandRowKeys: 'updateTreeData',
normalizedLazyNode: 'updateTreeData'
},
methods: {
normalize(data) {
const { childrenColumnName, lazyColumnIdentifier, rowKey, lazy } = this.states;
const res = {};
walkTreeNode(data, (parent, children, level) => {
const parentId = getRowIdentity(parent, rowKey);
if (Array.isArray(children)) {
res[parentId] = {
children: children.map(row => getRowIdentity(row, rowKey)),
level
};
} else if (lazy) {
// 当 children 不存在且 lazy 为 true,该节点即为懒加载的节点
res[parentId] = {
children: [],
lazy: true,
level
};
}
}, childrenColumnName, lazyColumnIdentifier);
return res;
},
updateTreeData() {
const nested = this.normalizedData;
const normalizedLazyNode = this.normalizedLazyNode;
const keys = Object.keys(nested);
if (!keys.length) return;
const { treeData: oldTreeData, defaultExpandAll, expandRowKeys, lazy } = this.states;
const newTreeData = {};
const rootLazyRowKeys = [];
const getExpanded = (oldValue, key) => {
const included = defaultExpandAll || (expandRowKeys && expandRowKeys.indexOf(key) !== -1);
return !!((oldValue && oldValue.expanded) || included);
};
// 合并 expanded 与 display,确保数据刷新后,状态不变
keys.forEach(key => {
const oldValue = oldTreeData[key];
const newValue = { ...nested[key] };
newValue.expanded = getExpanded(oldValue, key);
if (newValue.lazy) {
const { loaded = false, loading = false } = oldValue || {};
newValue.loaded = !!loaded;
newValue.loading = !!loading;
rootLazyRowKeys.push(key);
}
newTreeData[key] = newValue;
});
// 根据懒加载数据更新 treeData
const lazyKeys = Object.keys(normalizedLazyNode);
if (lazy && lazyKeys.length && rootLazyRowKeys.length) {
lazyKeys.forEach(key => {
const oldValue = oldTreeData[key];
const lazyNodeChildren = normalizedLazyNode[key].children;
if (rootLazyRowKeys.indexOf(key) !== -1) {
// 懒加载的 root 节点,更新一下原有的数据,原来的 children 一定是空数组
if (newTreeData[key].children.length !== 0) {
throw new Error('[ElTable]children must be an empty array.');
}
newTreeData[key].children = lazyNodeChildren;
} else {
const { loaded = false, loading = false } = oldValue || {};
newTreeData[key] = {
loaded: !!loaded,
loading: !!loading,
expanded: getExpanded(oldValue, key),
children: lazyNodeChildren,
level: ''
};
}
});
}
this.states.treeData = newTreeData;
this.updateTableScrollY();
},
updateTreeExpandKeys(value) {
// 仅仅在包含嵌套数据时才去更新
if (Object.keys(this.normalizedData).length) {
this.states.expandRowKeys = value;
this.updateTreeData();
}
},
toggleTreeExpansion(row, expanded) {
this.assertRowKey();
const { rowKey, treeData } = this.states;
const id = getRowIdentity(row, rowKey);
const data = id && treeData[id];
const oldExpanded = treeData[id].expanded;
if (id && data && ('expanded' in data)) {
expanded = typeof expanded === 'undefined' ? !data.expanded : expanded;
treeData[id].expanded = expanded;
if (oldExpanded !== expanded) {
this.table.$emit('expand-change', row, expanded);
}
this.updateTableScrollY();
}
},
loadOrToggle(row) {
this.assertRowKey();
const { lazy, treeData, rowKey } = this.states;
const id = getRowIdentity(row, rowKey);
const data = treeData[id];
if (lazy && data && ('loaded' in data) && !data.loaded) {
this.loadData(row, id, data);
} else {
this.toggleTreeExpansion(row);
}
},
loadData(row, key, treeNode) {
const { load } = this.table;
const { lazyTreeNodeMap, treeData } = this.states;
if (load && !treeData[key].loaded) {
treeData[key].loading = true;
load(row, treeNode, (data) => {
if (!Array.isArray(data)) {
throw new Error('[ElTable] data must be an array');
}
treeData[key].loading = false;
treeData[key].loaded = true;
treeData[key].expanded = true;
if (data.length) {
this.$set(lazyTreeNodeMap, key, data);
}
this.table.$emit('expand-change', row, true);
});
}
}
}
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
import LayoutObserver from './layout-observer';
import { mapStates } from './store/helper';
export default {
name: 'ElTableFooter',
......@@ -49,7 +50,7 @@ export default {
border="0">
<colgroup>
{
this._l(this.columns, column => <col name={ column.id } />)
this.columns.map(column => <col name={ column.id } key={column.id} />)
}
{
this.hasGutter ? <col name="gutter" /> : ''
......@@ -58,18 +59,17 @@ export default {
<tbody class={ [{ 'has-gutter': this.hasGutter }] }>
<tr>
{
this._l(this.columns, (column, cellIndex) =>
<td
colspan={ column.colSpan }
rowspan={ column.rowSpan }
class={ this.getRowClasses(column, cellIndex) }>
<div class={ ['cell', column.labelClassName] }>
{
sums[cellIndex]
}
</div>
</td>
)
this.columns.map((column, cellIndex) => <td
key={cellIndex}
colspan={ column.colSpan }
rowspan={ column.rowSpan }
class={ this.getRowClasses(column, cellIndex) }>
<div class={ ['cell', column.labelClassName] }>
{
sums[cellIndex]
}
</div>
</td>)
}
{
this.hasGutter ? <th class="gutter"></th> : ''
......@@ -104,37 +104,19 @@ export default {
return this.$parent;
},
isAllSelected() {
return this.store.states.isAllSelected;
},
columnsCount() {
return this.store.states.columns.length;
},
leftFixedCount() {
return this.store.states.fixedColumns.length;
},
leftFixedLeafCount() {
return this.store.states.fixedLeafColumnsLength;
},
rightFixedLeafCount() {
return this.store.states.rightFixedLeafColumnsLength;
},
rightFixedCount() {
return this.store.states.rightFixedColumns.length;
},
columns() {
return this.store.states.columns;
},
hasGutter() {
return !this.fixed && this.tableLayout.gutterWidth;
}
},
...mapStates({
columns: 'columns',
isAllSelected: 'isAllSelected',
leftFixedLeafCount: 'fixedLeafColumnsLength',
rightFixedLeafCount: 'rightFixedLeafColumnsLength',
columnsCount: states => states.columns.length,
leftFixedCount: states => states.fixedColumns.length,
rightFixedCount: states => states.rightFixedColumns.length
})
},
methods: {
......
import Vue from 'vue';
import { hasClass, addClass, removeClass } from 'element-ui/src/utils/dom';
import ElCheckbox from 'element-ui/packages/checkbox';
import ElTag from 'element-ui/packages/tag';
import Vue from 'vue';
import FilterPanel from './filter-panel.vue';
import LayoutObserver from './layout-observer';
import { mapStates } from './store/helper';
const getAllColumns = (columns) => {
const result = [];
......@@ -82,7 +82,7 @@ export default {
border="0">
<colgroup>
{
this._l(this.columns, column => <col name={ column.id } />)
this.columns.map(column => <col name={ column.id } key={column.id} />)
}
{
this.hasGutter ? <col name="gutter" /> : ''
......@@ -96,42 +96,44 @@ export default {
class={ this.getHeaderRowClass(rowIndex) }
>
{
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.handleHeaderClick($event, column) }
on-contextmenu={ ($event) => this.handleHeaderContextMenu($event, column) }
style={ this.getHeaderCellStyle(rowIndex, cellIndex, columns, column) }
class={ this.getHeaderCellClass(rowIndex, cellIndex, columns, column) }
key={ column.id }>
<div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : '', column.labelClassName] }>
{
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.handleSortClick($event, column) }>
<i class="sort-caret ascending" on-click={ ($event) => this.handleSortClick($event, column, 'ascending') }>
</i>
<i class="sort-caret descending" on-click={ ($event) => this.handleSortClick($event, column, '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>
)
columns.map((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.handleHeaderClick($event, column) }
on-contextmenu={ ($event) => this.handleHeaderContextMenu($event, column) }
style={ this.getHeaderCellStyle(rowIndex, cellIndex, columns, column) }
class={ this.getHeaderCellClass(rowIndex, cellIndex, columns, column) }
key={ column.id }>
<div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : '', column.labelClassName] }>
{
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.handleSortClick($event, column) }>
<i class="sort-caret ascending"
on-click={ ($event) => this.handleSortClick($event, column, 'ascending') }>
</i>
<i class="sort-caret descending"
on-click={ ($event) => this.handleSortClick($event, column, '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>))
}
{
this.hasGutter ? <th class="gutter"></th> : ''
......@@ -162,8 +164,7 @@ export default {
},
components: {
ElCheckbox,
ElTag
ElCheckbox
},
computed: {
......@@ -171,37 +172,19 @@ export default {
return this.$parent;
},
isAllSelected() {
return this.store.states.isAllSelected;
},
columnsCount() {
return this.store.states.columns.length;
},
leftFixedCount() {
return this.store.states.fixedColumns.length;
},
rightFixedCount() {
return this.store.states.rightFixedColumns.length;
},
leftFixedLeafCount() {
return this.store.states.fixedLeafColumnsLength;
},
rightFixedLeafCount() {
return this.store.states.rightFixedLeafColumnsLength;
},
columns() {
return this.store.states.columns;
},
hasGutter() {
return !this.fixed && this.tableLayout.gutterWidth;
}
},
...mapStates({
columns: 'columns',
isAllSelected: 'isAllSelected',
leftFixedLeafCount: 'fixedLeafColumnsLength',
rightFixedLeafCount: 'rightFixedLeafColumnsLength',
columnsCount: states => states.columns.length,
leftFixedCount: states => states.fixedColumns.length,
rightFixedCount: states => states.rightFixedColumns.length
})
},
created() {
......
import scrollbarWidth from 'element-ui/src/utils/scrollbar-width';
import Vue from 'vue';
import scrollbarWidth from 'element-ui/src/utils/scrollbar-width';
import { parseHeight } from './util';
class TableLayout {
constructor(options) {
......@@ -41,7 +42,7 @@ class TableLayout {
updateScrollY() {
const height = this.height;
if (typeof height !== 'string' && typeof height !== 'number') return;
if (height === null) return;
const bodyWrapper = this.table.bodyWrapper;
if (this.table.$el && bodyWrapper) {
const body = bodyWrapper.querySelector('.el-table__body');
......@@ -52,25 +53,33 @@ class TableLayout {
setHeight(value, prop = 'height') {
if (Vue.prototype.$isServer) return;
const el = this.table.$el;
if (typeof value === 'string' && /^\d+$/.test(value)) {
value = Number(value);
}
value = parseHeight(value);
this.height = value;
if (!el && (value || value === 0)) return Vue.nextTick(() => this.setHeight(value, prop));
if (typeof value === 'number') {
el.style[prop] = value + 'px';
this.updateElsHeight();
} else if (typeof value === 'string') {
el.style[prop] = value;
if (value) {
el.style[prop] = `${value}px`;
this.updateElsHeight();
}
}
setMaxHeight(value) {
return this.setHeight(value, 'max-height');
this.setHeight(value, 'max-height');
}
getFlattenColumns() {
const flattenColumns = [];
const columns = this.table.columns;
columns.forEach((column) => {
if (column.isColumnGroup) {
flattenColumns.push.apply(flattenColumns, column.columns);
} else {
flattenColumns.push(column);
}
});
return flattenColumns;
}
updateElsHeight() {
......@@ -84,11 +93,11 @@ class TableLayout {
return Vue.nextTick(() => this.updateElsHeight());
}
const tableHeight = this.tableHeight = this.table.$el.clientHeight;
if (this.height !== null && (!isNaN(this.height) || typeof this.height === 'string')) {
const footerHeight = this.footerHeight = footerWrapper ? footerWrapper.offsetHeight : 0;
const footerHeight = this.footerHeight = footerWrapper ? footerWrapper.offsetHeight : 0;
if (this.height !== null) {
this.bodyHeight = tableHeight - headerHeight - footerHeight + (footerWrapper ? 1 : 0);
}
this.fixedBodyHeight = this.scrollX ? this.bodyHeight - this.gutterWidth : this.bodyHeight;
this.fixedBodyHeight = this.scrollX ? (this.bodyHeight - this.gutterWidth) : this.bodyHeight;
const noData = !this.table.data || this.table.data.length === 0;
this.viewportHeight = this.scrollX ? tableHeight - (noData ? 0 : this.gutterWidth) : tableHeight;
......@@ -97,20 +106,6 @@ class TableLayout {
this.notifyObservers('scrollable');
}
getFlattenColumns() {
const flattenColumns = [];
const columns = this.table.columns;
columns.forEach((column) => {
if (column.isColumnGroup) {
flattenColumns.push.apply(flattenColumns, column.columns);
} else {
flattenColumns.push(column);
}
});
return flattenColumns;
}
updateColumnsWidth() {
if (Vue.prototype.$isServer) return;
const fit = this.fit;
......
This diff is collapsed.
This diff is collapsed.
......@@ -120,3 +120,135 @@ export const getRowIdentity = (row, rowKey) => {
return rowKey.call(null, row);
}
};
export const getKeysMap = function(array, rowKey) {
const arrayMap = {};
(array || []).forEach((row, index) => {
arrayMap[getRowIdentity(row, rowKey)] = { row, index };
});
return arrayMap;
};
function hasOwn(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
export function mergeOptions(defaults, config) {
const options = {};
let key;
for (key in defaults) {
options[key] = defaults[key];
}
for (key in config) {
if (hasOwn(config, key)) {
const value = config[key];
if (typeof value !== 'undefined') {
options[key] = value;
}
}
}
return options;
}
export function parseWidth(width) {
if (width !== undefined) {
width = parseInt(width, 10);
if (isNaN(width)) {
width = null;
}
}
return width;
}
export function parseMinWidth(minWidth) {
if (typeof minWidth !== 'undefined') {
minWidth = parseWidth(minWidth);
if (isNaN(minWidth)) {
minWidth = 80;
}
}
return minWidth;
};
export function parseHeight(height) {
if (typeof height === 'number') {
return height;
}
if (typeof height === 'string') {
if (/^\d+(?:px)?/.test(height)) {
return parseInt(height, 10);
}
console.warn('[Element Warn][ElTable]invalid height and it will be ignored.');
}
return null;
}
// https://github.com/reduxjs/redux/blob/master/src/compose.js
export function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
export function toggleRowStatus(statusArr, row, newVal) {
let changed = false;
const index = statusArr.indexOf(row);
const included = index !== -1;
const addRow = () => {
statusArr.push(row);
changed = true;
};
const removeRow = () => {
statusArr.splice(index, 1);
changed = true;
};
if (typeof newVal === 'boolean') {
if (newVal && !included) {
addRow();
} else if (!newVal && included) {
removeRow();
}
} else {
if (included) {
removeRow();
} else {
addRow();
}
}
return changed;
}
export function walkTreeNode(root, cb, childrenKey = 'children', lazyKey = 'hasChildren') {
const isNil = (array) => !(Array.isArray(array) && array.length);
function _walker(parent, children, level) {
cb(parent, children, level);
children.forEach(item => {
if (item[lazyKey]) {
cb(item, null, level + 1);
return;
}
const children = item[childrenKey];
if (!isNil(children)) {
_walker(item, children, level + 1);
}
});
}
root.forEach(item => {
if (item[lazyKey]) {
cb(item, null, 0);
return;
}
const children = item[childrenKey];
if (!isNil(children)) {
_walker(item, children, 0);
}
});
}
......@@ -561,9 +561,11 @@
[class*=el-table__row--level] {
.el-table__expand-icon {
display: inline-block;
width: 14px;
vertical-align: middle;
margin-right: 5px;
width: 20px;
line-height: 20px;
height: 20px;
text-align: center;
margin-right: 3px;
}
}
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment