chore: 调整 table 固定列和固定表头逻辑 (#7449)

This commit is contained in:
liaoxuezhi 2023-07-12 18:39:48 +08:00 committed by GitHub
parent ab3503c495
commit b40b2680bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1839 additions and 6079 deletions

View File

@ -1817,34 +1817,35 @@ popOver 的其它配置请参考 [popover](./popover)
## 属性表
| 属性名 | 类型 | 默认值 | 说明 | 版本 |
| ---------------- | -------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------- | --------------------------------- |
| type | `string` | | `"type"` 指定为 table 渲染器 | |
| title | `string` | | 标题 | |
| source | `string` | `${items}` | 数据源, 绑定当前环境变量 | |
| affixHeader | `boolean` | `true` | 是否固定表头 | |
| columnsTogglable | `auto` 或者 `boolean` | `auto` | 展示列显示开关, 自动即:列数量大于或等于 5 个时自动开启 | |
| placeholder | `string` 或者 `SchemaTpl` | `暂无数据` | 当没数据的时候的文字提示 | |
| className | `string` | `panel-default` | 外层 CSS 类名 | |
| tableClassName | `string` | `table-db table-striped` | 表格 CSS 类名 | |
| headerClassName | `string` | `Action.md-table-header` | 顶部外层 CSS 类名 | |
| footerClassName | `string` | `Action.md-table-footer` | 底部外层 CSS 类名 | |
| toolbarClassName | `string` | `Action.md-table-toolbar` | 工具栏 CSS 类名 | |
| columns | `Array<Column>` | | 用来设置列信息 | |
| combineNum | `number` | | 自动合并单元格 | |
| itemActions | Array<[Action](./action-button)> | | 悬浮行操作按钮组 | |
| itemCheckableOn | [表达式](../../docs/concepts/expression) | | 配置当前行是否可勾选的条件,要用 [表达式](../../docs/concepts/expression) | |
| itemDraggableOn | [表达式](../../docs/concepts/expression) | | 配置当前行是否可拖拽的条件,要用 [表达式](../../docs/concepts/expression) | |
| checkOnItemClick | `boolean` | `false` | 点击数据行是否可以勾选当前行 | |
| rowClassName | `string` | | 给行添加 CSS 类名 | |
| rowClassNameExpr | [模板](../../docs/concepts/template) | | 通过模板给行添加 CSS 类名 | |
| prefixRow | `Array` | | 顶部总结行 | |
| affixRow | `Array` | | 底部总结行 | |
| itemBadge | [`BadgeSchema`](./badge) | | 行角标配置 | |
| autoFillHeight | `boolean``{height: number}``{maxHeight: number}` | | 内容区域自适应高度,可选择自适应、固定高度和最大高度 | `maxHeight` 需要 `2.8.0` 以上版本 |
| resizable | `boolean` | `true` | 列宽度是否支持调整 | |
| selectable | `boolean` | `false` | 支持勾选 | |
| multiple | `boolean` | `false` | 勾选 icon 是否为多选样式`checkbox` 默认为`radio` | |
| 属性名 | 类型 | 默认值 | 说明 | 版本 |
| ---------------- | -------------------------------------------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------- |
| type | `string` | | `"type"` 指定为 table 渲染器 | |
| title | `string` | | 标题 | |
| source | `string` | `${items}` | 数据源, 绑定当前环境变量 | |
| tableLayout | `fixed` \| `auto` | `auto` | 表格元素的 table-layout 属性,设为 fixed 表示内容不会影响列的布局,当尝试修改列宽度时,自动转成 fixed 模式 | |
| affixHeader | `boolean` | `true` | 是否固定表头 | |
| columnsTogglable | `auto` 或者 `boolean` | `auto` | 展示列显示开关, 自动即:列数量大于或等于 5 个时自动开启 | |
| placeholder | `string` 或者 `SchemaTpl` | `暂无数据` | 当没数据的时候的文字提示 | |
| className | `string` | `panel-default` | 外层 CSS 类名 | |
| tableClassName | `string` | `table-db table-striped` | 表格 CSS 类名 | |
| headerClassName | `string` | `Action.md-table-header` | 顶部外层 CSS 类名 | |
| footerClassName | `string` | `Action.md-table-footer` | 底部外层 CSS 类名 | |
| toolbarClassName | `string` | `Action.md-table-toolbar` | 工具栏 CSS 类名 | |
| columns | `Array<Column>` | | 用来设置列信息 | |
| combineNum | `number` | | 自动合并单元格 | |
| itemActions | Array<[Action](./action-button)> | | 悬浮行操作按钮组 | |
| itemCheckableOn | [表达式](../../docs/concepts/expression) | | 配置当前行是否可勾选的条件,要用 [表达式](../../docs/concepts/expression) | |
| itemDraggableOn | [表达式](../../docs/concepts/expression) | | 配置当前行是否可拖拽的条件,要用 [表达式](../../docs/concepts/expression) | |
| checkOnItemClick | `boolean` | `false` | 点击数据行是否可以勾选当前行 | |
| rowClassName | `string` | | 给行添加 CSS 类名 | |
| rowClassNameExpr | [模板](../../docs/concepts/template) | | 通过模板给行添加 CSS 类名 | |
| prefixRow | `Array` | | 顶部总结行 | |
| affixRow | `Array` | | 底部总结行 | |
| itemBadge | [`BadgeSchema`](./badge) | | 行角标配置 | |
| autoFillHeight | `boolean``{height: number}``{maxHeight: number}` | | 内容区域自适应高度,可选择自适应、固定高度和最大高度 | `maxHeight` 需要 `2.8.0` 以上版本 |
| resizable | `boolean` | `true` | 列宽度是否支持调整 | |
| selectable | `boolean` | `false` | 支持勾选 | |
| multiple | `boolean` | `false` | 勾选 icon 是否为多选样式`checkbox` 默认为`radio` | |
### 列配置属性表

View File

@ -169,7 +169,7 @@ export default {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
sortable: true,
type: 'text',
toggled: true

View File

@ -78,7 +78,7 @@ export default {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
sortable: true,
type: 'text',
toggled: true

View File

@ -76,6 +76,7 @@ export default {
type: 'list',
label: 'List',
placeholder: '-',
width: 400,
size: 'sm',
listItem: {
title: '${title}',
@ -85,6 +86,7 @@ export default {
{
name: 'json',
width: 200,
type: 'json',
label: 'Json'
}

View File

@ -141,7 +141,7 @@ const table = {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
sortable: true,
type: 'text',
toggled: true,

View File

@ -12,7 +12,7 @@ export default {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
sortable: true,
type: 'text',
toggled: true

View File

@ -54,7 +54,8 @@ export default {
name: 'engine',
label: 'Rendering engine',
remark: 'Rendering engine',
groupName: 'A'
groupName: 'A',
fixed: 'left'
},
{
name: 'browser',
@ -65,7 +66,8 @@ export default {
name: 'platform',
label: 'Platform(s)',
remark: 'Platform(s)',
groupName: 'B'
groupName: 'B',
fixed: 'right'
},
{
name: 'version',

View File

@ -20,7 +20,7 @@ export default {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
type: 'text'
},
{

View File

@ -10,7 +10,7 @@ export default {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
type: 'text',
toggled: true
},

View File

@ -5,8 +5,7 @@ export default {
{
type: 'plain',
className: 'text-danger',
text:
'请通过上下左右键切换单元格,按 `Space` 键进入编辑模式,按 `Enter` 提交编辑,并最后点左上角的全部保存完成操作。'
text: '请通过上下左右键切换单元格,按 `Space` 键进入编辑模式,按 `Enter` 提交编辑,并最后点左上角的全部保存完成操作。'
},
{
type: 'crud',
@ -18,7 +17,7 @@ export default {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
sortable: true,
type: 'text',
toggled: true

View File

@ -29,6 +29,7 @@ export default {
}
]
},
affixHeader: true,
bulkActions: [
{
label: '批量删除',
@ -115,8 +116,7 @@ export default {
},
{
type: 'html',
html:
'<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
html: '<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
}
]
}

View File

@ -9,7 +9,7 @@ export default {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
type: 'text'
},
{

View File

@ -70,6 +70,7 @@ export default {
labelTpl: '${id} ${engine}',
orderBy: 'id',
orderDir: 'asc',
// affixHeader: false,
filter: {
title: '条件搜索',
submitText: '',

View File

@ -152,6 +152,7 @@ export default function (schema, schemaProps, showCode, envOverrides) {
tracker(eventTrack) {
console.debug('eventTrack', eventTrack);
},
affixOffsetTop: 50,
...envOverrides
};

View File

@ -61,7 +61,7 @@ const predefined = {
{
name: 'id',
label: 'ID',
width: 20,
width: 30,
sortable: true,
type: 'text',
toggled: true

View File

@ -55,6 +55,21 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
});
},
get toolbarData() {
// 包两层,主要是为了处理以下 case
// 里面放了个 formform 提交过来的时候不希望把 items 这些发送过来。
// 因为会把数据呈现在地址栏上。
return createObject(
createObject(self.data, {
...self.query,
items: self.items.concat(),
selectedItems: self.selectedItems.concat(),
unSelectedItems: self.unSelectedItems.concat()
}),
{}
);
},
get mergedData() {
return extendObject(self.data, {
...self.query,

View File

@ -45,6 +45,7 @@ export const Column = types
type: types.optional(types.string, 'plain'),
name: types.maybe(types.string),
value: types.frozen(),
id: '',
groupName: '',
toggled: false,
toggable: true,
@ -58,6 +59,7 @@ export const Column = types
fixed: '',
index: 0,
rawIndex: 0,
width: 0,
breakpoint: types.optional(types.frozen(), undefined),
pristine: types.optional(types.frozen(), undefined),
remark: types.optional(types.frozen(), undefined),
@ -84,6 +86,10 @@ export const Column = types
const table = getParent(self, 2) as ITableStore;
table.persistSaveToggledColumns();
},
setWidth(value: number) {
self.width = value;
}
}));
@ -350,6 +356,7 @@ export const TableStore = iRendererStore
formsRef: types.optional(types.array(types.frozen()), []),
maxKeepItemSelectionLength: Infinity,
keepItemSelectionOnPageChange: false,
useFixedLayout: false, // 默认 table-layout 为 auto主要这种方式下宽度设置不准确
// 导出 Excel 按钮的 loading 状态
exportExcelLoading: false,
searchFormExpanded: false // 用来控制搜索框是否展开了,那个自动根据 searchable 生成的表单 autoGenerateFilter
@ -425,31 +432,6 @@ export const TableStore = iRendererStore
);
}
function getLeftFixedColumns() {
if (self.dragging) {
return [];
}
let columns = getFilteredColumns().filter(item => item.fixed === 'left');
// 有才带过去,没有就不带了
if (columns.length) {
columns = getFilteredColumns().filter(
item => item.fixed === 'left' || /^__/.test(item.type)
);
}
return columns;
}
function getRightFixedColumns() {
if (self.dragging) {
return [];
}
return getFilteredColumns().filter(item => item.fixed === 'right');
}
function isSelected(row: IRow): boolean {
return !!~self.selectedRows.indexOf(row);
}
@ -597,10 +579,17 @@ export const TableStore = iRendererStore
(item.has.length === 1 && item.label === item.has[0].label)
? 2
: 1;
return {
...item,
rowSpan,
label: rowSpan === 2 ? item.label || item.has[0].label : item.label
label: rowSpan === 2 ? item.label || item.has[0].label : item.label,
fixed: item.has.every(column => column.fixed)
? item.has[0].fixed
: undefined,
get width() {
return item.has.reduce((a, b) => a + b.width, 0);
}
};
});
}
@ -647,14 +636,6 @@ export const TableStore = iRendererStore
return getFootableColumns();
},
get leftFixedColumns() {
return getLeftFixedColumns();
},
get rightFixedColumns() {
return getRightFixedColumns();
},
get toggableColumns() {
return getToggableColumns();
},
@ -771,11 +752,77 @@ export const TableStore = iRendererStore
});
return list;
},
get columnWidthReady() {
return getFilteredColumns().every(column => column.width);
},
getStickyStyles(column: IColumn, columns: Array<IColumn>) {
let stickyClassName = '';
const style: any = {};
const autoFixLeftColumns = ['__checkme', '__dragme', '__expandme'];
if (
column.fixed === 'left' ||
autoFixLeftColumns.includes(column.type)
) {
stickyClassName = 'is-sticky is-sticky-left';
let index = columns.indexOf(column) - 1;
if (
columns
.slice(index + 2)
.every(
col =>
!(
(col && col.fixed === 'left') ||
autoFixLeftColumns.includes(col.type)
)
)
) {
stickyClassName += ' is-sticky-last-left';
}
let left = 0;
while (index >= 0) {
const col = columns[index];
if (
(col && col.fixed === 'left') ||
autoFixLeftColumns.includes(col.type)
) {
left += col.width;
}
index--;
}
style.left = left;
} else if (column.fixed === 'right') {
stickyClassName = 'is-sticky is-sticky-right';
let right = 0;
let index = columns.indexOf(column) + 1;
if (columns.slice(0, index - 1).every(col => col.fixed !== 'right')) {
stickyClassName += ' is-sticky-first-right';
}
const len = columns.length;
while (index < len) {
const col = columns[index];
if (col && col.fixed === 'right') {
right += col.width;
}
index++;
}
style.right = right;
}
return [style, stickyClassName];
}
};
})
.actions(self => {
function update(config: Partial<STableStore>) {
function update(
config: Partial<STableStore> & {tableLayout?: 'fixed' | 'auto'}
) {
config.primaryField !== void 0 &&
(self.primaryField = config.primaryField);
config.selectable !== void 0 && (self.selectable = config.selectable);
@ -820,12 +867,6 @@ export const TableStore = iRendererStore
let columns: Array<SColumn> = config.columns
.filter(column => column)
.concat();
if (!columns.length) {
columns.push({
type: 'text',
label: '空'
});
}
// 更新列顺序afterCreate生命周期中更新columns不会触发组件的render
const key = getPersistDataKey(columns);
@ -846,42 +887,11 @@ export const TableStore = iRendererStore
}
}
columns.unshift({
type: '__expandme',
toggable: false,
className: 'Table-expandCell'
});
updateColumns(columns);
}
columns.unshift({
type: '__checkme',
fixed: 'left',
toggable: false,
className: 'Table-checkCell'
});
columns.unshift({
type: '__dragme',
toggable: false,
className: 'Table-dragCell'
});
columns = columns.map((item, index) => ({
...item,
index,
rawIndex: index - PARTITION_INDEX,
type: item.type || 'plain',
pristine: item,
toggled: item.toggled !== false,
breakpoint: item.breakpoint,
isPrimary: index === PARTITION_INDEX,
className: item.className || '',
/** 提前映射变量方便后续view中使用 */
label: isPureVariable(item.label)
? resolveVariableAndFilter(item.label, self.data)
: item.label
}));
self.columns.replace(columns as any);
if (config.tableLayout === 'fixed') {
self.useFixedLayout = true;
}
}
@ -917,7 +927,9 @@ export const TableStore = iRendererStore
columns = columns.map((item, index) => ({
...item,
id: guid(),
index,
width: 0,
rawIndex: index - PARTITION_INDEX,
type: item.type || 'plain',
pristine: item.pristine || item,
@ -931,10 +943,16 @@ export const TableStore = iRendererStore
}));
self.columns.replace(columns as any);
persistSaveToggledColumns();
// self.useFixedLayout = self.columns.some(
// column => column.pristine.width
// );
}
}
function invalidTableColumnWidth() {
self.columns.forEach(column => column.setWidth(0));
}
function combineCell(arr: Array<SRow>, keys: Array<string>): Array<SRow> {
if (!keys.length || !arr.length) {
return arr;
@ -1130,6 +1148,7 @@ export const TableStore = iRendererStore
}
self.dragging = false;
invalidTableColumnWidth(); // 更新内容需要重新计算表格布局
}
// 获取所有层级的子节点id
@ -1493,6 +1512,7 @@ export const TableStore = iRendererStore
return {
update,
updateColumns,
invalidTableColumnWidth,
initRows,
updateSelected,
toggleAll,
@ -1515,6 +1535,9 @@ export const TableStore = iRendererStore
persistSaveToggledColumns,
setSearchFormExpanded,
toggleSearchFormExpanded,
setUseFixedLayout(value: any) {
self.useFixedLayout = !!value;
},
// events
afterCreate() {

View File

@ -3970,9 +3970,9 @@
--Table-color: var(--table-body-color);
--Table-expandBtn-color: var(--colors-neutral-text-5);
--Table-fixed-zIndex: 5;
--Table-fixedLeft-boxShadow: 0.42rem 0 0.42rem -0.28rem rgba(0, 0, 0, 0.15);
--Table-fixedRight-boxShadow: -0.42rem 0 0.42rem -0.28rem rgba(0, 0, 0, 0.15);
--Table-fixedTop-boxShadow: var(--shadows-shadow-normal);
--Table-fixedLeft-boxShadow: inset 10px 0 8px -8px rgba(5, 5, 5, 0.06);
--Table-fixedRight-boxShadow: inset -10px 0 8px -8px rgba(5, 5, 5, 0.06);
--Table-fixedTop-boxShadow: inset 0 10px 8px -8px rgba(5, 5, 5, 0.06);
--Table-fontSize: var(--table-body-fontSize);
--Table-heading-bg: var(--table-title-bg-color);
--Table-heading-height: #{px2rem(40px)};

View File

@ -31,18 +31,11 @@
}
&-fixedTop {
position: absolute;
position: sticky;
background: var(--white);
z-index: -1;
opacity: 0;
box-shadow: var(--Cards-fixedTop-boxShadow);
// box-shadow: var(--Cards-fixedTop-boxShadow);
padding: var(--gap-sm);
&.in {
position: fixed;
opacity: 1;
z-index: $zindex-affix;
}
z-index: $zindex-sticky;
.#{$ns}Cards-toolbar {
margin-bottom: 0;

View File

@ -42,19 +42,12 @@
}
&-fixedTop {
position: absolute;
position: sticky;
background: var(--white);
z-index: -1;
opacity: 0;
box-shadow: var(--List-fixedTop-boxShadow);
z-index: $zindex-sticky;
// box-shadow: var(--List-fixedTop-boxShadow);
// padding: var(--gap-sm);
&.in {
position: fixed;
opacity: 1;
z-index: $zindex-affix;
}
.#{$ns}Cards-toolbar {
margin-bottom: 0;
}

View File

@ -3,6 +3,7 @@
align-items: center;
color: var(--text-color);
font-size: var(--fontSizeXs);
min-width: 50px;
&-line {
display: inline-block;
width: 100%;
@ -49,7 +50,6 @@
transition: width var(--animation-duration) ease;
border-radius: var(--Progress-borderRadius);
&.bg-info {
background: var(--Progress-line-theme-color);
}

View File

@ -8,82 +8,24 @@
margin-bottom: var(--gap-sm);
}
&-fixedLeft,
&-fixedRight {
position: absolute;
background: var(--Table-bg);
z-index: var(--Table-fixed-zIndex);
top: auto;
box-shadow: none;
&--autoFillHeight {
& > table thead {
position: sticky; // 简单实现表头吸顶效果不考虑 IE 11 不然太麻烦
top: 0;
z-index: 1; // 由于 badge 导致 tbody tr position: relative
}
}
}
&-fixedLeft {
// 还是改成默认不显示footable 展示的时候配置 固定列还没修复
left: 0;
top: -999999px;
&.in {
box-shadow: var(--Table-fixedLeft-boxShadow);
top: auto;
}
& > .#{$ns}Table-table {
> thead > tr > th:last-child,
> tbody > tr > td:last-child {
padding-right: var(--TableCell-paddingX);
}
// > thead > tr > th:last-child {
// border-right: var(--Table-thead-borderWidth) solid var(--Table-thead-borderColor);
// }
}
}
&-fixedRight {
// 还是改成默认不显示footable 展示的时候配置 固定列还没修复
right: 0;
top: -999999px;
&.in {
box-shadow: var(--Table-fixedRight-boxShadow);
top: auto;
}
& > .#{$ns}Table-table {
> thead > tr > th:first-child,
> tbody > tr > td:first-child {
padding-left: var(--TableCell-paddingX);
}
// > thead > tr > th:first-child {
// border-left: var(--Table-thead-borderWidth) solid var(--Table-thead-borderColor);
// }
}
}
&-fixedTop {
position: absolute;
position: sticky;
background: var(--Table-bg);
z-index: -1;
opacity: 0;
display: block;
opacity: 1;
z-index: $zindex-sticky;
&:after {
content: '';
position: absolute;
width: 100%;
box-shadow: var(--Table-fixedTop-boxShadow);
z-index: 10;
height: 1px;
margin-top: -3px;
z-index: 30;
height: 30px;
top: 100%;
pointer-events: none;
background-color: transparent;
margin-top: -2px;
}
// box-sizing: content-box;
@ -94,22 +36,11 @@
// box-sizing: border-box;
// }
&.in {
position: fixed;
opacity: 1;
z-index: $zindex-affix;
}
> .#{$ns}Table-fixedLeft,
> .#{$ns}Table-fixedRight {
z-index: $zindex-affix + 10;
// box-shadow: none;
background: transparent;
}
// &.in {
// // position: fixed;
// }
&.is-fakeHide {
> .#{$ns}Table-fixedLeft,
> .#{$ns}Table-fixedRight,
> .#{$ns}Table-wrapper {
visibility: hidden;
position: absolute;
@ -236,10 +167,6 @@
min-height: 0.01%;
overflow-x: auto;
transform: translateZ(0);
th {
position: relative;
}
}
&-content-colDragLine {
@ -253,7 +180,8 @@
opacity: 0.5;
z-index: $zindex-top;
&:hover {
&:hover,
&.is-resizing {
background: var(--primary);
}
}
@ -266,12 +194,54 @@
color: var(--Table-color);
background: var(--Table-bg);
border-spacing: 0;
border-collapse: collapse;
border-bottom: var(--Table-borderWidth) solid var(--Table-borderColor);
border-collapse: separate;
& th,
& td {
text-align: left;
border-bottom: var(--Table-borderWidth) solid var(--Table-borderColor);
&.is-sticky {
position: sticky !important;
z-index: 20;
background: inherit;
}
&.is-sticky-last-left:after {
position: absolute;
top: 0;
right: 0;
bottom: -1px;
width: 30px;
transform: translateX(100%);
transition: box-shadow 0.3s;
content: '';
pointer-events: none;
}
&.is-sticky-first-right:after {
position: absolute;
top: 0;
bottom: -1px;
left: 0;
width: 30px;
transform: translateX(-100%);
transition: box-shadow 0.3s;
content: '';
pointer-events: none;
}
}
&.table-fixed-left .is-sticky-last-left:after {
box-shadow: var(--Table-fixedLeft-boxShadow);
}
&.table-fixed-right .is-sticky-first-right:after {
box-shadow: var(--Table-fixedRight-boxShadow);
}
& th {
position: relative;
}
& th.text-center,
@ -290,6 +260,10 @@
padding-top: 0;
}
&--affixHeader thead {
visibility: collapse;
}
&--withCombine {
> thead > tr > th,
> tbody > tr > td {
@ -304,7 +278,7 @@
// reset
> tbody > tr {
@if $Table-strip-bg !=transparent {
@if $Table-strip-bg != transparent {
&.#{$ns}Table-tr--odd {
background: transparent;
}
@ -331,8 +305,9 @@
}
> thead > tr {
background: var(--Table-thead-bg);
> th {
background: var(--Table-thead-bg);
background: inherit;
padding: var(--TableCell-paddingY) var(--TableCell-paddingX);
text-align: left;
@ -399,6 +374,7 @@
> tbody > tr {
position: relative;
background: var(--Table-bg);
& + tr {
border-top: var(--Table-borderWidth) solid var(--Table-borderColor);
@ -415,6 +391,7 @@
color: var(--Table-thead-color);
font-weight: var(--fontWeightNormal);
white-space: nowrap;
border-right: var(--Table-thead-borderWidth) solid
var(--Table-thead-borderColor);
}
@ -533,51 +510,48 @@
}
}
.#{$ns}Table-divider2 {
content: '';
position: absolute;
height: px2rem(1px);
top: 50%;
width: px2rem(10px);
background: var(--Table-tree-borderColor);
}
.#{$ns}Table-divider3 {
position: absolute;
width: px2rem(1px);
top: 0;
bottom: 0;
height: 100%;
background: var(--Table-tree-borderColor);
}
@for $i from 2 through 10 {
tr.#{$ns}Table-tr--#{$i}th.is-expanded {
.#{$ns}Table-expandCell:before {
right: px2rem(7px) + px2rem(-18px) * ($i - 1);
left: px2rem(23px) + px2rem(18px) * ($i - 1);
}
}
tr.#{$ns}Table-tr--#{$i}th {
.#{$ns}Table-expandBtn {
position: relative;
right: -(px2rem(18px)) * ($i - 1);
left: px2rem(1px) + (px2rem(18px)) * ($i - 1);
}
.#{$ns}Table-expandCell + td {
position: relative;
.#{$ns}Table-divider2 {
left: px2rem(5px) + (px2rem(18px)) * ($i - 1);
}
&::before {
content: '';
position: absolute;
width: px2rem(1px);
top: 0;
bottom: 0;
left: px2rem(-8px) + px2rem(18px) * ($i - 2);
height: auto;
background: var(--Table-tree-borderColor);
}
&::after {
content: '';
position: absolute;
height: px2rem(1px);
top: 50%;
left: px2rem(-8px) + px2rem(18px) * ($i - 2);
width: px2rem(10px);
background: var(--Table-tree-borderColor);
}
padding-left: px2rem(18px) * $i - px2rem(18px);
.#{$ns}Table-divider3 {
left: px2rem(5px) + (px2rem(18px)) * ($i - 1);
}
}
tr.#{$ns}Table-tr--#{$i}th.is-expandable {
.#{$ns}Table-expandCell + td {
padding-left: px2rem(18px) * ($i - 1);
}
tr.#{$ns}Table-tr--#{$i}th.is-last .#{$ns}Table-divider3 {
height: 50%;
}
tr.#{$ns}Table-tr--#{$i}th.is-last:not(.is-expanded) {
@ -636,7 +610,7 @@
bottom: 0;
height: 100%;
background: var(--Table-tree-borderColor);
right: px2rem(7px) + px2rem(-18px) * ($i - 1);
left: px2rem(23px) + px2rem(18px) * ($i - 1);
}
}
}
@ -650,7 +624,7 @@
width: px2rem(1px);
top: 50%;
bottom: 0;
right: px2rem(7px);
left: px2rem(23px);
height: auto;
background: var(--Table-tree-borderColor);
}
@ -985,14 +959,10 @@
> .#{$ns}Table-content table thead {
position: sticky; // 简单实现表头吸顶效果不考虑 IE 11 不然太麻烦
top: 0;
z-index: 1; // 由于 badge 导致 tbody tr position: relative
z-index: 21; // 由于 badge 导致 tbody tr position: relative
}
}
> .#{$ns}Table-fixedTop {
display: none;
}
> .#{$ns}Table-footToolbar {
margin-bottom: 0;
}

View File

@ -407,86 +407,24 @@ exports[`Renderer:input table add 1`] = `
<div
class="cxd-Table-contentWrap"
>
<div
class="cxd-Table-fixedLeft"
/>
<div
class="cxd-Table-fixedRight"
>
<table
class="cxd-Table-table cxd-Table-table"
>
<thead>
<tr
class=""
>
<th
class="cxd-Table-operationCell"
data-index="5"
style="width: 1%;"
>
<div
class="cxd-TableCell--title v-middle nowrap"
style="width: 1%;"
>
<span
class="cxd-TplField"
>
<span>
操作
</span>
</span>
</div>
<div
class="cxd-Table-content-colDragLine"
/>
</th>
</tr>
</thead>
<tbody>
<tr
class="cxd-Table-tr--odd cxd-Table-tr--1th"
data-id="1"
data-index="0"
>
<td
class="v-middle nowrap"
style="width: 1%;"
>
<div
class="cxd-OperationField m-n"
>
<button
class="cxd-Button cxd-Button--link cxd-Button--size-sm"
type="button"
>
<icon-mock
classname="icon icon-check"
icon="check"
/>
</button>
<button
class="cxd-Button cxd-Button--link cxd-Button--size-sm"
type="button"
>
<icon-mock
classname="icon icon-close"
icon="close"
/>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div
class="cxd-Table-content"
style="position: relative;"
>
<table
class="cxd-Table-table"
>
<colgroup>
<col
data-index="3"
/>
<col
data-index="4"
/>
<col
data-index="5"
style="width: 1%;"
/>
</colgroup>
<thead>
<tr
class=""
@ -508,6 +446,7 @@ exports[`Renderer:input table add 1`] = `
</div>
<div
class="cxd-Table-content-colDragLine"
data-index="3"
/>
</th>
<th
@ -527,16 +466,16 @@ exports[`Renderer:input table add 1`] = `
</div>
<div
class="cxd-Table-content-colDragLine"
data-index="4"
/>
</th>
<th
class="cxd-Table-operationCell"
class="is-sticky is-sticky-right is-sticky-first-right cxd-Table-operationCell"
data-index="5"
style="width: 1%;"
style="right: 0px;"
>
<div
class="cxd-TableCell--title v-middle nowrap"
style="width: 1%;"
>
<span
class="cxd-TplField"
@ -548,6 +487,7 @@ exports[`Renderer:input table add 1`] = `
</div>
<div
class="cxd-Table-content-colDragLine"
data-index="5"
/>
</th>
</tr>
@ -630,8 +570,8 @@ exports[`Renderer:input table add 1`] = `
</div>
</td>
<td
class="v-middle nowrap"
style="width: 1%;"
class="v-middle nowrap is-sticky is-sticky-right is-sticky-first-right"
style="right: 0px;"
>
<div
class="cxd-OperationField m-n"
@ -659,46 +599,8 @@ exports[`Renderer:input table add 1`] = `
</tr>
</tbody>
</table>
<div
class="resize-sensor"
style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
class="resize-sensor-expand"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
style="position: absolute; left: 0px; top: 0px; width: 10px; height: 10px;"
/>
</div>
<div
class="resize-sensor-shrink"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
style="position: absolute; left: 0; top: 0; width: 200%; height: 200%"
/>
</div>
<div
class="resize-sensor-appear"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;animation-name: apearSensor; animation-duration: 0.2s;"
/>
</div>
</div>
<span />
</div>
</div>
<div
@ -837,19 +739,20 @@ exports[`Renderer:input-table cell selects delete 1`] = `
<div
class="cxd-Table-contentWrap"
>
<div
class="cxd-Table-fixedLeft"
/>
<div
class="cxd-Table-fixedRight"
/>
<div
class="cxd-Table-content"
style="position: relative;"
>
<table
class="cxd-Table-table"
>
<colgroup>
<col
data-index="3"
/>
<col
data-index="4"
/>
</colgroup>
<thead>
<tr
class=""
@ -871,6 +774,7 @@ exports[`Renderer:input-table cell selects delete 1`] = `
</div>
<div
class="cxd-Table-content-colDragLine"
data-index="3"
/>
</th>
<th
@ -890,6 +794,7 @@ exports[`Renderer:input-table cell selects delete 1`] = `
</div>
<div
class="cxd-Table-content-colDragLine"
data-index="4"
/>
</th>
</tr>
@ -992,46 +897,8 @@ exports[`Renderer:input-table cell selects delete 1`] = `
</tr>
</tbody>
</table>
<div
class="resize-sensor"
style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
class="resize-sensor-expand"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
style="position: absolute; left: 0px; top: 0px; width: 10px; height: 10px;"
/>
</div>
<div
class="resize-sensor-shrink"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
style="position: absolute; left: 0; top: 0; width: 200%; height: 200%"
/>
</div>
<div
class="resize-sensor-appear"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;animation-name: apearSensor; animation-duration: 0.2s;"
/>
</div>
</div>
<span />
</div>
</div>
</div>
@ -1253,19 +1120,17 @@ exports[`Renderer:input-table with combo column 1`] = `
<div
class="cxd-Table-contentWrap"
>
<div
class="cxd-Table-fixedLeft"
/>
<div
class="cxd-Table-fixedRight"
/>
<div
class="cxd-Table-content"
style="position: relative;"
>
<table
class="cxd-Table-table"
>
<colgroup>
<col
data-index="3"
/>
</colgroup>
<thead>
<tr
class=""
@ -1287,6 +1152,7 @@ exports[`Renderer:input-table with combo column 1`] = `
</div>
<div
class="cxd-Table-content-colDragLine"
data-index="3"
/>
</th>
</tr>
@ -1439,46 +1305,8 @@ exports[`Renderer:input-table with combo column 1`] = `
</tr>
</tbody>
</table>
<div
class="resize-sensor"
style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
class="resize-sensor-expand"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
style="position: absolute; left: 0px; top: 0px; width: 10px; height: 10px;"
/>
</div>
<div
class="resize-sensor-shrink"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
style="position: absolute; left: 0; top: 0; width: 200%; height: 200%"
/>
</div>
<div
class="resize-sensor-appear"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;animation-name: apearSensor; animation-duration: 0.2s;"
/>
</div>
</div>
<span />
</div>
</div>
</div>

View File

@ -102,6 +102,7 @@ exports[`Renderer:cards color 1`] = `
>
<div
class="cxd-Cards-fixedTop"
style="top: 0px;"
/>
<div
class="cxd-Cards-body cxd-Grid"

View File

@ -43,6 +43,10 @@ exports[`Renderer:list 1`] = `
<div
class="cxd-List"
>
<div
class="cxd-List-fixedTop"
style="top: 0px;"
/>
<div
class="cxd-List-items"
>
@ -800,9 +804,14 @@ exports[`Renderer:list with itemAction 1`] = `
class="cxd-List"
>
<div
class="cxd-List-heading"
class="cxd-List-fixedTop"
style="top: 0px;"
>
listTitleForTest
<div
class="cxd-List-heading"
>
listTitleForTest
</div>
</div>
<div
class="cxd-List-items"
@ -1030,6 +1039,10 @@ exports[`Renderer:list with listItem actions & actionsPosition 1`] = `
<div
class="cxd-List"
>
<div
class="cxd-List-fixedTop"
style="top: 0px;"
/>
<div
class="cxd-List-items"
>
@ -1228,6 +1241,10 @@ exports[`Renderer:list with listItem avatar & avatarClassName 1`] = `
<div
class="cxd-List"
>
<div
class="cxd-List-fixedTop"
style="top: 0px;"
/>
<div
class="cxd-List-items"
>
@ -1414,6 +1431,10 @@ exports[`Renderer:list with listItem title & titleClassName & subTitle & desc 1`
<div
class="cxd-List"
>
<div
class="cxd-List-fixedTop"
style="top: 0px;"
/>
<div
class="cxd-List-items"
>
@ -1635,6 +1656,7 @@ exports[`Renderer:list with title & header & footer & headerClassName & footerCl
>
<div
class="cxd-List-fixedTop"
style="top: 0px;"
>
<div
class="cxd-List-header headerTplClassName"
@ -1653,22 +1675,6 @@ exports[`Renderer:list with title & header & footer & headerClassName & footerCl
listTitleForTest
</div>
</div>
<div
class="cxd-List-header headerTplClassName"
>
<span
class="cxd-TplField"
>
<span>
头部标题
</span>
</span>
</div>
<div
class="cxd-List-heading"
>
listTitleForTest
</div>
<div
class="cxd-List-placeholder"
>

View File

@ -85,26 +85,32 @@ exports[`Renderer:Pagination 1`] = `
class="cxd-Table"
>
<div
class="cxd-Table-heading"
class="cxd-Table-fixedTop"
style="top: 0px;"
>
分页表格
<div
class="cxd-Table-heading"
>
分页表格
</div>
</div>
<div
class="cxd-Table-contentWrap"
>
<div
class="cxd-Table-fixedLeft"
/>
<div
class="cxd-Table-fixedRight"
/>
<div
class="cxd-Table-content"
style="position: relative;"
>
<table
class="cxd-Table-table"
>
<colgroup>
<col
data-index="3"
/>
<col
data-index="4"
/>
</colgroup>
<thead>
<tr
class=""
@ -126,6 +132,7 @@ exports[`Renderer:Pagination 1`] = `
</div>
<div
class="cxd-Table-content-colDragLine"
data-index="3"
/>
</th>
<th
@ -145,6 +152,7 @@ exports[`Renderer:Pagination 1`] = `
</div>
<div
class="cxd-Table-content-colDragLine"
data-index="4"
/>
</th>
</tr>
@ -200,119 +208,8 @@ exports[`Renderer:Pagination 1`] = `
</tr>
</tbody>
</table>
<div
class="resize-sensor"
style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
class="resize-sensor-expand"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
style="position: absolute; left: 0px; top: 0px; width: 10px; height: 10px;"
/>
</div>
<div
class="resize-sensor-shrink"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
>
<div
style="position: absolute; left: 0; top: 0; width: 200%; height: 200%"
/>
</div>
<div
class="resize-sensor-appear"
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;animation-name: apearSensor; animation-duration: 0.2s;"
/>
</div>
</div>
</div>
<div
class="cxd-Table-fixedTop"
>
<div
class="cxd-Table-heading"
>
分页表格
</div>
<div
class="cxd-Table-fixedLeft"
/>
<div
class="cxd-Table-fixedRight"
/>
<div
class="cxd-Table-wrapper"
>
<table
class="cxd-Table-table"
>
<colgroup>
<col
data-index="3"
/>
<col
data-index="4"
/>
</colgroup>
<thead>
<tr>
<th
class=""
data-index="3"
>
<div
class="cxd-TableCell--title"
>
<span
class="cxd-TplField"
>
<span>
Engine
</span>
</span>
</div>
<div
class="cxd-Table-content-colDragLine"
/>
</th>
<th
class=""
data-index="4"
>
<div
class="cxd-TableCell--title"
>
<span
class="cxd-TplField"
>
<span>
Version
</span>
</span>
</div>
<div
class="cxd-Table-content-colDragLine"
/>
</th>
</tr>
</thead>
</table>
</div>
<span />
</div>
</div>
</div>

View File

@ -99,6 +99,10 @@ exports[`Renderer:Picker base 1`] = `
<div
class="cxd-List cxd-Crud-body"
>
<div
class="cxd-List-fixedTop"
style="top: 0px;"
/>
<div
class="cxd-List-items"
>

View File

@ -2165,17 +2165,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
const $$editable = childProps.$$editable;
return render(`toolbar/${index}`, toolbar, {
// 包两层,主要是为了处理以下 case
// 里面放了个 formform 提交过来的时候不希望把 items 这些发送过来。
// 因为会把数据呈现在地址栏上。
data: createObject(
createObject(store.filterData, {
items: childProps.items,
selectedItems: store.selectedItems.concat(),
unSelectedItems: store.unSelectedItems.concat()
}),
{}
),
data: store.toolbarData,
page: store.page,
lastPage: store.lastPage,
perPage: store.perPage,

View File

@ -182,7 +182,6 @@ export default class Cards extends React.Component<GridProps, object> {
'selectable',
'headerClassName',
'footerClassName',
'fixAlignment',
'hideQuickSaveBtn',
'hideCheckToggler',
'itemCheckableOn',
@ -199,7 +198,6 @@ export default class Cards extends React.Component<GridProps, object> {
headerClassName: '',
footerClassName: '',
itemClassName: 'Grid-col--sm6 Grid-col--md4 Grid-col--lg3',
// fixAlignment: false,
hideCheckToggler: false,
masonryLayout: false,
affixHeader: true,
@ -209,9 +207,8 @@ export default class Cards extends React.Component<GridProps, object> {
dragTip?: HTMLElement;
sortable?: Sortable;
parentNode?: any;
body?: any;
// fixAlignmentLazy: Function;
unSensor: Function;
renderedToolbars: Array<string>;
@ -227,13 +224,7 @@ export default class Cards extends React.Component<GridProps, object> {
this.reset = this.reset.bind(this);
this.dragTipRef = this.dragTipRef.bind(this);
this.bodyRef = this.bodyRef.bind(this);
this.affixDetect = this.affixDetect.bind(this);
this.itemsRef = this.itemsRef.bind(this);
this.renderToolbar = this.renderToolbar.bind(this);
// this.fixAlignmentLazy = debounce(this.fixAlignment.bind(this), 250, {
// trailing: true,
// leading: false
// })
const {
store,
@ -293,20 +284,6 @@ export default class Cards extends React.Component<GridProps, object> {
return updateItems;
}
componentDidMount() {
let parent: HTMLElement | Window | null = getScrollParent(
findDOMNode(this) as HTMLElement
);
if (!parent || parent === document.body) {
parent = window;
}
this.parentNode = parent;
this.affixDetect();
parent.addEventListener('scroll', this.affixDetect);
window.addEventListener('resize', this.affixDetect);
}
componentDidUpdate(prevProps: GridProps) {
const props = this.props;
const store = props.store;
@ -352,64 +329,10 @@ export default class Cards extends React.Component<GridProps, object> {
}
}
componentWillUnmount() {
const parent = this.parentNode;
parent && parent.removeEventListener('scroll', this.affixDetect);
window.removeEventListener('resize', this.affixDetect);
}
// fixAlignment() {
// if (!this.props.fixAlignment || this.props.masonryLayout) {
// return;
// }
// const dom = this.body as HTMLElement;
// const ns = this.props.classPrefix;
// const cards = [].slice.apply(dom.querySelectorAll(`.${ns}Cards-body > div`));
// if (!cards.length) {
// return;
// }
// let maxHeight = cards.reduce((maxHeight:number, item:HTMLElement) => Math.max(item.offsetHeight, maxHeight), 0);
// cards.forEach((item: HTMLElement) => item.style.cssText += `min-height: ${maxHeight}px;`);
// }
bodyRef(ref: HTMLDivElement) {
this.body = ref;
}
itemsRef(ref: HTMLDivElement) {
if (ref) {
// this.unSensor = resizeSensor(ref.parentNode as HTMLElement, this.fixAlignmentLazy);
} else {
this.unSensor && this.unSensor();
// @ts-ignore;
delete this.unSensor;
}
}
affixDetect() {
if (!this.props.affixHeader || !this.body) {
return;
}
const ns = this.props.classPrefix;
const dom = findDOMNode(this) as HTMLElement;
const clip = (this.body as HTMLElement).getBoundingClientRect();
const offsetY =
this.props.affixOffsetTop ?? this.props.env.affixOffsetTop ?? 0;
const affixed =
clip.top - 10 < offsetY && clip.top + clip.height - 40 > offsetY;
const afixedDom = dom.querySelector(`.${ns}Cards-fixedTop`) as HTMLElement;
this.body.offsetWidth &&
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${this.body.offsetWidth}px;`);
affixed ? afixedDom.classList.add('in') : afixedDom.classList.remove('in');
// store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
}
@autobind
doAction(action: Action, data: object, throwErrors: boolean = false) {
if (action.actionType) {
@ -985,7 +908,9 @@ export default class Cards extends React.Component<GridProps, object> {
classnames: cx,
translate: __,
loading = false,
loadingConfig
loadingConfig,
affixOffsetTop,
env
} = this.props;
this.renderedToolbars = []; // 用来记录哪些 toolbar 已经渲染了,已经渲染了就不重复渲染了。
@ -1022,16 +947,22 @@ export default class Cards extends React.Component<GridProps, object> {
style={style}
>
{affixHeader ? (
<div className={cx('Cards-fixedTop')}>
<div
className={cx('Cards-fixedTop')}
style={{top: affixOffsetTop ?? env?.affixOffsetTop ?? 0}}
>
{header}
{heading}
</div>
) : null}
{header}
{heading}
) : (
<>
{header}
{heading}
</>
)}
{store.items.length ? (
<div
ref={this.itemsRef}
className={cx('Cards-body Grid', itemsClassName, masonryClassName)}
>
{store.items.map((item, index) =>

View File

@ -310,7 +310,6 @@ export default class List extends React.Component<ListProps, object> {
this.reset = this.reset.bind(this);
this.dragTipRef = this.dragTipRef.bind(this);
this.getPopOverContainer = this.getPopOverContainer.bind(this);
this.affixDetect = this.affixDetect.bind(this);
this.bodyRef = this.bodyRef.bind(this);
this.renderToolbar = this.renderToolbar.bind(this);
@ -375,20 +374,6 @@ export default class List extends React.Component<ListProps, object> {
return updateItems;
}
componentDidMount() {
let parent: HTMLElement | Window | null = getScrollParent(
findDOMNode(this) as HTMLElement
);
if (!parent || parent === document.body) {
parent = window;
}
this.parentNode = parent;
this.affixDetect();
parent.addEventListener('scroll', this.affixDetect);
window.addEventListener('resize', this.affixDetect);
}
componentDidUpdate(prevProps: ListProps) {
const props = this.props;
const store = props.store;
@ -436,40 +421,10 @@ export default class List extends React.Component<ListProps, object> {
}
}
componentWillUnmount() {
const parent = this.parentNode;
parent && parent.removeEventListener('scroll', this.affixDetect);
window.removeEventListener('resize', this.affixDetect);
}
bodyRef(ref: HTMLDivElement) {
this.body = ref;
}
affixDetect() {
if (!this.props.affixHeader || !this.body) {
return;
}
const ns = this.props.classPrefix;
const dom = findDOMNode(this) as HTMLElement;
const afixedDom = dom.querySelector(`.${ns}List-fixedTop`) as HTMLElement;
if (!afixedDom) {
return;
}
const clip = (this.body as HTMLElement).getBoundingClientRect();
const offsetY =
this.props.affixOffsetTop ?? this.props.env.affixOffsetTop ?? 0;
const affixed = clip.top < offsetY && clip.top + clip.height - 40 > offsetY;
this.body.offsetWidth &&
(afixedDom.style.cssText = `top: ${offsetY}px;width: ${this.body.offsetWidth}px;`);
affixed ? afixedDom.classList.add('in') : afixedDom.classList.remove('in');
// store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
}
getPopOverContainer() {
return findDOMNode(this);
}
@ -1017,7 +972,9 @@ export default class List extends React.Component<ListProps, object> {
hideCheckToggler,
checkOnItemClick,
itemAction,
affixOffsetTop,
affixHeader,
env,
classnames: cx,
size,
translate: __,
@ -1038,15 +995,21 @@ export default class List extends React.Component<ListProps, object> {
style={style}
ref={this.bodyRef}
>
{affixHeader && heading && header ? (
<div className={cx('List-fixedTop')}>
{affixHeader ? (
<div
className={cx('List-fixedTop')}
style={{top: affixOffsetTop ?? env?.affixOffsetTop ?? 0}}
>
{header}
{heading}
</div>
) : null}
) : (
<>
{header}
{heading}
</>
)}
{header}
{heading}
{store.items.length ? (
<div className={cx('List-items')}>
{store.items.map((item, index) =>

View File

@ -0,0 +1,29 @@
import React from 'react';
import type {IColumn, ITableStore} from 'amis-core/lib/store/table';
import {observer} from 'mobx-react';
export function ColGroup({
columns,
store
}: {
columns: Array<IColumn>;
store: ITableStore;
}) {
return (
<colgroup>
{columns.map(column => {
const style: any = {};
if (store.columnWidthReady) {
style.width = column.width;
} else if (column.pristine.width) {
style.width = column.pristine.width;
}
return <col data-index={column.index} style={style} key={column.id} />;
})}
</colgroup>
);
}
export default observer(ColGroup);

View File

@ -106,7 +106,10 @@ export class TableBody extends React.Component<TableBodyProps> {
? filter(rowClassNameExpr, item.locals)
: rowClassName,
{
'is-last': item.depth > 1 && rowIndex === rows.length - 1
'is-last':
item.depth > 1 &&
rowIndex === rows.length - 1 &&
!item.children.length
}
)}
columns={columns}

View File

@ -66,6 +66,14 @@ export class TableCell extends React.Component<TableCellProps> {
itemBadge,
...rest
} = this.props;
if (isHead) {
Component = 'th';
} else {
Component = Component || 'td';
}
const isTableCell = Component === 'td' || Component === 'th';
const schema = {
...column,
style: column.innerStyle, // column的innerStyle配置 作为内部组件的style 覆盖column的style
@ -88,24 +96,14 @@ export class TableCell extends React.Component<TableCellProps> {
data
});
if (width) {
if (isTableCell) {
// table Cell 会用 colGroup 来设置宽度,这里不需要再设置
style.width && (style = omit(style, ['width']));
} else if (width) {
style = {
...style,
width: (style && style.width) || width
};
if (!/%$/.test(String(style.width))) {
body = (
<div style={{width: style.width}}>
{cellPrefix}
{body}
{cellAffix}
</div>
);
cellPrefix = null;
cellAffix = null;
// delete style.width;
}
}
if (align) {
@ -152,12 +150,6 @@ export class TableCell extends React.Component<TableCellProps> {
return body as JSX.Element;
}
if (isHead) {
Component = 'th';
} else {
Component = Component || 'td';
}
return (
<Component
rowSpan={rowSpan > 1 ? rowSpan : undefined}

View File

@ -16,6 +16,7 @@ import {SchemaTpl} from '../../Schema';
import {Icon} from 'amis-ui';
import type {IColumn, IRow} from 'amis-core';
import ColGroup from './ColGroup';
export interface TableContentProps extends LocaleProps {
className?: string;
@ -32,7 +33,7 @@ export interface TableContentProps extends LocaleProps {
rows: Array<IRow>;
placeholder?: string | SchemaTpl;
render: (region: string, node: SchemaNode, props?: any) => JSX.Element;
onMouseMove: (event: React.MouseEvent) => void;
onMouseMove?: (event: React.MouseEvent) => void;
onScroll: (event: React.UIEvent) => void;
tableRef: (table?: HTMLTableElement | null) => void;
renderHeadCell: (column: IColumn, props?: any) => JSX.Element;
@ -177,24 +178,38 @@ export class TableContent extends React.Component<TableContentProps> {
className={cx('Table-content', className)}
onScroll={onScroll}
>
<table ref={tableRef} className={tableClassName}>
<table
style={store.useFixedLayout ? {tableLayout: 'fixed'} : undefined}
ref={tableRef}
className={tableClassName}
>
<ColGroup columns={columns} store={store} />
<thead>
{columnsGroup.length ? (
<tr>
{columnsGroup.map((item, index) =>
{columnsGroup.map((item, index) => {
const [stickyStyle, stickyClassName] = store.getStickyStyles(
item as any,
columnsGroup as any
);
/**
*
*
*/
!!~['__checkme', '__expandme'].indexOf(item.has[0].type) ||
(item.has.length === 1 &&
!/^__/.test(item.has[0].type) &&
!item.has[0].groupName) ? (
return !!~['__checkme', '__expandme'].indexOf(
item.has[0].type
) ||
(item.has.length === 1 &&
!/^__/.test(item.has[0].type) &&
!item.has[0].groupName) ? (
renderHeadCell(item.has[0], {
'data-index': item.has[0].index,
'key': index,
'colSpan': item.colSpan,
'rowSpan': item.rowSpan
'rowSpan': item.rowSpan,
'style': stickyStyle,
'className': stickyClassName
})
) : (
<th
@ -202,11 +217,13 @@ export class TableContent extends React.Component<TableContentProps> {
data-index={item.index}
colSpan={item.colSpan}
rowSpan={item.rowSpan}
style={stickyStyle}
className={stickyClassName}
>
{item.label ? render('tpl', item.label) : null}
</th>
)
)}
);
})}
</tr>
) : null}
<tr className={hideHeader ? 'fake-hide' : ''}>

File diff suppressed because it is too large Load Diff