| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- <template>
- <view :class="`wd-table ${border ? 'is-border' : ''} ${customClass}`" :style="tableStyle">
- <template v-if="fixedHeader">
- <scroll-view
- :enable-flex="true"
- :throttle="false"
- :scrollLeft="state.scrollLeft"
- :scroll-x="true"
- class="wd-table__header"
- @scroll="scroll"
- v-if="showHeader"
- >
- <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) && state.scrollLeft ? 'is-shadow' : ''
- }`"
- :style="getCellStyle(index)"
- v-for="(column, index) in children"
- :key="index"
- >
- <wd-sort-button
- v-model="column.$.exposed!.sortDirection.value"
- allow-reset
- :line="false"
- :title="column.label"
- @change="({ value }) => handleSortChange(value, index)"
- v-if="column.sortable"
- />
- <text v-else :class="`wd-table__value ${ellipsis ? 'is-ellipsis' : ''}`">{{ column.label }}</text>
- </view>
- </view>
- </scroll-view>
- <scroll-view
- class="wd-table__body"
- :style="bodyStyle"
- :enable-flex="true"
- :throttle="false"
- :scroll-x="true"
- @scroll="scroll"
- :scrollLeft="state.scrollLeft"
- >
- <view id="table-body" class="wd-table__content" :style="realWidthStyle">
- <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>
- </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>
- <script lang="ts">
- export default {
- name: 'wd-table',
- options: {
- addGlobalClass: true,
- virtualHost: true,
- styleIsolation: 'shared'
- }
- }
- </script>
- <script lang="ts" setup>
- import wdTableCol from '../wd-table-col/wd-table-col.vue'
- import wdSortButton from '../wd-sort-button/wd-sort-button.vue'
- import { type CSSProperties, computed, reactive, ref } from 'vue'
- import { addUnit, debounce, isDef, isObj, objToStyle, uuid } from '../common/util'
- import type { SortDirection, TableColumn, TableColumnInstance, TableColumnProps } from '../wd-table-col/types'
- import { TABLE_KEY, tableProps, type TableProvide } from './types'
- import WdTableCol from '../wd-table-col/wd-table-col.vue'
- import { useTranslate } from '../composables/useTranslate'
- import { useChildren } from '../composables/useChildren'
- const { translate } = useTranslate('tableCol')
- const props = defineProps(tableProps)
- const emit = defineEmits(['sort-method', 'row-click'])
- const state = reactive({
- scrollLeft: 0
- })
- const { linkChildren, children } = useChildren<TableColumnInstance, TableProvide>(TABLE_KEY)
- linkChildren({ props, state, rowClick, getIsLastFixed, getFixedStyle })
- const indexUUID = uuid()
- const indexColumn = ref<TableColumnProps>({
- prop: indexUUID,
- label: translate('indexLabel'),
- width: '100rpx',
- sortable: false,
- fixed: false,
- align: 'left',
- ...(isObj(props.index) ? props.index : {})
- })
- const scroll = debounce(handleScroll, 100, { leading: false }) // 滚动事件
- /**
- * 容器样式
- */
- const tableStyle = computed(() => {
- const style: CSSProperties = {}
- if (isDef(props.height)) {
- style['max-height'] = addUnit(props.height)
- }
- return `${objToStyle(style)}${props.customStyle}`
- })
- const realWidthStyle = computed(() => {
- const style: CSSProperties = {
- display: 'flex'
- }
- let width: string | number = ''
- children.forEach((child) => {
- width = width ? `${width} + ${addUnit(child.width)}` : addUnit(child.width)
- })
- style['width'] = `calc(${width})`
- return objToStyle(style)
- })
- const bodyStyle = computed(() => {
- const style: CSSProperties = {}
- if (isDef(props.height)) {
- style['height'] = isDef(props.rowHeight) ? `calc(${props.data.length} * ${addUnit(props.rowHeight)})` : `calc(${props.data.length} * 50px)`
- }
- return `${objToStyle(style)}`
- })
- /**
- * 是否最后一个固定元素
- * @param column 列数据
- */
- function getIsLastFixed(column: { fixed: boolean; prop: string }) {
- let isLastFixed: boolean = false
- if (column.fixed && isDef(children)) {
- const columns = children.filter((child) => {
- return child.fixed
- })
- if (columns.length && columns[columns.length - 1].prop === column.prop) {
- isLastFixed = true
- }
- }
- return isLastFixed
- }
- /**
- * 表头单元格样式
- */
- function getCellStyle(columnIndex: number) {
- let style: CSSProperties = {}
- if (isDef(children[columnIndex].width)) {
- style['width'] = addUnit(children[columnIndex].width)
- }
- if (children[columnIndex].fixed) {
- style = getFixedStyle(columnIndex, style)
- }
- return objToStyle(style)
- }
- /**
- * 获取固定列样式
- * @param columnIndex
- */
- function getFixedStyle(columnIndex: number, style: CSSProperties) {
- if (columnIndex > 0) {
- let left: string | number = ''
- children.forEach((column, index) => {
- if (index < columnIndex) {
- left = left ? `${left} + ${addUnit(column.width)}` : addUnit(column.width)
- }
- })
- style['left'] = `calc(${left})`
- } else {
- style['left'] = 0
- }
- return style
- }
- /**
- * 排序
- * @param value
- * @param index
- */
- function handleSortChange(value: SortDirection, index: number) {
- children[index].$.exposed!.sortDirection.value = value
- children.forEach((col, i) => {
- if (index != i) {
- col.$.exposed!.sortDirection.value = 0
- }
- })
- const column: TableColumn = {
- // 列对应字段
- prop: children[index].prop,
- // 列对应字段标题
- label: children[index].label,
- // 列宽度
- width: children[index].width,
- // 是否开启列排序
- sortable: children[index].sortable,
- // 列的对齐方式,可选值left,center,right
- align: children[index].align,
- // 列的排序方向
- sortDirection: value,
- // 是否i固定列
- fixed: children[index].fixed
- }
- emit('sort-method', column)
- }
- /**
- * 滚动事件
- */
- function handleScroll(event: any) {
- state.scrollLeft = event.detail.scrollLeft
- }
- function rowClick(index: number) {
- emit('row-click', { rowIndex: index })
- }
- </script>
- <style lang="scss" scoped>
- @import './index.scss';
- </style>
|