feat: Table 支持设置不固定表头 (#769)

This commit is contained in:
不如摸鱼去 2024-12-08 23:50:11 +08:00 committed by GitHub
parent 97c40047e8
commit b0a2461a1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 185 additions and 107 deletions

View File

@ -2,6 +2,10 @@
用于展示多条结构类似的数据, 可对数据进行排序等操作。
::: warning 提示
`$LOWEST_VERSION$`后取消了`height`的默认值,需要自行设置,最好设置为`number`类型,方便未来适配虚拟列表。
:::
## 基础用法
通过`data`设置表格数据。
@ -9,7 +13,7 @@
::: details 基础用法
```html
<wd-table :data="dataList">
<wd-table :data="dataList" :height="400">
<wd-table-col prop="name" label="姓名"></wd-table-col>
<wd-table-col prop="school" label="求学之所"></wd-table-col>
<wd-table-col prop="major" label="专业"></wd-table-col>
@ -46,7 +50,7 @@ const dataList = reactive([
:::
```html
<wd-table :data="dataList">
<wd-table :data="dataList" :height="400">
<wd-table-col prop="name" label="姓名" fixed></wd-table-col>
<wd-table-col prop="school" label="求学之所"></wd-table-col>
<wd-table-col prop="major" label="专业"></wd-table-col>
@ -58,7 +62,7 @@ const dataList = reactive([
通过`index`设置表格是否显示序号列,默认为`false`。同时也可以传入对象对序号列进行配置,参数同`TableColumnProps`
```html
<wd-table :data="dataList" height="328px" :index="true">
<wd-table :data="dataList" height="328px" :index="true" :height="400">
<wd-table-col prop="name" label="姓名" sortable></wd-table-col>
<wd-table-col prop="grade" label="分数" sortable></wd-table-col>
<wd-table-col prop="hobby" label="一言以蔽之" sortable :width="160"></wd-table-col>
@ -76,7 +80,7 @@ const dataList = reactive([
通过`stripe`设置表格是否展示斑马纹,默认`true`
```html
<wd-table :data="dataList" :stripe="false">
<wd-table :data="dataList" :stripe="false" :height="400">
<wd-table-col prop="name" label="姓名"></wd-table-col>
<wd-table-col prop="school" label="求学之所"></wd-table-col>
<wd-table-col prop="major" label="专业"></wd-table-col>
@ -88,7 +92,7 @@ const dataList = reactive([
通过`border`设置表格是否展示边框,默认`true`
```html
<wd-table :data="dataList" :border="false">
<wd-table :data="dataList" :border="false" :height="400">
<wd-table-col prop="name" label="姓名"></wd-table-col>
<wd-table-col prop="school" label="求学之所"></wd-table-col>
<wd-table-col prop="major" label="专业"></wd-table-col>
@ -97,10 +101,10 @@ const dataList = reactive([
## 表格高度
通过`height`设置表格高度,默认为`80vh`
通过`height`设置表格高度,设置高度后会自动固定表头
```html
<wd-table :data="dataList" height="328px">
<wd-table :data="dataList" :height="400">
<wd-table-col prop="name" label="姓名"></wd-table-col>
<wd-table-col prop="school" label="求学之所"></wd-table-col>
<wd-table-col prop="major" label="专业"></wd-table-col>
@ -112,7 +116,7 @@ const dataList = reactive([
当存在列参与排序时,点击会触发`sort-method`排序事件。
```html
<wd-table :data="dataList" @sort-method="handleSort">
<wd-table :data="dataList" @sort-method="handleSort" :height="400">
<wd-table-col prop="name" label="姓名"></wd-table-col>
<wd-table-col prop="school" label="求学之所" sortable></wd-table-col>
<wd-table-col prop="major" label="专业"></wd-table-col>
@ -133,7 +137,7 @@ function handleSort(e) {
::: details 查看自定义列模版 demo
```html
<wd-table :data="dataList" @sort-method="handleSort">
<wd-table :data="dataList" @sort-method="handleSort" :height="400">
<wd-table-col prop="name" label="姓名" fixed="true" width="320rpx" sortable></wd-table-col>
<wd-table-col prop="grade" label="分数" width="220rpx" sortable>
<template #value="{row}">
@ -248,13 +252,16 @@ function handleSort(e) {
:::
## 结合分页器使用
## 不固定表头结合分页器使用
使用`pagination`组件,通过`v-model`绑定分页器当前页码,通过`total`设置分页器总条数,实现分页加载效果。
设置`fixed-header``false`,取消固定表头。
::: details 查看结合分页器使用 demo
```html
<wd-table :data="paginationData" height="auto">
<wd-table :data="paginationData" :height="400" :fixed-header="false">
<wd-table-col prop="name" label="姓名" fixed align="center"></wd-table-col>
<wd-table-col prop="grade" label="分数" fixed align="center"></wd-table-col>
<wd-table-col prop="hobby" label="一言以蔽之" :width="160"></wd-table-col>
@ -439,20 +446,22 @@ const paginationData = computed(() => {
return dataList.value.slice((page.value - 1) * pageSize.value, page.value * pageSize.value)
})
```
:::
## Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
| ---------- | --------------------------------------------------- | ---------------------------- | ------ | ------ | -------- |
| --------------- | --------------------------------------------------- | ---------------------------- | ------ | ------ | ---------------- |
| data | 显示的数据 | Array | - | - | 0.0.39 |
| border | 是否带有边框 | boolean | - | true | 0.0.39 |
| stripe | 是否为斑马纹表 | boolean | - | true | 0.0.39 |
| height | Table 的高度,默认为`80vh` | string | - | `80vh` | 0.0.39 |
| height | Table 的高度,无默认值,设置后自动开启固定表头。 | `number / string` | - | - | 0.0.39 |
| rowHeight | 行高 | `number / string` | - | 50 | 0.0.39 |
| showHeader | 是否显示表头 | boolean | - | true | 0.0.39 |
| ellipsis | 是否超出 2 行隐藏 | boolean | - | true | 0.0.39 |
| index | 是否显示索引列,可传入`boolean`也可传入 column 配置 | `boolean / TableColumnProps` | | false | 1.2.19 |
| fixed-header | 是否固定表头,需要结合`height`才可以实现固定表头的效果。 | boolean | - | true | $LOWEST_VERSION$ |
## Events

View File

@ -1,35 +1,35 @@
<template>
<page-wraper>
<demo-block title="基本用法">
<wd-table :data="dataList" @sort-method="handleSort" height="328px" @row-click="handleRowClick">
<wd-table :data="dataList" @sort-method="handleSort" :height="400" @row-click="handleRowClick">
<wd-table-col prop="name" label="姓名" align="center" width="50%"></wd-table-col>
<wd-table-col prop="grade" label="分数" align="center" width="50%"></wd-table-col>
</wd-table>
</demo-block>
<demo-block title="无边框">
<wd-table :data="dataList" @sort-method="handleSort" height="328px" :border="false" @row-click="handleRowClick">
<wd-table :data="dataList" @sort-method="handleSort" :height="400" :border="false" @row-click="handleRowClick">
<wd-table-col prop="name" label="姓名" align="center" width="50%"></wd-table-col>
<wd-table-col prop="grade" label="分数" align="center" width="50%"></wd-table-col>
</wd-table>
</demo-block>
<demo-block title="无斑马纹">
<wd-table :data="dataList" @sort-method="handleSort" height="328px" :stripe="false" @row-click="handleRowClick">
<wd-table :data="dataList" @sort-method="handleSort" :height="400" :stripe="false" @row-click="handleRowClick">
<wd-table-col prop="name" label="姓名" align="center" width="50%"></wd-table-col>
<wd-table-col prop="grade" label="分数" align="center" width="50%"></wd-table-col>
</wd-table>
</demo-block>
<demo-block title="不展示表头">
<wd-table :data="dataList" @sort-method="handleSort" height="328px" :show-header="false" @row-click="handleRowClick">
<wd-table :data="dataList" @sort-method="handleSort" :height="400" :show-header="false" @row-click="handleRowClick">
<wd-table-col prop="name" label="姓名" align="center" width="50%"></wd-table-col>
<wd-table-col prop="grade" label="分数" align="center" width="50%"></wd-table-col>
</wd-table>
</demo-block>
<demo-block title="固定列">
<wd-table :data="dataList" @sort-method="handleSort" @row-click="handleRowClick" height="328px">
<wd-table :data="dataList" @sort-method="handleSort" @row-click="handleRowClick" :height="400">
<wd-table-col prop="name" label="姓名" fixed sortable align="center"></wd-table-col>
<wd-table-col prop="grade" label="分数" fixed sortable align="center"></wd-table-col>
<wd-table-col prop="hobby" label="一言以蔽之" sortable :width="160"></wd-table-col>
@ -40,7 +40,7 @@
</demo-block>
<demo-block title="显示索引">
<wd-table :data="dataList" height="328px" @sort-method="handleSort" :index="{ align: 'center' }">
<wd-table :data="dataList" :height="400" @sort-method="handleSort" :index="{ align: 'center' }">
<wd-table-col prop="name" label="姓名" sortable align="center"></wd-table-col>
<wd-table-col prop="grade" label="分数" sortable align="center"></wd-table-col>
<wd-table-col prop="hobby" label="一言以蔽之" sortable :width="160"></wd-table-col>
@ -51,7 +51,7 @@
</demo-block>
<demo-block title="自定义列模板">
<wd-table :data="dataList" @sort-method="handleSort" @row-click="handleRowClick" height="328px">
<wd-table :data="dataList" @sort-method="handleSort" @row-click="handleRowClick" :height="400">
<wd-table-col prop="name" label="姓名" fixed sortable align="center"></wd-table-col>
<wd-table-col prop="grade" label="分数" fixed sortable align="center">
<template #value="{ row }">
@ -69,8 +69,8 @@
</wd-table>
</demo-block>
<demo-block title="结合分页器">
<wd-table :data="paginationData" height="auto">
<demo-block title="不固定表头结合分页器">
<wd-table :data="paginationData" :fixed-header="false">
<wd-table-col prop="name" label="姓名" fixed align="center"></wd-table-col>
<wd-table-col prop="grade" label="分数" fixed align="center"></wd-table-col>
<wd-table-col prop="hobby" label="一言以蔽之" :width="160"></wd-table-col>

View File

@ -1,6 +1,6 @@
<template>
<view
:class="`wd-table-col ${fixed ? 'wd-table-col--fixed' : ''} ${isLastFixed && isDef(table) && table.scrollLeft ? 'is-shadow' : ''}`"
:class="`wd-table-col ${fixed ? 'wd-table-col--fixed' : ''} ${isLastFixed && isDef(table) && table.state.scrollLeft ? 'is-shadow' : ''}`"
:style="columnStyle"
>
<view
@ -27,7 +27,7 @@ export default {
}
</script>
<script lang="ts" setup>
import { type CSSProperties, computed, ref, watch } from 'vue'
import { type CSSProperties, computed, ref } from 'vue'
import { addUnit, isDef, objToStyle, isOdd, isFunction } from '../common/util'
import { tableColumnProps, type SortDirection } from './types'
import { useParent } from '../composables/useParent'
@ -100,7 +100,7 @@ const columnStyle = computed(() => {
*/
const cellStyle = computed(() => {
let style: CSSProperties = {}
const rowHeight: string | number = isDef(table) ? table.props.rowHeight : '80rpx' //
const rowHeight: string | number = isDef(table) ? table.props.rowHeight : 50 //
if (isDef(rowHeight)) {
style['height'] = addUnit(rowHeight)
}

View File

@ -43,7 +43,6 @@
border: 1px solid $-table-border-color;
}
:deep() {
.wd-table-col:last-child {
.wd-table__cell {
@ -72,6 +71,12 @@
@include e(content) {
display: flex;
@include m(header) {
position: sticky;
top: 0;
z-index: 2
}
}
@include e(cell) {
@ -127,6 +132,26 @@
}
}
@include e(wrapper) {
width: 100%;
overflow: auto;
}
@include e(inner) {
display: flex;
flex-direction: column;
}
@include e(header-row) {
display: flex;
flex-direction: row;
width: 100%;
}
@include e(body) {
display: flex;
width: 100%;
}
@include e(value) {
@include when(ellipsis) {

View File

@ -1,14 +1,14 @@
/*
* @Author: weisheng
* @Date: 2024-03-15 11:36:12
* @LastEditTime: 2024-07-18 19:02:32
* @LastEditTime: 2024-12-08 23:22:26
* @LastEditors: weisheng
* @Description:
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-table\types.ts
* @FilePath: /wot-design-uni/src/uni_modules/wot-design-uni/components/wd-table/types.ts
*
*/
import type { CSSProperties, ExtractPropTypes, InjectionKey } from 'vue'
import { baseProps, makeBooleanProp, makeNumericProp, makeRequiredProp, makeStringProp } from '../common/props'
import { baseProps, makeBooleanProp, makeNumericProp, makeRequiredProp, numericProp } from '../common/props'
import type { TableColumnProps } from '../wd-table-col/types'
import type { PropType } from 'vue'
@ -29,7 +29,7 @@ export const tableProps = {
/**
* Table
*/
height: makeStringProp('80vh'),
height: numericProp,
/**
*
*/
@ -48,14 +48,17 @@ export const tableProps = {
index: {
type: [Object, Boolean] as PropType<boolean | Omit<Partial<TableColumnProps>, 'prop'>>,
default: false
}
},
fixedHeader: makeBooleanProp(true)
}
export type TableProps = ExtractPropTypes<typeof tableProps>
export type TableProvide = {
props: Omit<TableProps, 'index' | 'customStyle' | 'customClass'>
state: {
scrollLeft: number
}
rowClick: (index: number) => void
getIsLastFixed: (column: { fixed: boolean; prop: string }) => boolean
getFixedStyle: (index: number, style: CSSProperties) => CSSProperties

View File

@ -1,18 +1,19 @@
<template>
<view :class="`wd-table ${border ? 'is-border' : ''} ${customClass}`" :style="tableStyle">
<template v-if="fixedHeader">
<scroll-view
:enable-flex="true"
:throttle="false"
:scrollLeft="reactiveState.scrollLeft"
:scrollLeft="state.scrollLeft"
:scroll-x="true"
class="wd-table__header"
@scroll="scroll"
v-if="showHeader"
>
<view id="table-header" class="wd-table__content" :style="realWidthStyle" style="position: sticky; top: 0; z-index: 2">
<view id="table-header" class="wd-table__content wd-table__content--header" :style="realWidthStyle">
<view
:class="`wd-table__cell ${border ? 'is-border' : ''} ${column.fixed ? 'is-fixed' : ''} ${stripe ? 'is-stripe' : ''} is-${column.align} ${
getIsLastFixed(column) && reactiveState.scrollLeft ? 'is-shadow' : ''
getIsLastFixed(column) && state.scrollLeft ? 'is-shadow' : ''
}`"
:style="getCellStyle(index)"
v-for="(column, index) in children"
@ -37,7 +38,7 @@
:throttle="false"
:scroll-x="true"
@scroll="scroll"
:scrollLeft="reactiveState.scrollLeft"
:scrollLeft="state.scrollLeft"
>
<view id="table-body" class="wd-table__content" :style="realWidthStyle">
<wd-table-col
@ -56,6 +57,53 @@
<slot></slot>
</view>
</scroll-view>
</template>
<!-- 非固定表头时使用单个scroll-view -->
<template v-else>
<scroll-view class="wd-table__wrapper" :enable-flex="true" :throttle="false" :scroll-x="true" @scroll="scroll" :scrollLeft="state.scrollLeft">
<view class="wd-table__inner" :style="realWidthStyle">
<!-- 表头部分 -->
<view v-if="showHeader" class="wd-table__header-row">
<view
v-for="(column, index) in children"
:key="index"
:class="`wd-table__cell ${border ? 'is-border' : ''} ${column.fixed ? 'is-fixed' : ''} ${stripe ? 'is-stripe' : ''} is-${
column.align
} ${getIsLastFixed(column) && state.scrollLeft ? 'is-shadow' : ''}`"
:style="getCellStyle(index)"
>
<wd-sort-button
v-if="column.sortable"
v-model="column.$.exposed!.sortDirection.value"
allow-reset
:line="false"
:title="column.label"
@change="({ value }) => handleSortChange(value, index)"
/>
<text v-else :class="`wd-table__value ${ellipsis ? 'is-ellipsis' : ''}`">{{ column.label }}</text>
</view>
</view>
<!-- 表格内容部分 -->
<view class="wd-table__content" :style="bodyStyle">
<wd-table-col
v-if="index !== false"
:prop="indexColumn.prop"
:label="indexColumn.label"
:width="indexColumn.width"
:sortable="indexColumn.sortable"
:fixed="indexColumn.fixed"
:align="indexColumn.align"
>
<template #value="{ index }">
<text>{{ index + 1 }}</text>
</template>
</wd-table-col>
<slot></slot>
</view>
</view>
</scroll-view>
</template>
</view>
</template>
@ -86,17 +134,13 @@ const { translate } = useTranslate('tableCol')
const props = defineProps(tableProps)
const emit = defineEmits(['sort-method', 'row-click'])
const reactiveState = reactive<TableProvide>({
props,
scrollLeft: 0,
rowClick,
getIsLastFixed,
getFixedStyle
const state = reactive({
scrollLeft: 0
})
const { linkChildren, children } = useChildren<TableColumnInstance, TableProvide>(TABLE_KEY)
linkChildren(reactiveState)
linkChildren({ props, state, rowClick, getIsLastFixed, getFixedStyle })
const indexUUID = uuid()
const indexColumn = ref<TableColumnProps>({
@ -227,10 +271,7 @@ function handleSortChange(value: SortDirection, index: number) {
* 滚动事件
*/
function handleScroll(event: any) {
if (!props.showHeader) {
return
}
reactiveState.scrollLeft = event.detail.scrollLeft
state.scrollLeft = event.detail.scrollLeft
}
function rowClick(index: number) {