refactor: remove old table
parent
223abb1a6b
commit
d84ebc4a3e
|
|
@ -1,60 +0,0 @@
|
||||||
.move-enter,
|
|
||||||
.move-appear {
|
|
||||||
opacity: 0;
|
|
||||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
||||||
animation-duration: 2.5s;
|
|
||||||
animation-fill-mode: both;
|
|
||||||
animation-play-state: paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
.move-leave {
|
|
||||||
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
|
||||||
animation-duration: 0.5s;
|
|
||||||
animation-fill-mode: both;
|
|
||||||
animation-play-state: paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
.move-enter.move-enter-active,
|
|
||||||
.move-appear.move-enter-active {
|
|
||||||
animation-name: moveLeftIn;
|
|
||||||
animation-play-state: running;
|
|
||||||
}
|
|
||||||
|
|
||||||
.move-leave.move-leave-active {
|
|
||||||
animation-name: moveRightOut;
|
|
||||||
animation-play-state: running;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes moveLeftIn {
|
|
||||||
0% {
|
|
||||||
transform-origin: 0 0;
|
|
||||||
transform: translateX(30px);
|
|
||||||
opacity: 0;
|
|
||||||
background: #fff6de;
|
|
||||||
}
|
|
||||||
20% {
|
|
||||||
transform-origin: 0 0;
|
|
||||||
transform: translateX(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
80% {
|
|
||||||
background: #fff6de;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background: transparent;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes moveRightOut {
|
|
||||||
0% {
|
|
||||||
transform-origin: 0 0;
|
|
||||||
transform: translateX(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform-origin: 0 0;
|
|
||||||
transform: translateX(-30px);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
@tablePrefixCls: rc-table;
|
|
||||||
@table-border-color: #e9e9e9;
|
|
||||||
|
|
||||||
.@{tablePrefixCls}.bordered {
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
border: 1px solid @table-border-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,233 +0,0 @@
|
||||||
@tablePrefixCls: rc-table;
|
|
||||||
@text-color : #666;
|
|
||||||
@font-size-base : 12px;
|
|
||||||
@line-height: 1.5;
|
|
||||||
@table-border-color: #e9e9e9;
|
|
||||||
@table-head-background-color: #f7f7f7;
|
|
||||||
@vertical-padding: 16px;
|
|
||||||
@horizontal-padding: 8px;
|
|
||||||
|
|
||||||
.@{tablePrefixCls} {
|
|
||||||
font-size: @font-size-base;
|
|
||||||
color: @text-color;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
position: relative;
|
|
||||||
line-height: @line-height;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.@{tablePrefixCls}-scroll {
|
|
||||||
overflow: auto;
|
|
||||||
table {
|
|
||||||
width: auto;
|
|
||||||
min-width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{tablePrefixCls}-header {
|
|
||||||
overflow: hidden;
|
|
||||||
background: @table-head-background-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-fixed-header &-body {
|
|
||||||
background: #fff;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-fixed-header &-body-inner {
|
|
||||||
height: 100%;
|
|
||||||
overflow: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-fixed-header &-scroll &-header {
|
|
||||||
overflow-x: scroll;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
margin-bottom: -20px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/ant-design/ant-design/issues/10828
|
|
||||||
&-fixed-columns-in-body {
|
|
||||||
visibility: hidden;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{tablePrefixCls}-title {
|
|
||||||
padding: @vertical-padding @horizontal-padding;
|
|
||||||
border-top: 1px solid @table-border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{tablePrefixCls}-content {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{tablePrefixCls}-footer {
|
|
||||||
padding: @vertical-padding @horizontal-padding;
|
|
||||||
border-bottom: 1px solid @table-border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{tablePrefixCls}-placeholder {
|
|
||||||
padding: 16px 8px;
|
|
||||||
background: #fff;
|
|
||||||
border-bottom: 1px solid @table-border-color;
|
|
||||||
text-align: center;
|
|
||||||
position: relative;
|
|
||||||
&-fixed-columns {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
background: transparent;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: separate;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
background: @table-head-background-color;
|
|
||||||
font-weight: bold;
|
|
||||||
transition: background 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
border-bottom: 1px solid @table-border-color;
|
|
||||||
&:empty:after {
|
|
||||||
content: '.'; // empty cell placeholder
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
&:hover {
|
|
||||||
background: #eaf8fe;
|
|
||||||
}
|
|
||||||
&.@{tablePrefixCls}-row-hover {
|
|
||||||
background: #eaf8fe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
padding: @vertical-padding @horizontal-padding;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{tablePrefixCls} {
|
|
||||||
&-expand-icon-col {
|
|
||||||
width: 34px;
|
|
||||||
}
|
|
||||||
&-row,
|
|
||||||
&-expanded-row {
|
|
||||||
&-expand-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 16px;
|
|
||||||
border: 1px solid @table-border-color;
|
|
||||||
user-select: none;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
&-spaced {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
&-spaced:after {
|
|
||||||
content: '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
&-expanded:after {
|
|
||||||
content: '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
&-collapsed:after {
|
|
||||||
content: '+';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tr&-expanded-row {
|
|
||||||
background: #f7f7f7;
|
|
||||||
&:hover {
|
|
||||||
background: #f7f7f7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-column-hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
&-prev-columns-page,
|
|
||||||
&-next-columns-page {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #666;
|
|
||||||
z-index: 1;
|
|
||||||
&:hover {
|
|
||||||
color: #2db7f5;
|
|
||||||
}
|
|
||||||
&-disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
color: #999;
|
|
||||||
&:hover {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-prev-columns-page {
|
|
||||||
margin-right: 8px;
|
|
||||||
&:before {
|
|
||||||
content: '<';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-next-columns-page {
|
|
||||||
float: right;
|
|
||||||
&:before {
|
|
||||||
content: '>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-fixed-left,
|
|
||||||
&-fixed-right {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
table {
|
|
||||||
width: auto;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-fixed-left {
|
|
||||||
left: 0;
|
|
||||||
box-shadow: 4px 0 4px rgba(100, 100, 100, 0.1);
|
|
||||||
& .@{tablePrefixCls}-body-inner {
|
|
||||||
margin-right: -20px;
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
||||||
.@{tablePrefixCls}-fixed-header & .@{tablePrefixCls}-body-inner {
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-fixed-right {
|
|
||||||
right: 0;
|
|
||||||
box-shadow: -4px 0 4px rgba(100, 100, 100, 0.1);
|
|
||||||
|
|
||||||
// hide expand row content in right fixed Table
|
|
||||||
// https://github.com/ant-design/ant-design/issues/1898
|
|
||||||
.@{tablePrefixCls}-expanded-row {
|
|
||||||
color: transparent;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&&-scroll-position-left &-fixed-left {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&&-scroll-position-right &-fixed-right {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,220 +0,0 @@
|
||||||
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: sans-serif;
|
|
||||||
-ms-text-size-adjust: 100%;
|
|
||||||
-webkit-text-size-adjust: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
article,
|
|
||||||
aside,
|
|
||||||
details,
|
|
||||||
figcaption,
|
|
||||||
figure,
|
|
||||||
footer,
|
|
||||||
header,
|
|
||||||
hgroup,
|
|
||||||
main,
|
|
||||||
nav,
|
|
||||||
section,
|
|
||||||
summary {
|
|
||||||
display: block
|
|
||||||
}
|
|
||||||
|
|
||||||
audio,
|
|
||||||
canvas,
|
|
||||||
progress,
|
|
||||||
video {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: baseline
|
|
||||||
}
|
|
||||||
|
|
||||||
audio:not([controls]) {
|
|
||||||
display: none;
|
|
||||||
height: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden],
|
|
||||||
template {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
background: 0 0
|
|
||||||
}
|
|
||||||
|
|
||||||
a:active,
|
|
||||||
a:hover {
|
|
||||||
outline: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr[title] {
|
|
||||||
border-bottom: 1px dotted
|
|
||||||
}
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: 700
|
|
||||||
}
|
|
||||||
|
|
||||||
dfn {
|
|
||||||
font-style: italic
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
margin: .67em 0
|
|
||||||
}
|
|
||||||
|
|
||||||
mark {
|
|
||||||
background: #ff0;
|
|
||||||
color: #000
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%
|
|
||||||
}
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: baseline
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -.5em
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -.25em
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
svg:not(:root) {
|
|
||||||
overflow: hidden
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 1em 40px
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
-moz-box-sizing: content-box;
|
|
||||||
box-sizing: content-box;
|
|
||||||
height: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
overflow: auto
|
|
||||||
}
|
|
||||||
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
pre,
|
|
||||||
samp {
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
font-size: 1em
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
input,
|
|
||||||
optgroup,
|
|
||||||
select,
|
|
||||||
textarea {
|
|
||||||
color: inherit;
|
|
||||||
font: inherit;
|
|
||||||
margin: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
overflow: visible
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
html input[type=button],
|
|
||||||
input[type=reset],
|
|
||||||
input[type=submit] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
cursor: pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
button[disabled],
|
|
||||||
html input[disabled] {
|
|
||||||
cursor: default
|
|
||||||
}
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
input::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
line-height: normal
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=checkbox],
|
|
||||||
input[type=radio] {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=number]::-webkit-inner-spin-button,
|
|
||||||
input[type=number]::-webkit-outer-spin-button {
|
|
||||||
height: auto
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=search] {
|
|
||||||
-webkit-appearance: textfield;
|
|
||||||
-moz-box-sizing: content-box;
|
|
||||||
-webkit-box-sizing: content-box;
|
|
||||||
box-sizing: content-box
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=search]::-webkit-search-cancel-button,
|
|
||||||
input[type=search]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
border: 1px solid silver;
|
|
||||||
margin: 0 2px;
|
|
||||||
padding: .35em .625em .75em
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
border: 0;
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto
|
|
||||||
}
|
|
||||||
|
|
||||||
optgroup {
|
|
||||||
font-weight: 700
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
// base rc-table 6.10.9
|
|
||||||
import Table from './src/Table';
|
|
||||||
import Column from './src/Column';
|
|
||||||
import ColumnGroup from './src/ColumnGroup';
|
|
||||||
import { INTERNAL_COL_DEFINE } from './src/utils';
|
|
||||||
// const Table = {
|
|
||||||
// name: 'Table',
|
|
||||||
// inheritAttrs: false,
|
|
||||||
// Column,
|
|
||||||
// ColumnGroup,
|
|
||||||
// props: T.props,
|
|
||||||
// methods: {
|
|
||||||
// getTableNode() {
|
|
||||||
// return this.table.tableNode;
|
|
||||||
// },
|
|
||||||
// getBodyTable() {
|
|
||||||
// return this.table.ref_bodyTable;
|
|
||||||
// },
|
|
||||||
// saveTable(node) {
|
|
||||||
// this.table = node;
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// render() {
|
|
||||||
// const props = getOptionProps(this);
|
|
||||||
// const columns = props.columns;
|
|
||||||
// const tProps = {
|
|
||||||
// ...props,
|
|
||||||
// ...this.$attrs,
|
|
||||||
// columns,
|
|
||||||
// ref: this.saveTable,
|
|
||||||
// };
|
|
||||||
// return <T {...tProps} />;
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
|
|
||||||
export default Table;
|
|
||||||
export { Column, ColumnGroup, INTERNAL_COL_DEFINE };
|
|
||||||
|
|
@ -1,172 +0,0 @@
|
||||||
import { inject } from 'vue';
|
|
||||||
import PropTypes, { withUndefined } from '../../_util/vue-types';
|
|
||||||
import classNames from '../../_util/classNames';
|
|
||||||
import ColGroup from './ColGroup';
|
|
||||||
import TableHeader from './TableHeader';
|
|
||||||
import TableRow from './TableRow';
|
|
||||||
import ExpandableRow from './ExpandableRow';
|
|
||||||
function noop() {}
|
|
||||||
const BaseTable = {
|
|
||||||
name: 'BaseTable',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
fixed: withUndefined(PropTypes.oneOfType([PropTypes.string, PropTypes.looseBool])),
|
|
||||||
columns: PropTypes.array.isRequired,
|
|
||||||
tableClassName: PropTypes.string.isRequired,
|
|
||||||
hasHead: PropTypes.looseBool.isRequired,
|
|
||||||
hasBody: PropTypes.looseBool.isRequired,
|
|
||||||
expander: PropTypes.object.isRequired,
|
|
||||||
getRowKey: PropTypes.func,
|
|
||||||
isAnyColumnsFixed: PropTypes.looseBool,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
table: inject('table', () => ({})),
|
|
||||||
store: inject('table-store', () => ({})),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getColumns(cols) {
|
|
||||||
const { columns = [] } = this.$props;
|
|
||||||
return (cols || columns).map(column => ({
|
|
||||||
...column,
|
|
||||||
className: classNames(column.className, column.class),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
handleRowHover(isHover, key) {
|
|
||||||
this.store.currentHoverKey = isHover ? key : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
renderRows(renderData, indent, ancestorKeys = []) {
|
|
||||||
const {
|
|
||||||
sComponents: components,
|
|
||||||
prefixCls,
|
|
||||||
childrenColumnName,
|
|
||||||
rowClassName,
|
|
||||||
customRow = noop,
|
|
||||||
onRowClick = noop,
|
|
||||||
onRowDoubleClick = noop,
|
|
||||||
onRowContextMenu = noop,
|
|
||||||
onRowMouseEnter = noop,
|
|
||||||
onRowMouseLeave = noop,
|
|
||||||
rowRef,
|
|
||||||
} = { ...this.table.$attrs, ...this.table.$props, ...this.table.$data };
|
|
||||||
const { columnManager } = this.store;
|
|
||||||
const { getRowKey, fixed, expander, isAnyColumnsFixed } = this;
|
|
||||||
|
|
||||||
const rows = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < renderData.length; i += 1) {
|
|
||||||
const record = renderData[i];
|
|
||||||
const key = getRowKey(record, i);
|
|
||||||
const className =
|
|
||||||
typeof rowClassName === 'string' ? rowClassName : rowClassName(record, i, indent);
|
|
||||||
|
|
||||||
const onHoverProps = {};
|
|
||||||
if (columnManager.isAnyColumnsFixed) {
|
|
||||||
onHoverProps.onHover = this.handleRowHover;
|
|
||||||
}
|
|
||||||
|
|
||||||
let leafColumns;
|
|
||||||
if (fixed === 'left') {
|
|
||||||
leafColumns = columnManager.leftLeafColumns;
|
|
||||||
} else if (fixed === 'right') {
|
|
||||||
leafColumns = columnManager.rightLeafColumns;
|
|
||||||
} else {
|
|
||||||
leafColumns = this.getColumns(columnManager.leafColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rowPrefixCls = `${prefixCls}-row`;
|
|
||||||
|
|
||||||
const expandableRowProps = {
|
|
||||||
...expander.props,
|
|
||||||
fixed,
|
|
||||||
index: i,
|
|
||||||
prefixCls: rowPrefixCls,
|
|
||||||
record,
|
|
||||||
rowKey: key,
|
|
||||||
needIndentSpaced: expander.needIndentSpaced,
|
|
||||||
key,
|
|
||||||
onRowClick,
|
|
||||||
onExpandedChange: expander.handleExpandChange,
|
|
||||||
};
|
|
||||||
const row = (
|
|
||||||
<ExpandableRow
|
|
||||||
{...expandableRowProps}
|
|
||||||
v-slots={{
|
|
||||||
default: expandableRow => {
|
|
||||||
const tableRowProps = {
|
|
||||||
fixed,
|
|
||||||
indent,
|
|
||||||
record,
|
|
||||||
index: i,
|
|
||||||
prefixCls: rowPrefixCls,
|
|
||||||
childrenColumnName,
|
|
||||||
columns: leafColumns,
|
|
||||||
rowKey: key,
|
|
||||||
ancestorKeys,
|
|
||||||
components,
|
|
||||||
isAnyColumnsFixed,
|
|
||||||
customRow,
|
|
||||||
onRowDoubleClick,
|
|
||||||
onRowContextMenu,
|
|
||||||
onRowMouseEnter,
|
|
||||||
onRowMouseLeave,
|
|
||||||
...onHoverProps,
|
|
||||||
class: className,
|
|
||||||
ref: rowRef(record, i, indent),
|
|
||||||
...expandableRow,
|
|
||||||
};
|
|
||||||
return <TableRow {...tableRowProps} />;
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
rows.push(row);
|
|
||||||
expander.renderRows(this.renderRows, rows, record, i, indent, fixed, key, ancestorKeys);
|
|
||||||
}
|
|
||||||
return rows;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { sComponents: components, prefixCls, scroll, data } = this.table;
|
|
||||||
const { expander, tableClassName, hasHead, hasBody, fixed } = this.$props;
|
|
||||||
const columns = this.getColumns();
|
|
||||||
const tableStyle = {};
|
|
||||||
|
|
||||||
if (!fixed && scroll.x) {
|
|
||||||
// not set width, then use content fixed width
|
|
||||||
tableStyle.width = scroll.x === true ? 'auto' : scroll.x;
|
|
||||||
tableStyle.width =
|
|
||||||
typeof tableStyle.width === 'number' ? `${tableStyle.width}px` : tableStyle.width;
|
|
||||||
}
|
|
||||||
if (fixed) {
|
|
||||||
const width = columns.reduce((sum, { width: w }) => {
|
|
||||||
return sum + parseFloat(w, 10);
|
|
||||||
}, 0);
|
|
||||||
if (width > 0) {
|
|
||||||
tableStyle.width = width + 'px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Table = hasBody ? components.table : 'table';
|
|
||||||
const BodyWrapper = components.body.wrapper;
|
|
||||||
|
|
||||||
let body;
|
|
||||||
if (hasBody) {
|
|
||||||
body = <BodyWrapper class={`${prefixCls}-tbody`}>{this.renderRows(data, 0)}</BodyWrapper>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Table class={tableClassName} style={tableStyle} key="table">
|
|
||||||
<ColGroup columns={columns} fixed={fixed} />
|
|
||||||
{hasHead && <TableHeader expander={expander} columns={columns} fixed={fixed} />}
|
|
||||||
{body}
|
|
||||||
</Table>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default BaseTable;
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
import { inject } from 'vue';
|
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import BaseTable from './BaseTable';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'BodyTable',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
columns: PropTypes.array.isRequired,
|
|
||||||
tableClassName: PropTypes.string.isRequired,
|
|
||||||
handleBodyScroll: PropTypes.func.isRequired,
|
|
||||||
handleWheel: PropTypes.func.isRequired,
|
|
||||||
getRowKey: PropTypes.func.isRequired,
|
|
||||||
expander: PropTypes.object.isRequired,
|
|
||||||
isAnyColumnsFixed: PropTypes.looseBool,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
table: inject('table', {}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const { prefixCls, scroll } = this.table;
|
|
||||||
const {
|
|
||||||
columns,
|
|
||||||
tableClassName,
|
|
||||||
getRowKey,
|
|
||||||
handleBodyScroll,
|
|
||||||
handleWheel,
|
|
||||||
expander,
|
|
||||||
isAnyColumnsFixed,
|
|
||||||
} = this;
|
|
||||||
let { useFixedHeader, saveRef } = this.table;
|
|
||||||
const bodyStyle = { ...this.table.bodyStyle };
|
|
||||||
|
|
||||||
if (scroll.y) {
|
|
||||||
// maxHeight will make fixed-Table scrolling not working
|
|
||||||
// so we only set maxHeight to body-Table here
|
|
||||||
let maxHeight = bodyStyle.maxHeight || scroll.y;
|
|
||||||
maxHeight = typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight;
|
|
||||||
|
|
||||||
bodyStyle.maxHeight = maxHeight;
|
|
||||||
bodyStyle.overflowY = bodyStyle.overflowY || 'scroll';
|
|
||||||
useFixedHeader = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scroll.x) {
|
|
||||||
bodyStyle.overflowX = bodyStyle.overflowX || 'auto';
|
|
||||||
// Fix weired webkit render bug
|
|
||||||
// https://github.com/ant-design/ant-design/issues/7783
|
|
||||||
bodyStyle.WebkitTransform = 'translate3d (0, 0, 0)';
|
|
||||||
|
|
||||||
if (!scroll.y) {
|
|
||||||
bodyStyle.overflowY = 'hidden';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseTable = (
|
|
||||||
<BaseTable
|
|
||||||
tableClassName={tableClassName}
|
|
||||||
hasHead={!useFixedHeader}
|
|
||||||
hasBody
|
|
||||||
columns={columns}
|
|
||||||
expander={expander}
|
|
||||||
getRowKey={getRowKey}
|
|
||||||
isAnyColumnsFixed={isAnyColumnsFixed}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
// Should provides `tabindex` if use scroll to enable keyboard scroll
|
|
||||||
const useTabIndex = scroll && (scroll.x || scroll.y);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
tabindex={useTabIndex ? -1 : undefined}
|
|
||||||
key="bodyTable"
|
|
||||||
class={`${prefixCls}-body`}
|
|
||||||
style={bodyStyle}
|
|
||||||
ref={saveRef('bodyTable')}
|
|
||||||
onWheel={handleWheel}
|
|
||||||
onScroll={handleBodyScroll}
|
|
||||||
>
|
|
||||||
{baseTable}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
import { inject } from 'vue';
|
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import { INTERNAL_COL_DEFINE } from './utils';
|
|
||||||
import ResizeObserver from '../../vc-resize-observer';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'ColGroup',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
fixed: PropTypes.string,
|
|
||||||
columns: PropTypes.array,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
table: inject('table', {}),
|
|
||||||
store: inject('table-store', () => ({})),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const { fixed, table } = this;
|
|
||||||
const { prefixCls, expandIconAsCell, onColumnResize } = table;
|
|
||||||
|
|
||||||
let cols = [];
|
|
||||||
|
|
||||||
if (expandIconAsCell && fixed !== 'right') {
|
|
||||||
cols.push(<col class={`${prefixCls}-expand-icon-col`} key="rc-table-expand-icon-col" />);
|
|
||||||
}
|
|
||||||
|
|
||||||
let leafColumns;
|
|
||||||
const { columnManager } = this.store;
|
|
||||||
if (fixed === 'left') {
|
|
||||||
leafColumns = columnManager.leftLeafColumns;
|
|
||||||
} else if (fixed === 'right') {
|
|
||||||
leafColumns = columnManager.rightLeafColumns;
|
|
||||||
} else {
|
|
||||||
leafColumns = columnManager.leafColumns;
|
|
||||||
}
|
|
||||||
cols = cols.concat(
|
|
||||||
leafColumns.map(({ key, dataIndex, width, [INTERNAL_COL_DEFINE]: additionalProps }) => {
|
|
||||||
const mergedKey = key !== undefined ? key : dataIndex;
|
|
||||||
const w = typeof width === 'number' ? `${width}px` : width;
|
|
||||||
return (
|
|
||||||
<ResizeObserver
|
|
||||||
onResize={({ offsetWidth }) => {
|
|
||||||
onColumnResize(mergedKey, offsetWidth);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<col
|
|
||||||
data-key={mergedKey}
|
|
||||||
key={mergedKey}
|
|
||||||
style={{ width: w, minWidth: w }}
|
|
||||||
{...additionalProps}
|
|
||||||
/>
|
|
||||||
</ResizeObserver>
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return <colgroup>{cols}</colgroup>;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
// import PropTypes from '../../_util/vue-types';
|
|
||||||
|
|
||||||
// export default {
|
|
||||||
// name: 'Column',
|
|
||||||
// props: {
|
|
||||||
// rowSpan: PropTypes.number,
|
|
||||||
// colSpan: PropTypes.number,
|
|
||||||
// title: PropTypes.any,
|
|
||||||
// dataIndex: PropTypes.string,
|
|
||||||
// width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
||||||
// ellipsis: PropTypes.looseBool,
|
|
||||||
// fixed: PropTypes.oneOf([true, 'left', 'right']),
|
|
||||||
// align: PropTypes.oneOf(['left', 'center', 'right']),
|
|
||||||
// customRender: PropTypes.func,
|
|
||||||
// className: PropTypes.string,
|
|
||||||
// // onCellClick: PropTypes.func,
|
|
||||||
// customCell: PropTypes.func,
|
|
||||||
// customHeaderCell: PropTypes.func,
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
|
|
||||||
const Column = () => null;
|
|
||||||
|
|
||||||
export default Column;
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'ColumnGroup',
|
|
||||||
props: {
|
|
||||||
title: PropTypes.any,
|
|
||||||
},
|
|
||||||
isTableColumnGroup: true,
|
|
||||||
render() {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import BaseMixin from '../../_util/BaseMixin';
|
|
||||||
export default {
|
|
||||||
name: 'ExpandIcon',
|
|
||||||
mixins: [BaseMixin],
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
record: PropTypes.object,
|
|
||||||
prefixCls: PropTypes.string,
|
|
||||||
expandable: PropTypes.any,
|
|
||||||
expanded: PropTypes.looseBool,
|
|
||||||
needIndentSpaced: PropTypes.looseBool,
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onExpand(e) {
|
|
||||||
this.__emit('expand', this.record, e);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { expandable, prefixCls, onExpand, needIndentSpaced, expanded } = this;
|
|
||||||
if (expandable) {
|
|
||||||
const expandClassName = expanded ? 'expanded' : 'collapsed';
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
class={`${prefixCls}-expand-icon ${prefixCls}-${expandClassName}`}
|
|
||||||
onClick={onExpand}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (needIndentSpaced) {
|
|
||||||
return <span class={`${prefixCls}-expand-icon ${prefixCls}-spaced`} />;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
import PropTypes, { withUndefined } from '../../_util/vue-types';
|
|
||||||
import ExpandIcon from './ExpandIcon';
|
|
||||||
import BaseMixin from '../../_util/BaseMixin';
|
|
||||||
import { getSlot } from '../../_util/props-util';
|
|
||||||
import { computed, inject } from 'vue';
|
|
||||||
|
|
||||||
const ExpandableRow = {
|
|
||||||
mixins: [BaseMixin],
|
|
||||||
name: 'ExpandableRow',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
prefixCls: PropTypes.string.isRequired,
|
|
||||||
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
||||||
fixed: withUndefined(PropTypes.oneOfType([PropTypes.string, PropTypes.looseBool])),
|
|
||||||
record: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired,
|
|
||||||
indentSize: PropTypes.number,
|
|
||||||
needIndentSpaced: PropTypes.looseBool.isRequired,
|
|
||||||
expandRowByClick: PropTypes.looseBool,
|
|
||||||
expandIconAsCell: PropTypes.looseBool,
|
|
||||||
expandIconColumnIndex: PropTypes.number,
|
|
||||||
childrenColumnName: PropTypes.string,
|
|
||||||
expandedRowRender: PropTypes.func,
|
|
||||||
expandIcon: PropTypes.func,
|
|
||||||
// onExpandedChange: PropTypes.func.isRequired,
|
|
||||||
// onRowClick: PropTypes.func,
|
|
||||||
// children: PropTypes.func.isRequired,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const store = inject('table-store', () => ({}));
|
|
||||||
return {
|
|
||||||
expanded: computed(() => store.expandedRowKeys.includes(props.rowKey)),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeUnmount() {
|
|
||||||
this.handleDestroy();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
hasExpandIcon(columnIndex) {
|
|
||||||
const { expandRowByClick, expandIcon } = this.$props;
|
|
||||||
|
|
||||||
if (this.tempExpandIconAsCell || columnIndex !== this.tempExpandIconColumnIndex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!expandIcon || !expandRowByClick;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleExpandChange(record, event) {
|
|
||||||
const { expanded, rowKey } = this;
|
|
||||||
this.__emit('expandedChange', !expanded, record, event, rowKey);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDestroy() {
|
|
||||||
const { rowKey, record } = this;
|
|
||||||
this.__emit('expandedChange', false, record, null, rowKey, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleRowClick(record, index, event) {
|
|
||||||
const { expandRowByClick } = this;
|
|
||||||
if (expandRowByClick) {
|
|
||||||
this.handleExpandChange(record, event);
|
|
||||||
}
|
|
||||||
this.__emit('rowClick', record, index, event);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderExpandIcon() {
|
|
||||||
const { prefixCls, expanded, record, needIndentSpaced, expandIcon } = this;
|
|
||||||
if (expandIcon) {
|
|
||||||
return expandIcon({
|
|
||||||
prefixCls,
|
|
||||||
expanded,
|
|
||||||
record,
|
|
||||||
needIndentSpaced,
|
|
||||||
expandable: this.expandable,
|
|
||||||
onExpand: this.handleExpandChange,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<ExpandIcon
|
|
||||||
expandable={this.expandable}
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
onExpand={this.handleExpandChange}
|
|
||||||
needIndentSpaced={needIndentSpaced}
|
|
||||||
expanded={expanded}
|
|
||||||
record={record}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderExpandIconCell(cells) {
|
|
||||||
if (!this.tempExpandIconAsCell) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { prefixCls } = this;
|
|
||||||
|
|
||||||
cells.push(
|
|
||||||
<td class={`${prefixCls}-expand-icon-cell`} key="rc-table-expand-icon-cell">
|
|
||||||
{this.renderExpandIcon()}
|
|
||||||
</td>,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { childrenColumnName, expandedRowRender, indentSize, record, fixed, expanded } = this;
|
|
||||||
|
|
||||||
this.tempExpandIconAsCell = fixed !== 'right' ? this.expandIconAsCell : false;
|
|
||||||
this.tempExpandIconColumnIndex = fixed !== 'right' ? this.expandIconColumnIndex : -1;
|
|
||||||
const childrenData = record[childrenColumnName];
|
|
||||||
this.expandable = !!(childrenData || expandedRowRender);
|
|
||||||
const expandableRowProps = {
|
|
||||||
indentSize,
|
|
||||||
expanded, // not used in TableRow, but it's required to re-render TableRow when `expanded` changes
|
|
||||||
hasExpandIcon: this.hasExpandIcon,
|
|
||||||
renderExpandIcon: this.renderExpandIcon,
|
|
||||||
renderExpandIconCell: this.renderExpandIconCell,
|
|
||||||
onRowClick: this.handleRowClick,
|
|
||||||
};
|
|
||||||
|
|
||||||
return getSlot(this, 'default', expandableRowProps);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ExpandableRow;
|
|
||||||
|
|
@ -1,241 +0,0 @@
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import BaseMixin from '../../_util/BaseMixin';
|
|
||||||
import shallowEqual from '../../_util/shallowequal';
|
|
||||||
import TableRow from './TableRow';
|
|
||||||
import { remove } from './utils';
|
|
||||||
import { initDefaultProps, getOptionProps, getSlot } from '../../_util/props-util';
|
|
||||||
import { inject } from 'vue';
|
|
||||||
|
|
||||||
export const ExpandableTableProps = () => ({
|
|
||||||
expandIconAsCell: PropTypes.looseBool,
|
|
||||||
expandRowByClick: PropTypes.looseBool,
|
|
||||||
expandedRowKeys: PropTypes.array,
|
|
||||||
expandedRowClassName: PropTypes.func,
|
|
||||||
defaultExpandAllRows: PropTypes.looseBool,
|
|
||||||
defaultExpandedRowKeys: PropTypes.array,
|
|
||||||
expandIconColumnIndex: PropTypes.number,
|
|
||||||
expandedRowRender: PropTypes.func,
|
|
||||||
expandIcon: PropTypes.func,
|
|
||||||
childrenColumnName: PropTypes.string,
|
|
||||||
indentSize: PropTypes.number,
|
|
||||||
// onExpand: PropTypes.func,
|
|
||||||
// onExpandedRowsChange: PropTypes.func,
|
|
||||||
columnManager: PropTypes.object.isRequired,
|
|
||||||
prefixCls: PropTypes.string.isRequired,
|
|
||||||
data: PropTypes.array,
|
|
||||||
getRowKey: PropTypes.func,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ExpandableTable = {
|
|
||||||
name: 'ExpandableTable',
|
|
||||||
inheritAttrs: false,
|
|
||||||
mixins: [BaseMixin],
|
|
||||||
props: initDefaultProps(ExpandableTableProps(), {
|
|
||||||
expandIconAsCell: false,
|
|
||||||
expandedRowClassName: () => '',
|
|
||||||
expandIconColumnIndex: 0,
|
|
||||||
defaultExpandAllRows: false,
|
|
||||||
defaultExpandedRowKeys: [],
|
|
||||||
childrenColumnName: 'children',
|
|
||||||
indentSize: 15,
|
|
||||||
}),
|
|
||||||
setup(props) {
|
|
||||||
const store = inject('table-store', () => ({}));
|
|
||||||
const {
|
|
||||||
data,
|
|
||||||
childrenColumnName,
|
|
||||||
defaultExpandAllRows,
|
|
||||||
expandedRowKeys,
|
|
||||||
defaultExpandedRowKeys,
|
|
||||||
getRowKey,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
let finalExpandedRowKeys = [];
|
|
||||||
let rows = [...data];
|
|
||||||
|
|
||||||
if (defaultExpandAllRows) {
|
|
||||||
for (let i = 0; i < rows.length; i += 1) {
|
|
||||||
const row = rows[i];
|
|
||||||
finalExpandedRowKeys.push(getRowKey(row, i));
|
|
||||||
rows = rows.concat(row[childrenColumnName] || []);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
finalExpandedRowKeys = expandedRowKeys || defaultExpandedRowKeys;
|
|
||||||
}
|
|
||||||
Object.assign(store, {
|
|
||||||
expandedRowsHeight: {},
|
|
||||||
expandedRowKeys: finalExpandedRowKeys,
|
|
||||||
});
|
|
||||||
return { store };
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.handleUpdated();
|
|
||||||
},
|
|
||||||
updated() {
|
|
||||||
this.handleUpdated();
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
expandedRowKeys(val) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.store.expandedRowKeys = val;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleUpdated() {
|
|
||||||
// We should record latest expanded rows to avoid multiple rows remove cause `onExpandedRowsChange` trigger many times
|
|
||||||
this.latestExpandedRows = null;
|
|
||||||
},
|
|
||||||
handleExpandChange(expanded, record, event, rowKey, destroy = false) {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
let { expandedRowKeys } = this.store;
|
|
||||||
|
|
||||||
if (expanded) {
|
|
||||||
// row was expaned
|
|
||||||
expandedRowKeys = [...expandedRowKeys, rowKey];
|
|
||||||
} else {
|
|
||||||
// row was collapse
|
|
||||||
const expandedRowIndex = expandedRowKeys.indexOf(rowKey);
|
|
||||||
if (expandedRowIndex !== -1) {
|
|
||||||
expandedRowKeys = remove(expandedRowKeys, rowKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.expandedRowKeys) {
|
|
||||||
this.store.expandedRowKeys = expandedRowKeys;
|
|
||||||
}
|
|
||||||
// De-dup of repeat call
|
|
||||||
if (!this.latestExpandedRows || !shallowEqual(this.latestExpandedRows, expandedRowKeys)) {
|
|
||||||
this.latestExpandedRows = expandedRowKeys;
|
|
||||||
this.__emit('expandedRowsChange', expandedRowKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!destroy) {
|
|
||||||
this.__emit('expand', expanded, record);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
renderExpandIndentCell(rows, fixed) {
|
|
||||||
const { prefixCls, expandIconAsCell } = this;
|
|
||||||
if (!expandIconAsCell || fixed === 'right' || !rows.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const iconColumn = {
|
|
||||||
key: 'rc-table-expand-icon-cell',
|
|
||||||
className: `${prefixCls}-expand-icon-th`,
|
|
||||||
title: '',
|
|
||||||
rowSpan: rows.length,
|
|
||||||
};
|
|
||||||
|
|
||||||
rows[0].unshift({ ...iconColumn, column: iconColumn });
|
|
||||||
},
|
|
||||||
|
|
||||||
renderExpandedRow(record, index, expandedRowRender, className, ancestorKeys, indent, fixed) {
|
|
||||||
const { prefixCls, expandIconAsCell, indentSize } = this;
|
|
||||||
const parentKey = ancestorKeys[ancestorKeys.length - 1];
|
|
||||||
const rowKey = `${parentKey}-extra-row`;
|
|
||||||
const components = {
|
|
||||||
body: {
|
|
||||||
row: 'tr',
|
|
||||||
cell: 'td',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let colCount;
|
|
||||||
if (fixed === 'left') {
|
|
||||||
colCount = this.columnManager.leftLeafColumns.value.length;
|
|
||||||
} else if (fixed === 'right') {
|
|
||||||
colCount = this.columnManager.rightLeafColumns.value.length;
|
|
||||||
} else {
|
|
||||||
colCount = this.columnManager.leafColumns.value.length;
|
|
||||||
}
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
key: 'extra-row',
|
|
||||||
customRender: () => {
|
|
||||||
const { expandedRowKeys } = this.store;
|
|
||||||
const expanded = expandedRowKeys.includes(parentKey);
|
|
||||||
return {
|
|
||||||
props: { colSpan: colCount },
|
|
||||||
children:
|
|
||||||
fixed !== 'right'
|
|
||||||
? expandedRowRender({ record, index, indent, expanded })
|
|
||||||
: ' ',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
if (expandIconAsCell && fixed !== 'right') {
|
|
||||||
columns.unshift({
|
|
||||||
key: 'expand-icon-placeholder',
|
|
||||||
customRender: () => null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow
|
|
||||||
key={rowKey}
|
|
||||||
columns={columns}
|
|
||||||
class={className}
|
|
||||||
rowKey={rowKey}
|
|
||||||
ancestorKeys={ancestorKeys}
|
|
||||||
prefixCls={`${prefixCls}-expanded-row`}
|
|
||||||
indentSize={indentSize}
|
|
||||||
indent={indent}
|
|
||||||
fixed={fixed}
|
|
||||||
components={components}
|
|
||||||
expandedRow
|
|
||||||
hasExpandIcon={() => {}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderRows(renderRows, rows, record, index, indent, fixed, parentKey, ancestorKeys) {
|
|
||||||
const { expandedRowClassName, expandedRowRender, childrenColumnName } = this;
|
|
||||||
const childrenData = record[childrenColumnName];
|
|
||||||
const nextAncestorKeys = [...ancestorKeys, parentKey];
|
|
||||||
const nextIndent = indent + 1;
|
|
||||||
|
|
||||||
if (expandedRowRender) {
|
|
||||||
rows.push(
|
|
||||||
this.renderExpandedRow(
|
|
||||||
record,
|
|
||||||
index,
|
|
||||||
expandedRowRender,
|
|
||||||
expandedRowClassName(record, index, indent),
|
|
||||||
nextAncestorKeys,
|
|
||||||
nextIndent,
|
|
||||||
fixed,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (childrenData) {
|
|
||||||
rows.push(...renderRows(childrenData, nextIndent, nextAncestorKeys));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { data, childrenColumnName } = this;
|
|
||||||
const props = getOptionProps(this);
|
|
||||||
const needIndentSpaced = data.some(record => record[childrenColumnName]);
|
|
||||||
|
|
||||||
return getSlot(this, 'default', {
|
|
||||||
props: {
|
|
||||||
...props,
|
|
||||||
...this.$attrs,
|
|
||||||
},
|
|
||||||
needIndentSpaced,
|
|
||||||
renderRows: this.renderRows,
|
|
||||||
handleExpandChange: this.handleExpandChange,
|
|
||||||
renderExpandIndentCell: this.renderExpandIndentCell,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ExpandableTable;
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
import { inject } from 'vue';
|
|
||||||
import PropTypes, { withUndefined } from '../../_util/vue-types';
|
|
||||||
import { measureScrollbar } from './utils';
|
|
||||||
import BaseTable from './BaseTable';
|
|
||||||
import classNames from '../../_util/classNames';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'HeadTable',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
fixed: withUndefined(PropTypes.oneOfType([PropTypes.string, PropTypes.looseBool])),
|
|
||||||
columns: PropTypes.array.isRequired,
|
|
||||||
tableClassName: PropTypes.string.isRequired,
|
|
||||||
handleBodyScrollLeft: PropTypes.func.isRequired,
|
|
||||||
expander: PropTypes.object.isRequired,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
table: inject('table', {}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const { columns, fixed, tableClassName, handleBodyScrollLeft, expander, table } = this;
|
|
||||||
const { prefixCls, scroll, showHeader, saveRef } = table;
|
|
||||||
let { useFixedHeader } = table;
|
|
||||||
const headStyle = {};
|
|
||||||
|
|
||||||
const scrollbarWidth = measureScrollbar({ direction: 'vertical' });
|
|
||||||
|
|
||||||
if (scroll.y) {
|
|
||||||
useFixedHeader = true;
|
|
||||||
// https://github.com/ant-design/ant-design/issues/17051
|
|
||||||
const scrollbarWidthOfHeader = measureScrollbar({ direction: 'horizontal', prefixCls });
|
|
||||||
// Add negative margin bottom for scroll bar overflow bug
|
|
||||||
if (scrollbarWidthOfHeader > 0 && !fixed) {
|
|
||||||
headStyle.marginBottom = `-${scrollbarWidthOfHeader}px`;
|
|
||||||
headStyle.paddingBottom = '0px';
|
|
||||||
// https://github.com/ant-design/ant-design/pull/19986
|
|
||||||
headStyle.minWidth = `${scrollbarWidth}px`;
|
|
||||||
// https://github.com/ant-design/ant-design/issues/17051
|
|
||||||
headStyle.overflowX = 'scroll';
|
|
||||||
headStyle.overflowY = scrollbarWidth === 0 ? 'hidden' : 'scroll';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!useFixedHeader || !showHeader) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key="headTable"
|
|
||||||
ref={fixed ? () => {} : saveRef('headTable')}
|
|
||||||
class={classNames(`${prefixCls}-header`, {
|
|
||||||
[`${prefixCls}-hide-scrollbar`]: scrollbarWidth > 0,
|
|
||||||
})}
|
|
||||||
style={headStyle}
|
|
||||||
onScroll={handleBodyScrollLeft}
|
|
||||||
>
|
|
||||||
<BaseTable
|
|
||||||
tableClassName={tableClassName}
|
|
||||||
hasHead
|
|
||||||
hasBody={false}
|
|
||||||
fixed={fixed}
|
|
||||||
columns={columns}
|
|
||||||
expander={expander}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,611 +0,0 @@
|
||||||
/* eslint-disable camelcase */
|
|
||||||
import {
|
|
||||||
provide,
|
|
||||||
markRaw,
|
|
||||||
defineComponent,
|
|
||||||
nextTick,
|
|
||||||
reactive,
|
|
||||||
computed,
|
|
||||||
ref,
|
|
||||||
onUpdated,
|
|
||||||
onMounted,
|
|
||||||
toRef,
|
|
||||||
} from 'vue';
|
|
||||||
import shallowequal from '../../_util/shallowequal';
|
|
||||||
import merge from 'lodash-es/merge';
|
|
||||||
import classes from '../../_util/component-classes';
|
|
||||||
import classNames from '../../_util/classNames';
|
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import { debounce, getColumnsKey, getDataAndAriaProps, validateValue } from './utils';
|
|
||||||
import warning from '../../_util/warning';
|
|
||||||
import addEventListener from '../../vc-util/Dom/addEventListener';
|
|
||||||
import HeadTable from './HeadTable';
|
|
||||||
import BodyTable from './BodyTable';
|
|
||||||
import ExpandableTable from './ExpandableTable';
|
|
||||||
import { initDefaultProps, getOptionProps } from '../../_util/props-util';
|
|
||||||
import BaseMixin from '../../_util/BaseMixin';
|
|
||||||
import { useLayoutState } from '../../_util/hooks/useLayoutState';
|
|
||||||
import useColumnManager from './useColumnManager';
|
|
||||||
import useStickyOffsets from './useStickyOffsets';
|
|
||||||
import { getCellFixedInfo } from './fixUtil';
|
|
||||||
import ResizeObserver from '../../vc-resize-observer';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'Table',
|
|
||||||
mixins: [BaseMixin],
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: initDefaultProps(
|
|
||||||
{
|
|
||||||
data: PropTypes.array,
|
|
||||||
useFixedHeader: PropTypes.looseBool,
|
|
||||||
columns: PropTypes.array,
|
|
||||||
prefixCls: PropTypes.string,
|
|
||||||
bodyStyle: PropTypes.object,
|
|
||||||
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
||||||
rowClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
||||||
customRow: PropTypes.func,
|
|
||||||
customHeaderRow: PropTypes.func,
|
|
||||||
// onRowClick: PropTypes.func,
|
|
||||||
// onRowDoubleClick: PropTypes.func,
|
|
||||||
// onRowContextMenu: PropTypes.func,
|
|
||||||
// onRowMouseEnter: PropTypes.func,
|
|
||||||
// onRowMouseLeave: PropTypes.func,
|
|
||||||
showHeader: PropTypes.looseBool,
|
|
||||||
title: PropTypes.func,
|
|
||||||
id: PropTypes.string,
|
|
||||||
footer: PropTypes.func,
|
|
||||||
emptyText: PropTypes.any,
|
|
||||||
scroll: PropTypes.object,
|
|
||||||
rowRef: PropTypes.func,
|
|
||||||
// getBodyWrapper: PropTypes.func,
|
|
||||||
components: PropTypes.shape({
|
|
||||||
table: PropTypes.any,
|
|
||||||
header: PropTypes.shape({
|
|
||||||
wrapper: PropTypes.any,
|
|
||||||
row: PropTypes.any,
|
|
||||||
cell: PropTypes.any,
|
|
||||||
}).loose,
|
|
||||||
body: PropTypes.shape({
|
|
||||||
wrapper: PropTypes.any,
|
|
||||||
row: PropTypes.any,
|
|
||||||
cell: PropTypes.any,
|
|
||||||
}).loose,
|
|
||||||
}).loose,
|
|
||||||
expandIconAsCell: PropTypes.looseBool,
|
|
||||||
expandedRowKeys: PropTypes.array,
|
|
||||||
expandedRowClassName: PropTypes.func,
|
|
||||||
defaultExpandAllRows: PropTypes.looseBool,
|
|
||||||
defaultExpandedRowKeys: PropTypes.array,
|
|
||||||
expandIconColumnIndex: PropTypes.number,
|
|
||||||
expandedRowRender: PropTypes.func,
|
|
||||||
childrenColumnName: PropTypes.string,
|
|
||||||
indentSize: PropTypes.number,
|
|
||||||
expandRowByClick: PropTypes.looseBool,
|
|
||||||
expandIcon: PropTypes.func,
|
|
||||||
tableLayout: PropTypes.string,
|
|
||||||
transformCellText: PropTypes.func,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
data: [],
|
|
||||||
useFixedHeader: false,
|
|
||||||
rowKey: 'key',
|
|
||||||
rowClassName: () => '',
|
|
||||||
prefixCls: 'rc-table',
|
|
||||||
bodyStyle: {},
|
|
||||||
showHeader: true,
|
|
||||||
scroll: {},
|
|
||||||
rowRef: () => null,
|
|
||||||
emptyText: () => 'No Data',
|
|
||||||
customHeaderRow: () => {},
|
|
||||||
},
|
|
||||||
),
|
|
||||||
setup(props) {
|
|
||||||
const columnManager = useColumnManager(toRef(props, 'columns'));
|
|
||||||
const colsKeys = computed(() => getColumnsKey(columnManager.leafColumns.value));
|
|
||||||
const [colsWidths, updateColsWidths] = useLayoutState(new Map());
|
|
||||||
const pureColWidths = computed(() =>
|
|
||||||
colsKeys.value.map(columnKey => colsWidths.value.get(columnKey)),
|
|
||||||
);
|
|
||||||
const stickyOffsets = useStickyOffsets(pureColWidths, columnManager.leafColumns);
|
|
||||||
const onColumnResize = (columnKey, width) => {
|
|
||||||
updateColsWidths(widths => {
|
|
||||||
if (widths.get(columnKey) !== width) {
|
|
||||||
const newWidths = new Map(widths);
|
|
||||||
newWidths.set(columnKey, width);
|
|
||||||
return newWidths;
|
|
||||||
}
|
|
||||||
return widths;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const fixedInfoList = computed(() =>
|
|
||||||
columnManager.leafColumns.value.map((_, colIndex) =>
|
|
||||||
getCellFixedInfo(colIndex, colIndex, columnManager.leafColumns.value, stickyOffsets.value),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
const store = reactive({
|
|
||||||
currentHoverKey: null,
|
|
||||||
fixedColumnsHeadRowsHeight: [],
|
|
||||||
fixedColumnsBodyRowsHeight: {},
|
|
||||||
expandedRowsHeight: {},
|
|
||||||
expandedRowKeys: [],
|
|
||||||
columnManager,
|
|
||||||
fixedInfoList,
|
|
||||||
stickyOffsets,
|
|
||||||
});
|
|
||||||
provide('table-store', store);
|
|
||||||
const bodyRef = ref();
|
|
||||||
const pingedLeft = ref(false);
|
|
||||||
const pingedRight = ref(false);
|
|
||||||
const horizonScroll = computed(() => props.scroll && validateValue(props.scroll.x));
|
|
||||||
const onScroll = currentTarget => {
|
|
||||||
const { scrollWidth, clientWidth, scrollLeft } = currentTarget;
|
|
||||||
pingedLeft.value = scrollLeft > 0;
|
|
||||||
pingedRight.value = scrollLeft < scrollWidth - clientWidth;
|
|
||||||
};
|
|
||||||
onUpdated(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
horizonScroll.value && onScroll(bodyRef.value.$el);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
horizonScroll.value && onScroll(bodyRef.value.$el);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const onFullTableResize = () => {
|
|
||||||
horizonScroll.value && onScroll(bodyRef.value.$el);
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
bodyRef,
|
|
||||||
store,
|
|
||||||
onColumnResize,
|
|
||||||
columnManager,
|
|
||||||
onScroll,
|
|
||||||
pingedLeft,
|
|
||||||
pingedRight,
|
|
||||||
onFullTableResize,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
this.preData = [...this.data];
|
|
||||||
return {
|
|
||||||
sComponents: markRaw(
|
|
||||||
merge(
|
|
||||||
{
|
|
||||||
table: 'table',
|
|
||||||
header: {
|
|
||||||
wrapper: 'thead',
|
|
||||||
row: 'tr',
|
|
||||||
cell: 'th',
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
wrapper: 'tbody',
|
|
||||||
row: 'tr',
|
|
||||||
cell: 'td',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
this.components,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
dataLen() {
|
|
||||||
return this.$props.data.length;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
components() {
|
|
||||||
this._components = merge(
|
|
||||||
{
|
|
||||||
table: 'table',
|
|
||||||
header: {
|
|
||||||
wrapper: 'thead',
|
|
||||||
row: 'tr',
|
|
||||||
cell: 'th',
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
wrapper: 'tbody',
|
|
||||||
row: 'tr',
|
|
||||||
cell: 'td',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
this.components,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
dataLen(val, preVal) {
|
|
||||||
if ((val === 0 || preVal === 0) && this.hasScrollX()) {
|
|
||||||
nextTick(() => {
|
|
||||||
this.resetScrollX();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
provide('table', this);
|
|
||||||
|
|
||||||
this.setScrollPosition('left');
|
|
||||||
|
|
||||||
this.debouncedWindowResize = debounce(this.handleWindowResize, 150);
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.columnManager.isAnyColumnsFixed.value) {
|
|
||||||
this.handleWindowResize();
|
|
||||||
this.resizeEvent = addEventListener(window, 'resize', this.debouncedWindowResize);
|
|
||||||
}
|
|
||||||
// https://github.com/ant-design/ant-design/issues/11635
|
|
||||||
if (this.ref_headTable) {
|
|
||||||
this.ref_headTable.scrollLeft = 0;
|
|
||||||
}
|
|
||||||
if (this.ref_bodyTable) {
|
|
||||||
this.ref_bodyTable.scrollLeft = 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
updated() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.columnManager.isAnyColumnsFixed.value) {
|
|
||||||
this.handleWindowResize();
|
|
||||||
if (!this.resizeEvent) {
|
|
||||||
this.resizeEvent = addEventListener(window, 'resize', this.debouncedWindowResize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeUnmount() {
|
|
||||||
if (this.resizeEvent) {
|
|
||||||
this.resizeEvent.remove();
|
|
||||||
}
|
|
||||||
if (this.debouncedWindowResize) {
|
|
||||||
this.debouncedWindowResize.cancel();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getRowKey(record, index) {
|
|
||||||
const rowKey = this.rowKey;
|
|
||||||
const key = typeof rowKey === 'function' ? rowKey(record, index) : record[rowKey];
|
|
||||||
warning(
|
|
||||||
key !== undefined,
|
|
||||||
'Each record in table should have a unique `key` prop,' +
|
|
||||||
'or set `rowKey` to an unique primary key.',
|
|
||||||
);
|
|
||||||
return key === undefined ? index : key;
|
|
||||||
},
|
|
||||||
|
|
||||||
setScrollPosition(position) {
|
|
||||||
this.scrollPosition = position;
|
|
||||||
if (this.tableNode) {
|
|
||||||
const { prefixCls } = this;
|
|
||||||
if (position === 'both') {
|
|
||||||
classes(this.tableNode)
|
|
||||||
.remove(new RegExp(`^${prefixCls}-scroll-position-.+$`))
|
|
||||||
.add(`${prefixCls}-scroll-position-left`)
|
|
||||||
.add(`${prefixCls}-scroll-position-right`);
|
|
||||||
} else {
|
|
||||||
classes(this.tableNode)
|
|
||||||
.remove(new RegExp(`^${prefixCls}-scroll-position-.+$`))
|
|
||||||
.add(`${prefixCls}-scroll-position-${position}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setScrollPositionClassName() {
|
|
||||||
const node = this.ref_bodyTable;
|
|
||||||
const scrollToLeft = node.scrollLeft === 0;
|
|
||||||
const scrollToRight =
|
|
||||||
node.scrollLeft + 1 >=
|
|
||||||
node.children[0].getBoundingClientRect().width - node.getBoundingClientRect().width;
|
|
||||||
if (scrollToLeft && scrollToRight) {
|
|
||||||
this.setScrollPosition('both');
|
|
||||||
} else if (scrollToLeft) {
|
|
||||||
this.setScrollPosition('left');
|
|
||||||
} else if (scrollToRight) {
|
|
||||||
this.setScrollPosition('right');
|
|
||||||
} else if (this.scrollPosition !== 'middle') {
|
|
||||||
this.setScrollPosition('middle');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
isTableLayoutFixed() {
|
|
||||||
const { tableLayout, columns = [], useFixedHeader, scroll = {} } = this.$props;
|
|
||||||
if (typeof tableLayout !== 'undefined') {
|
|
||||||
return tableLayout === 'fixed';
|
|
||||||
}
|
|
||||||
// if one column is ellipsis, use fixed table layout to fix align issue
|
|
||||||
if (columns.some(({ ellipsis }) => !!ellipsis)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// if header fixed, use fixed table layout to fix align issue
|
|
||||||
if (useFixedHeader || scroll.y) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// if scroll.x is number/px/% width value, we should fixed table layout
|
|
||||||
// to avoid long word layout broken issue
|
|
||||||
if (scroll.x && scroll.x !== true && scroll.x !== 'max-content') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleWindowResize() {
|
|
||||||
this.syncFixedTableRowHeight();
|
|
||||||
this.setScrollPositionClassName();
|
|
||||||
},
|
|
||||||
|
|
||||||
syncFixedTableRowHeight() {
|
|
||||||
const tableRect = this.tableNode.getBoundingClientRect();
|
|
||||||
// If tableNode's height less than 0, suppose it is hidden and don't recalculate rowHeight.
|
|
||||||
// see: https://github.com/ant-design/ant-design/issues/4836
|
|
||||||
if (tableRect.height !== undefined && tableRect.height <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { prefixCls } = this;
|
|
||||||
const headRows = this.ref_headTable
|
|
||||||
? this.ref_headTable.querySelectorAll('thead')
|
|
||||||
: this.ref_bodyTable.querySelectorAll('thead');
|
|
||||||
const bodyRows = this.ref_bodyTable.querySelectorAll(`.${prefixCls}-row`) || [];
|
|
||||||
const fixedColumnsHeadRowsHeight = [].map.call(headRows, row => {
|
|
||||||
return row.getBoundingClientRect().height
|
|
||||||
? row.getBoundingClientRect().height - 0.5
|
|
||||||
: 'auto';
|
|
||||||
});
|
|
||||||
const state = this.store;
|
|
||||||
const fixedColumnsBodyRowsHeight = [].reduce.call(
|
|
||||||
bodyRows,
|
|
||||||
(acc, row) => {
|
|
||||||
const rowKey = row.getAttribute('data-row-key');
|
|
||||||
const height =
|
|
||||||
row.getBoundingClientRect().height ||
|
|
||||||
state.fixedColumnsBodyRowsHeight[rowKey] ||
|
|
||||||
'auto';
|
|
||||||
acc[rowKey] = height;
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
shallowequal(state.fixedColumnsHeadRowsHeight, fixedColumnsHeadRowsHeight) &&
|
|
||||||
shallowequal(state.fixedColumnsBodyRowsHeight, fixedColumnsBodyRowsHeight)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.store.fixedColumnsHeadRowsHeight = fixedColumnsHeadRowsHeight;
|
|
||||||
this.store.fixedColumnsBodyRowsHeight = fixedColumnsBodyRowsHeight;
|
|
||||||
},
|
|
||||||
|
|
||||||
resetScrollX() {
|
|
||||||
if (this.ref_headTable) {
|
|
||||||
this.ref_headTable.scrollLeft = 0;
|
|
||||||
}
|
|
||||||
if (this.ref_bodyTable) {
|
|
||||||
this.ref_bodyTable.scrollLeft = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
hasScrollX() {
|
|
||||||
const { scroll = {} } = this;
|
|
||||||
return 'x' in scroll;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleBodyScrollLeft(e) {
|
|
||||||
const target = e.target;
|
|
||||||
const { scroll = {} } = this;
|
|
||||||
const { ref_headTable, ref_bodyTable } = this;
|
|
||||||
if (target.scrollLeft !== this.lastScrollLeft && scroll.x) {
|
|
||||||
if (target === ref_bodyTable && ref_headTable) {
|
|
||||||
ref_headTable.scrollLeft = target.scrollLeft;
|
|
||||||
} else if (target === ref_headTable && ref_bodyTable) {
|
|
||||||
ref_bodyTable.scrollLeft = target.scrollLeft;
|
|
||||||
}
|
|
||||||
this.setScrollPositionClassName();
|
|
||||||
}
|
|
||||||
// Remember last scrollLeft for scroll direction detecting.
|
|
||||||
this.lastScrollLeft = target.scrollLeft;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleBodyScrollTop(e) {
|
|
||||||
const target = e.target;
|
|
||||||
// Fix https://github.com/ant-design/ant-design/issues/9033
|
|
||||||
if (e.currentTarget !== target) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { scroll = {} } = this;
|
|
||||||
const { ref_headTable, ref_bodyTable, ref_fixedColumnsBodyLeft, ref_fixedColumnsBodyRight } =
|
|
||||||
this;
|
|
||||||
if (target.scrollTop !== this.lastScrollTop && scroll.y && target !== ref_headTable) {
|
|
||||||
const scrollTop = target.scrollTop;
|
|
||||||
if (ref_fixedColumnsBodyLeft && target !== ref_fixedColumnsBodyLeft) {
|
|
||||||
ref_fixedColumnsBodyLeft.scrollTop = scrollTop;
|
|
||||||
}
|
|
||||||
if (ref_fixedColumnsBodyRight && target !== ref_fixedColumnsBodyRight) {
|
|
||||||
ref_fixedColumnsBodyRight.scrollTop = scrollTop;
|
|
||||||
}
|
|
||||||
if (ref_bodyTable && target !== ref_bodyTable) {
|
|
||||||
ref_bodyTable.scrollTop = scrollTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Remember last scrollTop for scroll direction detecting.
|
|
||||||
this.lastScrollTop = target.scrollTop;
|
|
||||||
},
|
|
||||||
handleBodyScroll(e) {
|
|
||||||
this.onScroll(e.target);
|
|
||||||
this.handleBodyScrollLeft(e);
|
|
||||||
this.handleBodyScrollTop(e);
|
|
||||||
},
|
|
||||||
handleWheel(event) {
|
|
||||||
const { scroll = {} } = this.$props;
|
|
||||||
if (window.navigator.userAgent.match(/Trident\/7\./) && scroll.y) {
|
|
||||||
event.preventDefault();
|
|
||||||
const wd = event.deltaY;
|
|
||||||
const target = event.target;
|
|
||||||
const {
|
|
||||||
ref_bodyTable: bodyTable,
|
|
||||||
ref_fixedColumnsBodyLeft: fixedColumnsBodyLeft,
|
|
||||||
ref_fixedColumnsBodyRight: fixedColumnsBodyRight,
|
|
||||||
} = this;
|
|
||||||
let scrollTop = 0;
|
|
||||||
|
|
||||||
if (this.lastScrollTop) {
|
|
||||||
scrollTop = this.lastScrollTop + wd;
|
|
||||||
} else {
|
|
||||||
scrollTop = wd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fixedColumnsBodyLeft && target !== fixedColumnsBodyLeft) {
|
|
||||||
fixedColumnsBodyLeft.scrollTop = scrollTop;
|
|
||||||
}
|
|
||||||
if (fixedColumnsBodyRight && target !== fixedColumnsBodyRight) {
|
|
||||||
fixedColumnsBodyRight.scrollTop = scrollTop;
|
|
||||||
}
|
|
||||||
if (bodyTable && target !== bodyTable) {
|
|
||||||
bodyTable.scrollTop = scrollTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// saveChildrenRef(name, node) {
|
|
||||||
// this[`ref_${name}`] = node;
|
|
||||||
// },
|
|
||||||
saveRef(name) {
|
|
||||||
return node => {
|
|
||||||
this[`ref_${name}`] = node;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
saveTableNodeRef(node) {
|
|
||||||
this.tableNode = node;
|
|
||||||
},
|
|
||||||
renderMainTable() {
|
|
||||||
const { scroll, prefixCls } = this;
|
|
||||||
const isAnyColumnsFixed = this.columnManager.isAnyColumnsFixed.value;
|
|
||||||
const scrollable = isAnyColumnsFixed || scroll.x || scroll.y;
|
|
||||||
|
|
||||||
const table = [
|
|
||||||
this.renderTable({
|
|
||||||
columns: this.columnManager.groupedColumns.value,
|
|
||||||
isAnyColumnsFixed,
|
|
||||||
}),
|
|
||||||
this.renderEmptyText(),
|
|
||||||
this.renderFooter(),
|
|
||||||
];
|
|
||||||
|
|
||||||
return scrollable ? (
|
|
||||||
<ResizeObserver onResize={this.onFullTableResize}>
|
|
||||||
<div class={`${prefixCls}-scroll`}>{table}</div>
|
|
||||||
</ResizeObserver>
|
|
||||||
) : (
|
|
||||||
table
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTable(options) {
|
|
||||||
const { columns, isAnyColumnsFixed } = options;
|
|
||||||
const { prefixCls, scroll = {} } = this;
|
|
||||||
const tableClassName = scroll.x ? `${prefixCls}-fixed` : '';
|
|
||||||
|
|
||||||
const headTable = (
|
|
||||||
<HeadTable
|
|
||||||
key="head"
|
|
||||||
columns={columns}
|
|
||||||
tableClassName={tableClassName}
|
|
||||||
handleBodyScrollLeft={this.handleBodyScrollLeft}
|
|
||||||
expander={this.expander}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const bodyTable = (
|
|
||||||
<BodyTable
|
|
||||||
key="body"
|
|
||||||
columns={columns}
|
|
||||||
tableClassName={tableClassName}
|
|
||||||
getRowKey={this.getRowKey}
|
|
||||||
handleWheel={this.handleWheel}
|
|
||||||
handleBodyScroll={this.handleBodyScroll}
|
|
||||||
expander={this.expander}
|
|
||||||
isAnyColumnsFixed={isAnyColumnsFixed}
|
|
||||||
ref="bodyRef"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return [headTable, bodyTable];
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTitle() {
|
|
||||||
const { title, prefixCls, data } = this;
|
|
||||||
return title ? (
|
|
||||||
<div class={`${prefixCls}-title`} key="title">
|
|
||||||
{title(data)}
|
|
||||||
</div>
|
|
||||||
) : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
renderFooter() {
|
|
||||||
const { footer, prefixCls, data } = this;
|
|
||||||
return footer ? (
|
|
||||||
<div class={`${prefixCls}-footer`} key="footer">
|
|
||||||
{footer(data)}
|
|
||||||
</div>
|
|
||||||
) : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
renderEmptyText() {
|
|
||||||
const { emptyText, prefixCls, data } = this;
|
|
||||||
if (data.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const emptyClassName = `${prefixCls}-placeholder`;
|
|
||||||
return (
|
|
||||||
<div class={emptyClassName} key="emptyText">
|
|
||||||
{typeof emptyText === 'function' ? emptyText() : emptyText}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const props = { ...getOptionProps(this), ...this.$attrs };
|
|
||||||
const { columnManager, getRowKey } = this;
|
|
||||||
const prefixCls = props.prefixCls;
|
|
||||||
|
|
||||||
const tableClassName = classNames(props.prefixCls, props.class, {
|
|
||||||
[`${prefixCls}-fixed-header`]: props.useFixedHeader || (props.scroll && props.scroll.y),
|
|
||||||
[`${prefixCls}-scroll-position-left ${prefixCls}-scroll-position-right`]:
|
|
||||||
this.scrollPosition === 'both',
|
|
||||||
[`${prefixCls}-scroll-position-${this.scrollPosition}`]: this.scrollPosition !== 'both',
|
|
||||||
[`${prefixCls}-layout-fixed`]: this.isTableLayoutFixed(),
|
|
||||||
[`${prefixCls}-ping-left`]: this.pingedLeft,
|
|
||||||
[`${prefixCls}-ping-right`]: this.pingedRight,
|
|
||||||
});
|
|
||||||
const dataAndAriaProps = getDataAndAriaProps(props);
|
|
||||||
const expandableTableProps = {
|
|
||||||
...props,
|
|
||||||
columnManager,
|
|
||||||
getRowKey,
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<ExpandableTable
|
|
||||||
{...expandableTableProps}
|
|
||||||
v-slots={{
|
|
||||||
default: expander => {
|
|
||||||
this.expander = expander;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={this.saveTableNodeRef}
|
|
||||||
class={tableClassName}
|
|
||||||
style={props.style}
|
|
||||||
id={props.id}
|
|
||||||
{...dataAndAriaProps}
|
|
||||||
>
|
|
||||||
{this.renderTitle()}
|
|
||||||
<div class={`${prefixCls}-content`}>{this.renderMainTable()}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
import { inject, toRaw } from 'vue';
|
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import get from 'lodash-es/get';
|
|
||||||
import classNames from '../../_util/classNames';
|
|
||||||
import { isValidElement } from '../../_util/props-util';
|
|
||||||
|
|
||||||
function isInvalidRenderCellText(text) {
|
|
||||||
return (
|
|
||||||
text && !isValidElement(text) && Object.prototype.toString.call(text) === '[object Object]'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'TableCell',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
record: PropTypes.object,
|
|
||||||
prefixCls: PropTypes.string,
|
|
||||||
index: PropTypes.number,
|
|
||||||
indent: PropTypes.number,
|
|
||||||
indentSize: PropTypes.number,
|
|
||||||
column: PropTypes.object,
|
|
||||||
expandIcon: PropTypes.any,
|
|
||||||
component: PropTypes.any,
|
|
||||||
colIndex: PropTypes.number,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
table: inject('table', {}),
|
|
||||||
store: inject('table-store', {}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleClick(e) {
|
|
||||||
const {
|
|
||||||
record,
|
|
||||||
column: { onCellClick },
|
|
||||||
} = this;
|
|
||||||
if (onCellClick) {
|
|
||||||
onCellClick(record, e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
record,
|
|
||||||
indentSize,
|
|
||||||
prefixCls,
|
|
||||||
indent,
|
|
||||||
index,
|
|
||||||
expandIcon,
|
|
||||||
column,
|
|
||||||
component: BodyCell,
|
|
||||||
} = this;
|
|
||||||
const fixedInfoList = this.store.fixedInfoList || [];
|
|
||||||
const fixedInfo = fixedInfoList[this.colIndex] || {};
|
|
||||||
const { fixLeft, fixRight, firstFixLeft, lastFixLeft, firstFixRight, lastFixRight } = fixedInfo;
|
|
||||||
// ====================== Fixed =======================
|
|
||||||
const fixedStyle = {};
|
|
||||||
const isFixLeft = typeof fixLeft === 'number';
|
|
||||||
const isFixRight = typeof fixRight === 'number';
|
|
||||||
|
|
||||||
if (isFixLeft) {
|
|
||||||
fixedStyle.position = 'sticky';
|
|
||||||
fixedStyle.left = `${fixLeft}px`;
|
|
||||||
}
|
|
||||||
if (isFixRight) {
|
|
||||||
fixedStyle.position = 'sticky';
|
|
||||||
fixedStyle.right = `${fixRight}px`;
|
|
||||||
}
|
|
||||||
const { dataIndex, customRender, className = '' } = column;
|
|
||||||
const { transformCellText, prefixCls: rootPrefixCls } = this.table;
|
|
||||||
// We should return undefined if no dataIndex is specified, but in order to
|
|
||||||
// be compatible with object-path's behavior, we return the record object instead.
|
|
||||||
let text;
|
|
||||||
if (typeof dataIndex === 'number') {
|
|
||||||
text = get(record, dataIndex);
|
|
||||||
} else if (!dataIndex || dataIndex.length === 0) {
|
|
||||||
text = record;
|
|
||||||
} else {
|
|
||||||
text = get(record, dataIndex);
|
|
||||||
}
|
|
||||||
let tdProps = {
|
|
||||||
onClick: this.handleClick,
|
|
||||||
};
|
|
||||||
let colSpan;
|
|
||||||
let rowSpan;
|
|
||||||
|
|
||||||
if (customRender) {
|
|
||||||
text = customRender({ text, record, index, column });
|
|
||||||
if (isInvalidRenderCellText(text)) {
|
|
||||||
tdProps = text.props || text.attrs || tdProps;
|
|
||||||
({ colSpan, rowSpan } = tdProps);
|
|
||||||
text = text.children;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (column.customCell) {
|
|
||||||
tdProps = { ...tdProps, ...column.customCell(record, index) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix https://github.com/ant-design/ant-design/issues/1202
|
|
||||||
if (isInvalidRenderCellText(text)) {
|
|
||||||
text = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transformCellText) {
|
|
||||||
text = transformCellText({ text, column, record, index });
|
|
||||||
}
|
|
||||||
|
|
||||||
const indentText = expandIcon ? (
|
|
||||||
<span
|
|
||||||
style={{ paddingLeft: `${indentSize * indent}px` }}
|
|
||||||
class={`${prefixCls}-indent indent-level-${indent}`}
|
|
||||||
/>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
if (rowSpan === 0 || colSpan === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (column.align) {
|
|
||||||
tdProps.style = { textAlign: column.align, ...tdProps.style };
|
|
||||||
}
|
|
||||||
|
|
||||||
const cellClassName = classNames(className, column.class, {
|
|
||||||
[`${prefixCls}-cell-ellipsis`]: !!column.ellipsis,
|
|
||||||
// 如果有宽度,增加断行处理
|
|
||||||
// https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241
|
|
||||||
[`${prefixCls}-cell-break-word`]: !!column.width,
|
|
||||||
[`${rootPrefixCls}-cell-fix-left`]: isFixLeft,
|
|
||||||
[`${rootPrefixCls}-cell-fix-left-first`]: firstFixLeft,
|
|
||||||
[`${rootPrefixCls}-cell-fix-left-last`]: lastFixLeft,
|
|
||||||
[`${rootPrefixCls}-cell-fix-right`]: isFixRight,
|
|
||||||
[`${rootPrefixCls}-cell-fix-right-first`]: firstFixRight,
|
|
||||||
[`${rootPrefixCls}-cell-fix-right-last`]: lastFixRight,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (column.ellipsis) {
|
|
||||||
if (typeof text === 'string') {
|
|
||||||
tdProps.title = text;
|
|
||||||
} else if (text) {
|
|
||||||
// const { props: textProps } = text;
|
|
||||||
// if (textProps && textProps.children && typeof textProps.children === 'string') {
|
|
||||||
// tdProps.attrs.title = textProps.children;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BodyCell
|
|
||||||
class={cellClassName}
|
|
||||||
{...tdProps}
|
|
||||||
{...{ style: { ...(tdProps.style || {}), ...fixedStyle } }}
|
|
||||||
>
|
|
||||||
{indentText}
|
|
||||||
{expandIcon}
|
|
||||||
{toRaw(text)}
|
|
||||||
</BodyCell>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
import { inject } from 'vue';
|
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import TableHeaderRow from './TableHeaderRow';
|
|
||||||
|
|
||||||
function parseHeaderRows(rootColumns) {
|
|
||||||
const rows = [];
|
|
||||||
|
|
||||||
function fillRowCells(columns, colIndex, rowIndex = 0) {
|
|
||||||
// Init rows
|
|
||||||
rows[rowIndex] = rows[rowIndex] || [];
|
|
||||||
|
|
||||||
let currentColIndex = colIndex;
|
|
||||||
const colSpans = columns.filter(Boolean).map(column => {
|
|
||||||
const cell = {
|
|
||||||
key: column.key,
|
|
||||||
className: column.className || column.class || '',
|
|
||||||
children: column.title,
|
|
||||||
column,
|
|
||||||
colStart: currentColIndex,
|
|
||||||
};
|
|
||||||
|
|
||||||
let colSpan = 1;
|
|
||||||
|
|
||||||
const subColumns = column.children;
|
|
||||||
if (subColumns && subColumns.length > 0) {
|
|
||||||
colSpan = fillRowCells(subColumns, currentColIndex, rowIndex + 1).reduce(
|
|
||||||
(total, count) => total + count,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
cell.hasSubColumns = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('colSpan' in column) {
|
|
||||||
({ colSpan } = column);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('rowSpan' in column) {
|
|
||||||
cell.rowSpan = column.rowSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell.colSpan = colSpan;
|
|
||||||
cell.colEnd = cell.colStart + colSpan - 1;
|
|
||||||
rows[rowIndex].push(cell);
|
|
||||||
|
|
||||||
currentColIndex += colSpan;
|
|
||||||
|
|
||||||
return colSpan;
|
|
||||||
});
|
|
||||||
|
|
||||||
return colSpans;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate `rows` cell data
|
|
||||||
fillRowCells(rootColumns, 0);
|
|
||||||
|
|
||||||
// Handle `rowSpan`
|
|
||||||
const rowCount = rows.length;
|
|
||||||
for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
|
|
||||||
rows[rowIndex].forEach(cell => {
|
|
||||||
if (!('rowSpan' in cell) && !cell.hasSubColumns) {
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
cell.rowSpan = rowCount - rowIndex;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'TableHeader',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
fixed: PropTypes.string,
|
|
||||||
columns: PropTypes.array.isRequired,
|
|
||||||
expander: PropTypes.object.isRequired,
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
table: inject('table', {}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { sComponents: components, prefixCls, showHeader, customHeaderRow } = this.table;
|
|
||||||
const { expander, columns, fixed } = this;
|
|
||||||
|
|
||||||
if (!showHeader) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const rows = parseHeaderRows(this.columns);
|
|
||||||
expander.renderExpandIndentCell(rows, fixed);
|
|
||||||
|
|
||||||
const HeaderWrapper = components.header.wrapper;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<HeaderWrapper class={`${prefixCls}-thead`}>
|
|
||||||
{rows.map((row, index) => (
|
|
||||||
<TableHeaderRow
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
key={index}
|
|
||||||
index={index}
|
|
||||||
fixed={fixed}
|
|
||||||
columns={columns}
|
|
||||||
rows={rows}
|
|
||||||
row={row}
|
|
||||||
components={components}
|
|
||||||
customHeaderRow={customHeaderRow}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</HeaderWrapper>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
import classNames from '../../_util/classNames';
|
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import { computed, inject } from 'vue';
|
|
||||||
import { getCellFixedInfo } from './fixUtil';
|
|
||||||
|
|
||||||
const TableHeaderRow = {
|
|
||||||
name: 'TableHeaderRow',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
index: PropTypes.number,
|
|
||||||
fixed: PropTypes.string,
|
|
||||||
columns: PropTypes.array,
|
|
||||||
rows: PropTypes.array,
|
|
||||||
row: PropTypes.array,
|
|
||||||
components: PropTypes.object,
|
|
||||||
customHeaderRow: PropTypes.func,
|
|
||||||
prefixCls: PropTypes.prefixCls,
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const store = inject('table-store', () => ({}));
|
|
||||||
return {
|
|
||||||
height: computed(() => {
|
|
||||||
const { fixedColumnsHeadRowsHeight } = store;
|
|
||||||
const { columns, rows, fixed } = props;
|
|
||||||
const headerHeight = fixedColumnsHeadRowsHeight[0];
|
|
||||||
|
|
||||||
if (!fixed) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (headerHeight && columns) {
|
|
||||||
if (headerHeight === 'auto') {
|
|
||||||
return 'auto';
|
|
||||||
}
|
|
||||||
return `${headerHeight / rows.length}px`;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}),
|
|
||||||
store,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const { row, index, height, components, customHeaderRow, prefixCls } = this;
|
|
||||||
const HeaderRow = components.header.row;
|
|
||||||
const HeaderCell = components.header.cell;
|
|
||||||
const rowProps = customHeaderRow(
|
|
||||||
row.map(cell => cell.column),
|
|
||||||
index,
|
|
||||||
);
|
|
||||||
const customStyle = rowProps ? rowProps.style : {};
|
|
||||||
const style = { height, ...customStyle };
|
|
||||||
if (style.height === null) {
|
|
||||||
delete style.height;
|
|
||||||
}
|
|
||||||
const { stickyOffsets, columnManager } = this.store;
|
|
||||||
return (
|
|
||||||
<HeaderRow {...rowProps} style={style}>
|
|
||||||
{row.map((cell, i) => {
|
|
||||||
const { column, isLast, children, className, ...cellProps } = cell;
|
|
||||||
const fixedInfo = getCellFixedInfo(
|
|
||||||
cell.colStart,
|
|
||||||
cell.colEnd,
|
|
||||||
columnManager.leafColumns,
|
|
||||||
stickyOffsets,
|
|
||||||
);
|
|
||||||
const customProps = column.customHeaderCell ? column.customHeaderCell(column) : {};
|
|
||||||
const headerCellProps = {
|
|
||||||
...cellProps,
|
|
||||||
...customProps,
|
|
||||||
key: column.key || column.dataIndex || i,
|
|
||||||
};
|
|
||||||
if (headerCellProps.colSpan === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (column.align) {
|
|
||||||
headerCellProps.style = { ...customProps.style, textAlign: column.align };
|
|
||||||
}
|
|
||||||
// ====================== Fixed =======================
|
|
||||||
const { fixLeft, fixRight, firstFixLeft, lastFixLeft, firstFixRight, lastFixRight } =
|
|
||||||
fixedInfo;
|
|
||||||
const fixedStyle = {};
|
|
||||||
const isFixLeft = typeof fixLeft === 'number';
|
|
||||||
const isFixRight = typeof fixRight === 'number';
|
|
||||||
|
|
||||||
if (isFixLeft) {
|
|
||||||
fixedStyle.position = 'sticky';
|
|
||||||
fixedStyle.left = `${fixLeft}px`;
|
|
||||||
}
|
|
||||||
if (isFixRight) {
|
|
||||||
fixedStyle.position = 'sticky';
|
|
||||||
fixedStyle.right = `${fixRight}px`;
|
|
||||||
}
|
|
||||||
headerCellProps.class = classNames(
|
|
||||||
customProps.class,
|
|
||||||
customProps.className,
|
|
||||||
column.class,
|
|
||||||
column.className,
|
|
||||||
{
|
|
||||||
[`${prefixCls}-align-${column.align}`]: !!column.align,
|
|
||||||
[`${prefixCls}-row-cell-ellipsis`]: !!column.ellipsis,
|
|
||||||
[`${prefixCls}-row-cell-break-word`]: !!column.width,
|
|
||||||
[`${prefixCls}-row-cell-last`]: isLast,
|
|
||||||
[`${prefixCls}-cell-fix-left`]: isFixLeft,
|
|
||||||
[`${prefixCls}-cell-fix-left-first`]: firstFixLeft,
|
|
||||||
[`${prefixCls}-cell-fix-left-last`]: lastFixLeft,
|
|
||||||
[`${prefixCls}-cell-fix-right`]: isFixRight,
|
|
||||||
[`${prefixCls}-cell-fix-right-first`]: firstFixRight,
|
|
||||||
[`${prefixCls}-cell-fix-right-last`]: lastFixRight,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
headerCellProps.style = { ...(headerCellProps.style || {}), ...fixedStyle };
|
|
||||||
if (typeof HeaderCell === 'function') {
|
|
||||||
return HeaderCell(headerCellProps, children);
|
|
||||||
}
|
|
||||||
return <HeaderCell {...headerCellProps}>{children}</HeaderCell>;
|
|
||||||
})}
|
|
||||||
</HeaderRow>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TableHeaderRow;
|
|
||||||
|
|
@ -1,302 +0,0 @@
|
||||||
import classNames from '../../_util/classNames';
|
|
||||||
import PropTypes, { withUndefined } from '../../_util/vue-types';
|
|
||||||
import TableCell from './TableCell';
|
|
||||||
import { initDefaultProps, findDOMNode } from '../../_util/props-util';
|
|
||||||
import BaseMixin from '../../_util/BaseMixin';
|
|
||||||
import { computed, inject } from 'vue';
|
|
||||||
function noop() {}
|
|
||||||
const TableRow = {
|
|
||||||
name: 'TableRow',
|
|
||||||
inheritAttrs: false,
|
|
||||||
mixins: [BaseMixin],
|
|
||||||
props: initDefaultProps(
|
|
||||||
{
|
|
||||||
customRow: PropTypes.func,
|
|
||||||
// onRowClick: PropTypes.func,
|
|
||||||
// onRowDoubleClick: PropTypes.func,
|
|
||||||
// onRowContextMenu: PropTypes.func,
|
|
||||||
// onRowMouseEnter: PropTypes.func,
|
|
||||||
// onRowMouseLeave: PropTypes.func,
|
|
||||||
record: PropTypes.object,
|
|
||||||
prefixCls: PropTypes.string,
|
|
||||||
// onHover: PropTypes.func,
|
|
||||||
columns: PropTypes.array,
|
|
||||||
index: PropTypes.number,
|
|
||||||
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
||||||
className: PropTypes.string,
|
|
||||||
indent: PropTypes.number,
|
|
||||||
indentSize: PropTypes.number,
|
|
||||||
hasExpandIcon: PropTypes.func,
|
|
||||||
fixed: withUndefined(PropTypes.oneOfType([PropTypes.string, PropTypes.looseBool])),
|
|
||||||
renderExpandIcon: PropTypes.func,
|
|
||||||
renderExpandIconCell: PropTypes.func,
|
|
||||||
components: PropTypes.any,
|
|
||||||
expandedRow: PropTypes.looseBool,
|
|
||||||
isAnyColumnsFixed: PropTypes.looseBool,
|
|
||||||
ancestorKeys: PropTypes.array.isRequired,
|
|
||||||
expandIconColumnIndex: PropTypes.number,
|
|
||||||
expandRowByClick: PropTypes.looseBool,
|
|
||||||
// visible: PropTypes.looseBool,
|
|
||||||
// hovered: PropTypes.looseBool,
|
|
||||||
// height: PropTypes.any,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// expandIconColumnIndex: 0,
|
|
||||||
// expandRowByClick: false,
|
|
||||||
hasExpandIcon() {},
|
|
||||||
renderExpandIcon() {},
|
|
||||||
renderExpandIconCell() {},
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
setup(props) {
|
|
||||||
const store = inject('table-store', () => ({}));
|
|
||||||
const visible = computed(() => {
|
|
||||||
const { expandedRowKeys } = store;
|
|
||||||
const { ancestorKeys } = props;
|
|
||||||
return !!(ancestorKeys.length === 0 || ancestorKeys.every(k => expandedRowKeys.includes(k)));
|
|
||||||
});
|
|
||||||
const height = computed(() => {
|
|
||||||
const { expandedRowsHeight, fixedColumnsBodyRowsHeight } = store;
|
|
||||||
const { fixed, rowKey } = props;
|
|
||||||
|
|
||||||
if (!fixed) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expandedRowsHeight[rowKey]) {
|
|
||||||
return expandedRowsHeight[rowKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fixedColumnsBodyRowsHeight[rowKey]) {
|
|
||||||
return fixedColumnsBodyRowsHeight[rowKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
const hovered = computed(() => {
|
|
||||||
const { currentHoverKey } = store;
|
|
||||||
const { rowKey } = props;
|
|
||||||
return currentHoverKey === rowKey;
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
store,
|
|
||||||
visible,
|
|
||||||
hovered,
|
|
||||||
height,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
this.rowRef = null;
|
|
||||||
return {
|
|
||||||
shouldRender: this.visible,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
if (this.shouldRender) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.saveRowRef();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
visible(val) {
|
|
||||||
if (val) {
|
|
||||||
this.shouldRender = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
updated() {
|
|
||||||
if (this.shouldRender && !this.rowRef) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.saveRowRef();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onRowClick(event, rowPropFunc = noop) {
|
|
||||||
const { record, index } = this;
|
|
||||||
this.__emit('rowClick', record, index, event);
|
|
||||||
rowPropFunc(event);
|
|
||||||
},
|
|
||||||
|
|
||||||
onRowDoubleClick(event, rowPropFunc = noop) {
|
|
||||||
const { record, index } = this;
|
|
||||||
this.__emit('rowDoubleClick', record, index, event);
|
|
||||||
rowPropFunc(event);
|
|
||||||
},
|
|
||||||
|
|
||||||
onContextMenu(event, rowPropFunc = noop) {
|
|
||||||
const { record, index } = this;
|
|
||||||
this.__emit('rowContextmenu', record, index, event);
|
|
||||||
rowPropFunc(event);
|
|
||||||
},
|
|
||||||
|
|
||||||
onMouseEnter(event, rowPropFunc = noop) {
|
|
||||||
const { record, index, rowKey } = this;
|
|
||||||
this.__emit('hover', true, rowKey);
|
|
||||||
this.__emit('rowMouseenter', record, index, event);
|
|
||||||
rowPropFunc(event);
|
|
||||||
},
|
|
||||||
|
|
||||||
onMouseLeave(event, rowPropFunc = noop) {
|
|
||||||
const { record, index, rowKey } = this;
|
|
||||||
this.__emit('hover', false, rowKey);
|
|
||||||
this.__emit('rowMouseleave', record, index, event);
|
|
||||||
rowPropFunc(event);
|
|
||||||
},
|
|
||||||
|
|
||||||
setExpandedRowHeight() {
|
|
||||||
const { store, rowKey } = this;
|
|
||||||
let { expandedRowsHeight } = store;
|
|
||||||
const height = this.rowRef.getBoundingClientRect().height;
|
|
||||||
expandedRowsHeight = {
|
|
||||||
...expandedRowsHeight,
|
|
||||||
[rowKey]: height,
|
|
||||||
};
|
|
||||||
store.expandedRowsHeight = expandedRowsHeight;
|
|
||||||
},
|
|
||||||
|
|
||||||
setRowHeight() {
|
|
||||||
const { store, rowKey } = this;
|
|
||||||
const { fixedColumnsBodyRowsHeight } = store;
|
|
||||||
const height = this.rowRef.getBoundingClientRect().height;
|
|
||||||
store.fixedColumnsBodyRowsHeight = {
|
|
||||||
...fixedColumnsBodyRowsHeight,
|
|
||||||
[rowKey]: height,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
getStyle() {
|
|
||||||
const { height, visible } = this;
|
|
||||||
let style = this.$attrs.style || {};
|
|
||||||
if (height) {
|
|
||||||
style = { ...style, height };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!visible && !style.display) {
|
|
||||||
style = { ...style, display: 'none' };
|
|
||||||
}
|
|
||||||
|
|
||||||
return style;
|
|
||||||
},
|
|
||||||
|
|
||||||
saveRowRef() {
|
|
||||||
this.rowRef = findDOMNode(this);
|
|
||||||
const { isAnyColumnsFixed, fixed, expandedRow, ancestorKeys } = this;
|
|
||||||
if (!isAnyColumnsFixed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!fixed && expandedRow) {
|
|
||||||
this.setExpandedRowHeight();
|
|
||||||
}
|
|
||||||
if (!fixed && ancestorKeys.length >= 0) {
|
|
||||||
this.setRowHeight();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (!this.shouldRender) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
prefixCls,
|
|
||||||
columns,
|
|
||||||
record,
|
|
||||||
rowKey,
|
|
||||||
index,
|
|
||||||
customRow = noop,
|
|
||||||
indent,
|
|
||||||
indentSize,
|
|
||||||
hovered,
|
|
||||||
height,
|
|
||||||
visible,
|
|
||||||
components,
|
|
||||||
hasExpandIcon,
|
|
||||||
renderExpandIcon,
|
|
||||||
renderExpandIconCell,
|
|
||||||
} = this;
|
|
||||||
const BodyRow = components.body.row;
|
|
||||||
const BodyCell = components.body.cell;
|
|
||||||
|
|
||||||
let className = this.$attrs.class || '';
|
|
||||||
|
|
||||||
if (hovered) {
|
|
||||||
className += ` ${prefixCls}-hover`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cells = [];
|
|
||||||
|
|
||||||
renderExpandIconCell(cells);
|
|
||||||
|
|
||||||
for (let i = 0; i < columns.length; i += 1) {
|
|
||||||
const column = columns[i];
|
|
||||||
|
|
||||||
cells.push(
|
|
||||||
<TableCell
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
record={record}
|
|
||||||
indentSize={indentSize}
|
|
||||||
indent={indent}
|
|
||||||
index={index}
|
|
||||||
colIndex={i}
|
|
||||||
column={column}
|
|
||||||
key={column.key || column.dataIndex}
|
|
||||||
expandIcon={hasExpandIcon(i) && renderExpandIcon()}
|
|
||||||
component={BodyCell}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
class: customClass,
|
|
||||||
className: customClassName,
|
|
||||||
style: customStyle,
|
|
||||||
...rowProps
|
|
||||||
} = customRow(record, index) || {};
|
|
||||||
|
|
||||||
let style = { height: typeof height === 'number' ? `${height}px` : height };
|
|
||||||
|
|
||||||
if (!visible) {
|
|
||||||
style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
style = { ...style, ...customStyle };
|
|
||||||
const rowClassName = classNames(
|
|
||||||
prefixCls,
|
|
||||||
className,
|
|
||||||
`${prefixCls}-level-${indent}`,
|
|
||||||
customClassName,
|
|
||||||
customClass,
|
|
||||||
);
|
|
||||||
const bodyRowProps = {
|
|
||||||
...rowProps,
|
|
||||||
style,
|
|
||||||
onClick: e => {
|
|
||||||
this.onRowClick(e, rowProps.onClick);
|
|
||||||
},
|
|
||||||
onDblclick: e => {
|
|
||||||
this.onRowDoubleClick(e, rowProps.onDblclick);
|
|
||||||
},
|
|
||||||
onMouseenter: e => {
|
|
||||||
this.onMouseEnter(e, rowProps.onMouseenter);
|
|
||||||
},
|
|
||||||
onMouseleave: e => {
|
|
||||||
this.onMouseLeave(e, rowProps.onMouseleave);
|
|
||||||
},
|
|
||||||
onContextmenu: e => {
|
|
||||||
this.onContextMenu(e, rowProps.onContextmenu);
|
|
||||||
},
|
|
||||||
class: rowClassName,
|
|
||||||
'data-row-key': rowKey,
|
|
||||||
};
|
|
||||||
return <BodyRow {...bodyRowProps}>{cells}</BodyRow>;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TableRow;
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
export interface StickyOffsets {
|
|
||||||
left: readonly number[];
|
|
||||||
right: readonly number[];
|
|
||||||
isSticky?: boolean;
|
|
||||||
}
|
|
||||||
export type FixedType = 'left' | 'right' | boolean;
|
|
||||||
export interface FixedInfo {
|
|
||||||
fixLeft: number | false;
|
|
||||||
fixRight: number | false;
|
|
||||||
lastFixLeft: boolean;
|
|
||||||
firstFixRight: boolean;
|
|
||||||
|
|
||||||
// For Rtl Direction
|
|
||||||
lastFixRight: boolean;
|
|
||||||
firstFixLeft: boolean;
|
|
||||||
|
|
||||||
isSticky: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCellFixedInfo(
|
|
||||||
colStart: number,
|
|
||||||
colEnd: number,
|
|
||||||
columns: readonly { fixed?: FixedType }[],
|
|
||||||
stickyOffsets: StickyOffsets,
|
|
||||||
direction: 'ltr' | 'rtl',
|
|
||||||
): FixedInfo {
|
|
||||||
const startColumn = columns[colStart] || {};
|
|
||||||
const endColumn = columns[colEnd] || {};
|
|
||||||
|
|
||||||
let fixLeft: number;
|
|
||||||
let fixRight: number;
|
|
||||||
|
|
||||||
if (startColumn.fixed === 'left') {
|
|
||||||
fixLeft = stickyOffsets.left[colStart];
|
|
||||||
} else if (endColumn.fixed === 'right') {
|
|
||||||
fixRight = stickyOffsets.right[colEnd];
|
|
||||||
}
|
|
||||||
|
|
||||||
let lastFixLeft = false;
|
|
||||||
let firstFixRight = false;
|
|
||||||
|
|
||||||
let lastFixRight = false;
|
|
||||||
let firstFixLeft = false;
|
|
||||||
|
|
||||||
const nextColumn = columns[colEnd + 1];
|
|
||||||
const prevColumn = columns[colStart - 1];
|
|
||||||
|
|
||||||
if (direction === 'rtl') {
|
|
||||||
if (fixLeft !== undefined) {
|
|
||||||
const prevFixLeft = prevColumn && prevColumn.fixed === 'left';
|
|
||||||
firstFixLeft = !prevFixLeft;
|
|
||||||
} else if (fixRight !== undefined) {
|
|
||||||
const nextFixRight = nextColumn && nextColumn.fixed === 'right';
|
|
||||||
lastFixRight = !nextFixRight;
|
|
||||||
}
|
|
||||||
} else if (fixLeft !== undefined) {
|
|
||||||
const nextFixLeft = nextColumn && nextColumn.fixed === 'left';
|
|
||||||
lastFixLeft = !nextFixLeft;
|
|
||||||
} else if (fixRight !== undefined) {
|
|
||||||
const prevFixRight = prevColumn && prevColumn.fixed === 'right';
|
|
||||||
firstFixRight = !prevFixRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
fixLeft,
|
|
||||||
fixRight,
|
|
||||||
lastFixLeft,
|
|
||||||
firstFixRight,
|
|
||||||
lastFixRight,
|
|
||||||
firstFixLeft,
|
|
||||||
isSticky: stickyOffsets.isSticky,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
import { computed } from 'vue';
|
|
||||||
export default function useColumnManager(columns) {
|
|
||||||
const _leafColumns = (cls, fixed = false) => {
|
|
||||||
const leafColumns = [];
|
|
||||||
cls.forEach(column => {
|
|
||||||
column.fixed = fixed || column.fixed;
|
|
||||||
if (!column.children) {
|
|
||||||
leafColumns.push(column);
|
|
||||||
} else {
|
|
||||||
leafColumns.push(..._leafColumns(column.children, column.fixed));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return leafColumns;
|
|
||||||
};
|
|
||||||
|
|
||||||
// add appropriate rowspan and colspan to column
|
|
||||||
const groupedColumns = computed(() => {
|
|
||||||
const _groupColumns = (cls, currentRow = 0, parentColumn = {}, rows = [], fixed = false) => {
|
|
||||||
// track how many rows we got
|
|
||||||
rows[currentRow] = rows[currentRow] || [];
|
|
||||||
const grouped = [];
|
|
||||||
const setRowSpan = column => {
|
|
||||||
const rowSpan = rows.length - currentRow;
|
|
||||||
if (
|
|
||||||
column &&
|
|
||||||
!column.children && // parent columns.value are supposed to be one row
|
|
||||||
rowSpan > 1 &&
|
|
||||||
(!column.rowSpan || column.rowSpan < rowSpan)
|
|
||||||
) {
|
|
||||||
column.rowSpan = rowSpan;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
cls.forEach((column, index) => {
|
|
||||||
const newColumn = { ...column };
|
|
||||||
newColumn.fixed = fixed || column.fixed;
|
|
||||||
rows[currentRow].push(newColumn);
|
|
||||||
parentColumn.colSpan = parentColumn.colSpan || 0;
|
|
||||||
if (newColumn.children && newColumn.children.length > 0) {
|
|
||||||
newColumn.children = _groupColumns(
|
|
||||||
newColumn.children,
|
|
||||||
currentRow + 1,
|
|
||||||
newColumn,
|
|
||||||
rows,
|
|
||||||
newColumn.fixed,
|
|
||||||
);
|
|
||||||
parentColumn.colSpan += newColumn.colSpan;
|
|
||||||
} else {
|
|
||||||
parentColumn.colSpan += 1;
|
|
||||||
}
|
|
||||||
// update rowspan to all same row columns.value
|
|
||||||
for (let i = 0; i < rows[currentRow].length - 1; i += 1) {
|
|
||||||
setRowSpan(rows[currentRow][i]);
|
|
||||||
}
|
|
||||||
// last column, update rowspan immediately
|
|
||||||
if (index + 1 === cls.length) {
|
|
||||||
setRowSpan(newColumn);
|
|
||||||
}
|
|
||||||
grouped.push(newColumn);
|
|
||||||
});
|
|
||||||
return grouped;
|
|
||||||
};
|
|
||||||
return _groupColumns(columns.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
const isAnyColumnsFixed = computed(() => columns.value.some(column => !!column.fixed));
|
|
||||||
|
|
||||||
const isAnyColumnsLeftFixed = computed(() =>
|
|
||||||
columns.value.some(column => column.fixed === 'left' || column.fixed === true),
|
|
||||||
);
|
|
||||||
|
|
||||||
const isAnyColumnsRightFixed = computed(() =>
|
|
||||||
columns.value.some(column => column.fixed === 'right'),
|
|
||||||
);
|
|
||||||
|
|
||||||
const leftColumns = computed(() =>
|
|
||||||
groupedColumns.value.filter(column => column.fixed === 'left' || column.fixed === true),
|
|
||||||
);
|
|
||||||
|
|
||||||
const rightColumns = computed(() => {
|
|
||||||
return groupedColumns.value.filter(column => column.fixed === 'right');
|
|
||||||
});
|
|
||||||
|
|
||||||
const leafColumns = computed(() => {
|
|
||||||
return _leafColumns(columns.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
const leftLeafColumns = computed(() => _leafColumns(leftColumns.value));
|
|
||||||
|
|
||||||
const rightLeafColumns = computed(() => _leafColumns(rightColumns.value));
|
|
||||||
return {
|
|
||||||
groupedColumns,
|
|
||||||
isAnyColumnsFixed,
|
|
||||||
isAnyColumnsLeftFixed,
|
|
||||||
isAnyColumnsRightFixed,
|
|
||||||
leftColumns,
|
|
||||||
rightColumns,
|
|
||||||
leafColumns,
|
|
||||||
leftLeafColumns,
|
|
||||||
rightLeafColumns,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import { ref, watch } from 'vue';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get sticky column offset width
|
|
||||||
*/
|
|
||||||
function useStickyOffsets(colWidths, columns) {
|
|
||||||
const stickyOffsets = ref({
|
|
||||||
left: [],
|
|
||||||
right: [],
|
|
||||||
});
|
|
||||||
const columnCount = ref();
|
|
||||||
watch(
|
|
||||||
columns,
|
|
||||||
() => {
|
|
||||||
columnCount.value = columns.value.length;
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
);
|
|
||||||
watch([colWidths, columnCount], () => {
|
|
||||||
const leftOffsets = [];
|
|
||||||
const rightOffsets = [];
|
|
||||||
let left = 0;
|
|
||||||
let right = 0;
|
|
||||||
|
|
||||||
for (let start = 0; start < columnCount.value; start += 1) {
|
|
||||||
// Left offset
|
|
||||||
leftOffsets[start] = left;
|
|
||||||
left += colWidths.value[start] || 0;
|
|
||||||
|
|
||||||
// Right offset
|
|
||||||
const end = columnCount.value - start - 1;
|
|
||||||
rightOffsets[end] = right;
|
|
||||||
right += colWidths.value[end] || 0;
|
|
||||||
}
|
|
||||||
stickyOffsets.value = {
|
|
||||||
left: leftOffsets,
|
|
||||||
right: rightOffsets,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return stickyOffsets;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useStickyOffsets;
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
let scrollbarVerticalSize;
|
|
||||||
let scrollbarHorizontalSize;
|
|
||||||
|
|
||||||
// Measure scrollbar width for padding body during modal show/hide
|
|
||||||
const scrollbarMeasure = {
|
|
||||||
position: 'absolute',
|
|
||||||
top: '-9999px',
|
|
||||||
width: '50px',
|
|
||||||
height: '50px',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const INTERNAL_COL_DEFINE = 'RC_TABLE_INTERNAL_COL_DEFINE';
|
|
||||||
|
|
||||||
export function measureScrollbar({ direction = 'vertical', prefixCls }) {
|
|
||||||
if (typeof document === 'undefined' || typeof window === 'undefined') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const isVertical = direction === 'vertical';
|
|
||||||
if (isVertical && scrollbarVerticalSize) {
|
|
||||||
return scrollbarVerticalSize;
|
|
||||||
}
|
|
||||||
if (!isVertical && scrollbarHorizontalSize) {
|
|
||||||
return scrollbarHorizontalSize;
|
|
||||||
}
|
|
||||||
const scrollDiv = document.createElement('div');
|
|
||||||
Object.keys(scrollbarMeasure).forEach(scrollProp => {
|
|
||||||
scrollDiv.style[scrollProp] = scrollbarMeasure[scrollProp];
|
|
||||||
});
|
|
||||||
// apply hide scrollbar className ahead
|
|
||||||
scrollDiv.className = `${prefixCls}-hide-scrollbar scroll-div-append-to-body`;
|
|
||||||
|
|
||||||
// Append related overflow style
|
|
||||||
if (isVertical) {
|
|
||||||
scrollDiv.style.overflowY = 'scroll';
|
|
||||||
} else {
|
|
||||||
scrollDiv.style.overflowX = 'scroll';
|
|
||||||
}
|
|
||||||
document.body.appendChild(scrollDiv);
|
|
||||||
let size = 0;
|
|
||||||
if (isVertical) {
|
|
||||||
size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
|
||||||
scrollbarVerticalSize = size;
|
|
||||||
} else {
|
|
||||||
size = scrollDiv.offsetHeight - scrollDiv.clientHeight;
|
|
||||||
scrollbarHorizontalSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.removeChild(scrollDiv);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function debounce(func, wait, immediate) {
|
|
||||||
let timeout;
|
|
||||||
function debounceFunc(...args) {
|
|
||||||
const context = this;
|
|
||||||
// https://fb.me/react-event-pooling
|
|
||||||
if (args[0] && args[0].persist) {
|
|
||||||
args[0].persist();
|
|
||||||
}
|
|
||||||
const later = () => {
|
|
||||||
timeout = null;
|
|
||||||
if (!immediate) {
|
|
||||||
func.apply(context, args);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const callNow = immediate && !timeout;
|
|
||||||
clearTimeout(timeout);
|
|
||||||
timeout = setTimeout(later, wait);
|
|
||||||
if (callNow) {
|
|
||||||
func.apply(context, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debounceFunc.cancel = function cancel() {
|
|
||||||
if (timeout) {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
timeout = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return debounceFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function remove(array, item) {
|
|
||||||
const index = array.indexOf(item);
|
|
||||||
const front = array.slice(0, index);
|
|
||||||
const last = array.slice(index + 1, array.length);
|
|
||||||
return front.concat(last);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns only data- and aria- key/value pairs
|
|
||||||
* @param {object} props
|
|
||||||
*/
|
|
||||||
export function getDataAndAriaProps(props) {
|
|
||||||
return Object.keys(props).reduce((memo, key) => {
|
|
||||||
if (key.substr(0, 5) === 'data-' || key.substr(0, 5) === 'aria-') {
|
|
||||||
memo[key] = props[key];
|
|
||||||
}
|
|
||||||
return memo;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getColumnsKey(columns) {
|
|
||||||
const columnKeys = [];
|
|
||||||
|
|
||||||
columns.forEach(column => {
|
|
||||||
const { key, dataIndex } = column || {};
|
|
||||||
|
|
||||||
columnKeys.push(key !== undefined ? key : dataIndex);
|
|
||||||
});
|
|
||||||
|
|
||||||
return columnKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function validateValue(val) {
|
|
||||||
return val !== null && val !== undefined;
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue