mirror of
https://gitee.com/wot-design-uni/wot-design-uni.git
synced 2025-12-06 09:08:51 +08:00
feat: ✨ table组件支持排序
This commit is contained in:
parent
68affd2f59
commit
9898b01c06
File diff suppressed because it is too large
Load Diff
@ -796,3 +796,6 @@ $-navbar-capsule-border-color: var(--wot-navbar-capsule-border-color, #e7e7e7);
|
||||
$-navbar-capsule-border-radius: var(--wot-navbar-capsule-border-radius, 16px);
|
||||
$-navbar-capsule-width: var(--wot-navbar-capsule-width, 88px);
|
||||
$-navbar-capsule-height: var(--wot-navbar-capsule-height, 32px);
|
||||
|
||||
// table
|
||||
$-table-color: var(--wot-table-color, $-font-gray-1);
|
||||
|
||||
@ -24,7 +24,7 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import { type CSSProperties, computed, inject, onMounted, ref, watch, getCurrentInstance, reactive } from 'vue'
|
||||
import { type CSSProperties, computed, inject, onMounted, ref, watch, getCurrentInstance } from 'vue'
|
||||
import { isDef, objToStyle } from '../common/util'
|
||||
|
||||
interface Props {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
type AlignType = 'left' | 'center' | 'right' // 列的对齐方式
|
||||
|
||||
type SortDirection = 'asc' | 'desc' // 列的排序方向
|
||||
export type SortDirection = 0 | 1 | -1 // 列的排序方向
|
||||
|
||||
export interface TableColumn {
|
||||
// 列对应字段
|
||||
@ -16,5 +16,5 @@ export interface TableColumn {
|
||||
// 列的对齐方式,可选值left,center,right
|
||||
align?: AlignType
|
||||
// 列的排序方向
|
||||
sortDirection?: SortDirection | ''
|
||||
sortDirection: SortDirection
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
@click="handleRowClick(index)"
|
||||
>
|
||||
<slot v-if="$slots.default" :row="scope(index)"></slot>
|
||||
<view class="cell" v-else>{{ row }}</view>
|
||||
<text :class="`wd-table__value ${ellipsis ? 'is-ellipsis' : ''}`" v-else>{{ row }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@ -24,7 +24,7 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import { Ref, computed, inject, onMounted, ref } from 'vue'
|
||||
import { type CSSProperties, computed, inject, onMounted } from 'vue'
|
||||
import { addUnit, isDef, objToStyle, isOdd } from '../common/util'
|
||||
|
||||
type AlignType = 'left' | 'center' | 'right'
|
||||
@ -51,29 +51,29 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
align: 'left'
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
const setColumns: Function = inject('setColumns') as Function // 设置列数据.
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
const setRowClick: Function = inject('setRowClick') as Function
|
||||
const $props = inject<Ref>('$props') || ref({}) // table数据
|
||||
const parent = inject<any>('wdTable', { data: [] }) // table数据
|
||||
|
||||
// 是否开启斑马纹
|
||||
const stripe = computed(() => {
|
||||
return $props.value.stripe || false
|
||||
return parent.stripe || false
|
||||
})
|
||||
|
||||
/**
|
||||
* 是否有边框
|
||||
*/
|
||||
const border = computed(() => {
|
||||
return $props.value.border || false
|
||||
return parent.border || false
|
||||
})
|
||||
|
||||
const ellipsis = computed(() => {
|
||||
return parent.ellipsis || false
|
||||
})
|
||||
|
||||
/**
|
||||
* 根节点样式
|
||||
*/
|
||||
const rootStyle = computed(() => {
|
||||
const style: Record<string, string | number> = {}
|
||||
const style: CSSProperties = {}
|
||||
if (isDef(props.width)) {
|
||||
// width存在且包含px则转成px
|
||||
style['width'] = addUnit(props.width)
|
||||
@ -83,8 +83,8 @@ const rootStyle = computed(() => {
|
||||
})
|
||||
|
||||
const rowStyle = computed(() => {
|
||||
const rowHeight: string | number = $props.value.rowHeight || '80rpx' // 自定义行高
|
||||
const style: Record<string, string | number> = {}
|
||||
const rowHeight: string | number = parent.rowHeight || '80rpx' // 自定义行高
|
||||
const style: CSSProperties = {}
|
||||
if (isDef(props.width)) {
|
||||
// width存在且包含px则转成px
|
||||
style['width'] = addUnit(props.width)
|
||||
@ -93,37 +93,40 @@ const rowStyle = computed(() => {
|
||||
// width存在且包含px则转成px
|
||||
style['height'] = addUnit(rowHeight)
|
||||
}
|
||||
|
||||
return objToStyle(style)
|
||||
})
|
||||
|
||||
// 行完整数据
|
||||
const scope = computed(() => {
|
||||
return (index: number) => {
|
||||
return $props.value.data[index] || {}
|
||||
return parent.data[index] || {}
|
||||
}
|
||||
})
|
||||
|
||||
// 列数据
|
||||
const column = computed(() => {
|
||||
let column: any[] = $props.value.data.map((item) => {
|
||||
let column: any[] = parent.data.map((item) => {
|
||||
return item[props.prop]
|
||||
})
|
||||
return column
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
setColumns({
|
||||
parent.setColumns &&
|
||||
parent.setColumns({
|
||||
prop: props.prop,
|
||||
label: props.label,
|
||||
width: props.width,
|
||||
sortable: props.sortable,
|
||||
lightHigh: props.lightHigh,
|
||||
sortDirection: 0,
|
||||
align: props.align
|
||||
})
|
||||
})
|
||||
|
||||
function handleRowClick(index: number) {
|
||||
setRowClick(index)
|
||||
parent.setRowClick && parent.setRowClick(index)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -55,7 +55,6 @@
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
pointer-events: none;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@ -66,13 +65,15 @@
|
||||
}
|
||||
|
||||
@include e(cell) {
|
||||
flex: 0 0 auto;
|
||||
width: 220rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
|
||||
flex: 0 0 auto;
|
||||
width: 220rpx;
|
||||
min-height: 50px;
|
||||
padding: 8px 10px;
|
||||
font-size: 13px;
|
||||
color: $-table-color;
|
||||
|
||||
@include when(border) {
|
||||
border-right: 1px solid #ececec;
|
||||
@ -82,6 +83,24 @@
|
||||
@include when(stripe) {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
|
||||
@include when(left) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
@include when(center) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@include when(right) {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include e(value) {
|
||||
@include when(ellipsis) {
|
||||
@include multiEllipsis(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,32 +1,48 @@
|
||||
<template>
|
||||
<view :class="`wd-table-content ${border ? 'is-border' : ''}`">
|
||||
<view :class="`wd-table--fixed ${isShadow ? 'is-shadow' : ''}`" :style="fixedStyle">
|
||||
<view :class="`wd-table--fixed ${isShadow ? 'is-shadow' : ''}`" :style="fixedStyle" v-if="$slots.fixed">
|
||||
<view class="wd-table__header" v-if="showHeader">
|
||||
<view
|
||||
:class="`wd-table__cell ${border ? 'is-border' : ''} ${stripe ? 'is-stripe' : ''}`"
|
||||
:class="`wd-table__cell ${border ? 'is-border' : ''} ${stripe ? 'is-stripe' : ''} is-${column.align}`"
|
||||
:style="headerCellStyle(column.width)"
|
||||
v-for="(column, index) in columns"
|
||||
:key="index"
|
||||
>
|
||||
<text>{{ column.label }}</text>
|
||||
<wd-sort-button
|
||||
v-model="column.sortDirection"
|
||||
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 class="wd-table__body" :style="fixedBodyStyle" :enable-flex="true" :scroll-y="true" :scroll-top="scrollTop">
|
||||
<scroll-view class="wd-table__body" :style="fixedBodyStyle" :enable-flex="true" :throttle="false" :scroll-y="true" :scroll-top="scrollTop">
|
||||
<view style="display: inline-flex" id="fixed-body">
|
||||
<slot name="fixed"></slot>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<scroll-view :class="`wd-table is-border`" :style="wraperStyle" :scroll-x="true" :throttle="false" @scroll="handleWraperScroll">
|
||||
<scroll-view class="wd-table" :style="wraperStyle" :scroll-x="true" :throttle="false" @scroll="handleWraperScroll">
|
||||
<view class="wd-table__header" id="table-header" :style="rowStyle" v-if="showHeader">
|
||||
<view
|
||||
:class="`wd-table__cell ${border ? 'is-border' : ''} ${stripe ? 'is-stripe' : ''}`"
|
||||
:class="`wd-table__cell ${border ? 'is-border' : ''} ${stripe ? 'is-stripe' : ''} is-${column.align}`"
|
||||
:style="headerCellStyle(column.width)"
|
||||
v-for="(column, index) in columns"
|
||||
:key="index"
|
||||
>
|
||||
<text>{{ column.label }}</text>
|
||||
<wd-sort-button
|
||||
v-model="column.sortDirection"
|
||||
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 class="wd-table__body" :style="bodyStyle" :enable-flex="true" :throttle="false" :scroll-y="true" @scroll="handleBodyScroll">
|
||||
@ -51,9 +67,11 @@ export default {
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { type CSSProperties, computed, getCurrentInstance, nextTick, onMounted, provide, ref, watch } from 'vue'
|
||||
import { type CSSProperties, computed, getCurrentInstance, nextTick, onMounted, provide, ref, watch, reactive } from 'vue'
|
||||
import { addUnit, deepClone, getRect, isDef, objToStyle } from '../common/util'
|
||||
import type { TableColumn } from '../wd-table-col/types'
|
||||
import type { SortDirection, TableColumn } from '../wd-table-col/types'
|
||||
|
||||
const a = ref(0)
|
||||
|
||||
interface Props {
|
||||
// 显示的数据
|
||||
@ -68,6 +86,8 @@ interface Props {
|
||||
rowHeight?: number | string
|
||||
// 是否显示表头
|
||||
showHeader?: boolean
|
||||
// 是否超出2行隐藏
|
||||
ellipsis?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@ -79,16 +99,18 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
// table高度
|
||||
height: '80vh',
|
||||
// 行高
|
||||
rowHeight: '48px',
|
||||
rowHeight: 50,
|
||||
// 是否显示表头
|
||||
showHeader: true
|
||||
showHeader: true,
|
||||
// 是否超出2行隐藏
|
||||
ellipsis: true
|
||||
})
|
||||
|
||||
// 监听数据源变化改变privide出去的$dataSource
|
||||
watch(
|
||||
props,
|
||||
() => {
|
||||
$props.value = props
|
||||
() => props.data,
|
||||
(newValue) => {
|
||||
parentData.data = newValue
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
@ -96,23 +118,25 @@ watch(
|
||||
const scrollTop = ref<number>(0) // scroll-view 滚动距离
|
||||
const scrollWidth = ref<number | string>('auto') // 动态设置滚动宽度,兼容微信scroll-view中sticky失效的问题
|
||||
const columns = ref<TableColumn[]>([]) // 数据列
|
||||
const $props = ref<Props>(props)
|
||||
const fixedWidth = ref<number | string>(0) // 固定列宽度
|
||||
const isShadow = ref<boolean>(false) // 是否展示shadow
|
||||
|
||||
const emit = defineEmits(['click', 'sort-method', 'row-click'])
|
||||
|
||||
/**
|
||||
* 根节点样式
|
||||
*/
|
||||
const rootStyle = computed(() => {
|
||||
const style: CSSProperties = {}
|
||||
if (isDef(props.height)) {
|
||||
style['height'] = addUnit(props.height)
|
||||
}
|
||||
return objToStyle(style)
|
||||
const parentData = reactive({
|
||||
data: props.data,
|
||||
stripe: props.stripe,
|
||||
border: props.border,
|
||||
height: props.height,
|
||||
rowHeight: props.rowHeight,
|
||||
showHeader: props.showHeader,
|
||||
ellipsis: props.ellipsis,
|
||||
setRowClick,
|
||||
setColumns
|
||||
})
|
||||
|
||||
provide('wdTable', parentData)
|
||||
|
||||
const emit = defineEmits(['click', 'sort-method', 'row-click'])
|
||||
|
||||
/**
|
||||
* 容器样式
|
||||
*/
|
||||
@ -145,7 +169,7 @@ const rowStyle = computed(() => {
|
||||
return objToStyle(style)
|
||||
})
|
||||
|
||||
const headerHeight = ref<string | number>(48) // 表格header高度
|
||||
const headerHeight = ref<string | number>(50) // 表格header高度
|
||||
|
||||
const fixedBodyStyle = computed(() => {
|
||||
const style: CSSProperties = {}
|
||||
@ -193,31 +217,23 @@ function setColumns(column: TableColumn) {
|
||||
* 表头单元格样式
|
||||
*/
|
||||
function headerCellStyle(width?: string | number) {
|
||||
const style: Record<string, string | number> = {}
|
||||
const style: CSSProperties = {}
|
||||
if (isDef(width)) {
|
||||
style['width'] = addUnit(width)
|
||||
}
|
||||
return objToStyle(style)
|
||||
}
|
||||
|
||||
/**
|
||||
* 排序事件
|
||||
*/
|
||||
function doSort(column, index) {
|
||||
if (column.sortDirection === 'asc') {
|
||||
columns.value[index].sortDirection = 'desc'
|
||||
} else if (columns.value[index].sortDirection === 'desc') {
|
||||
columns.value[index].sortDirection = ''
|
||||
} else {
|
||||
columns.value[index].sortDirection = 'asc'
|
||||
}
|
||||
function handleSortChange(value: SortDirection, index: number) {
|
||||
columns.value[index].sortDirection = value
|
||||
columns.value.forEach((col, i) => {
|
||||
if (index != i) {
|
||||
col.sortDirection = ''
|
||||
col.sortDirection = 0
|
||||
}
|
||||
})
|
||||
emit('sort-method', columns.value[index])
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动事件
|
||||
*/
|
||||
@ -245,11 +261,30 @@ function handleWraperScroll(event) {
|
||||
function setRowClick(index: number) {
|
||||
emit('row-click', { rowIndex: index })
|
||||
}
|
||||
|
||||
provide('$props', $props) // 行高provide
|
||||
provide('setRowClick', setRowClick)
|
||||
provide('setColumns', setColumns)
|
||||
</script>
|
||||
|
||||
<!-- <script module="touch" lang="wxs">
|
||||
|
||||
function touchstart(event, ins) {
|
||||
console.log(event);
|
||||
console.log(ins);
|
||||
}
|
||||
function touchend(event, ins) {
|
||||
console.log(event);
|
||||
console.log(ins);
|
||||
}
|
||||
|
||||
function transitionend(event, ins) {
|
||||
console.log(event);
|
||||
console.log(ins);
|
||||
}
|
||||
|
||||
module.exports= {
|
||||
touchstart,
|
||||
touchend,
|
||||
transitionend
|
||||
}
|
||||
</script> -->
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user