11<script lang="ts">
22import { defineComponent , h , PropType , ref , toRaw , watch } from ' vue' ;
3- import type { VNode } from ' vue' ;
4- import { random } from ' ph-utils' ;
3+ import type { VNode , CSSProperties } from ' vue' ;
4+ import { isBlank , random } from ' ph-utils' ;
55import { format } from ' ph-utils/date' ;
66
77export interface ColumnOption {
@@ -27,10 +27,9 @@ export interface ColumnOption {
2727 titleColspan? : number ;
2828 /** th rowspan */
2929 titleRowspan? : number ;
30- /** 设置可选择 */
31- type? : ' radio' | ' checkbox' ;
32- /** 为 radio,checkbox 设置是否禁用 */
33- disabled? : (row : any ) => boolean ;
30+ id? : string ;
31+ style? : CSSProperties ;
32+ className? : string ;
3433}
3534
3635export interface DataSortState {
@@ -51,44 +50,115 @@ type SorterFnOption = (
5150
5251type RowKeyOption = (row : any ) => any ;
5352
54- /** 通过配置的 columns 计算表头跨行,跨列 */
55- function calculateSpan(headers : ColumnOption [], level = 0 ): ColumnOption [] {
56- if (! Array .isArray (headers )) {
57- return [];
53+ function getLeftStart(id : string , left : [string , number ][]) {
54+ let start = 0 ;
55+ const len = left .length ;
56+ let isFirst = false ;
57+ for (let i = 0 ; i < len ; i ++ ) {
58+ const item = left [i ];
59+ if (item [0 ] === id ) {
60+ if (i === 0 ) {
61+ isFirst = true ;
62+ }
63+ break ;
64+ }
65+ start += item [1 ];
66+ }
67+ return { start , isFirst };
68+ }
69+
70+ function getRightStart(id : string , right : [string , number ][]) {
71+ let start = 0 ;
72+ let isFirst = false ;
73+ const len = right .length ;
74+ for (let i = len - 1 ; i >= 0 ; i -- ) {
75+ const item = right [i ];
76+ if (item [0 ] === id ) {
77+ if (i === len - 1 ) {
78+ isFirst = true ;
79+ }
80+ break ;
81+ }
82+ start += item [1 ];
5883 }
84+ return { start , isFirst };
85+ }
86+
87+ function getCommonStyle(
88+ column : ColumnOption ,
89+ fl : [string , number ][],
90+ fr : [string , number ][],
91+ ): CSSProperties {
92+ const res: CSSProperties = { ... column .style };
93+ if (column .width != null ) {
94+ if (typeof column .width === ' number' ) {
95+ res .width = ` ${column .width }px ` ;
96+ } else {
97+ res .width = column .width ;
98+ }
99+ }
100+ return res ;
101+ }
59102
60- const spans = headers .map ((header ) => {
103+ /** 通过配置的 columns 计算表头跨行,跨列 */
104+ function calculateSpan(
105+ headers : ColumnOption [],
106+ level = 0 ,
107+ leftFixed : [string , number ][],
108+ rightFixed : [string , number ][],
109+ ): ColumnOption [] {
110+ const tmpCols = [];
111+ for (let i = 0 , len = headers .length ; i < len ; i ++ ) {
112+ const header = headers [i ];
113+ if (header .id == null ) {
114+ header .id = header .key || header .title ;
115+ }
116+ if (isBlank (header .id )) {
117+ header .id = random (6 ) as string ;
118+ }
119+ if (header .fixed != null ) {
120+ const widNum = parseInt (` ${header .width || 0 } ` );
121+ if (header .fixed === ' left' ) {
122+ leftFixed .push ([header .id as string , widNum ]);
123+ } else if (header .fixed === ' right' ) {
124+ rightFixed .push ([header .id as string , widNum ]);
125+ }
126+ }
61127 // 如果有子级元素,递归计算
62128 if (header .children != null ) {
63129 let titleColspan = header .titleColspan ;
64- const childrenSpans = calculateSpan (header .children , level + 1 );
130+ const childrenSpans = calculateSpan (
131+ header .children ,
132+ level + 1 ,
133+ leftFixed ,
134+ rightFixed ,
135+ );
65136 if (titleColspan == null ) {
66137 titleColspan = childrenSpans .reduce (
67138 (sum , childSpan ) => sum + (childSpan .titleColspan || 0 ),
68139 0 ,
69140 );
70141 }
71- return {
142+ tmpCols . push ( {
72143 ... header ,
73144 titleColspan: titleColspan ,
74145 titleRowspan: header .titleRowspan || 1 ,
75146 children: childrenSpans ,
76- };
147+ }) ;
77148 } else {
78149 let titleRowspan = header .titleRowspan ;
79150 if (titleRowspan == null ) {
80151 titleRowspan = getMaxDepth (headers );
81152 }
82153 // 如果元素没有子级,意味着它占满从当前层级到最底层的所有行
83- return {
154+ tmpCols . push ( {
84155 ... header ,
85156 titleColspan: header .titleColspan || 1 ,
86157 titleRowspan: titleRowspan ,
87- };
158+ }) ;
88159 }
89- });
90-
91- return spans ;
160+ }
161+ return tmpCols ;
92162}
93163
94164// 递归获取最深的层级数
@@ -164,8 +234,18 @@ export default defineComponent({
164234 order: ' ' ,
165235 });
166236 const sourceData = ref (props .data );
167- const parsedColumns = calculateSpan (props .columns , 0 );
168-
237+ /** 缓存列样式, 避免每次遍历列都重新计算 */
238+ const globalColStyles: Record <string , CSSProperties > = {};
239+ /** 左边固定列 */
240+ const fixedLeft: [string , number ][] = [];
241+ /** 右边固定列 */
242+ const fixedRight: [string , number ][] = [];
243+ const parsedColumns = calculateSpan (
244+ props .columns ,
245+ 0 ,
246+ fixedLeft ,
247+ fixedRight ,
248+ );
169249 watch (
170250 () => props .data ,
171251 () => {
@@ -256,10 +336,6 @@ export default defineComponent({
256336 }
257337 }
258338
259- if (column .type != null && column .width == null ) {
260- column .width = 40 ;
261- }
262-
263339 if (column .width ) {
264340 let colWidth: string = column .width as string ;
265341 if (typeof column .width === ' number' ) {
0 commit comments