uview-plus 3.4.78 → 3.4.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/changelog.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 3.4.80(2025-08-10)
2
+ feat: 新增table2固定列对树状支持
3
+
4
+ ## 3.4.79(2025-08-09)
5
+ feat: table2组件支持左侧固定列功能
6
+
1
7
  ## 3.4.78(2025-08-09)
2
8
  fix: 修复table2在popup弹窗中无法横向滚动
3
9
 
File without changes
@@ -1,99 +1,175 @@
1
1
  <template>
2
- <scroll-view scroll-x class="u-table2" :style="{ height: height ? height + 'px' : 'auto' }">
3
- <!-- 表头 -->
4
- <view v-if="showHeader" class="u-table-header" :class="{ 'u-table-sticky': fixedHeader }" :style="{minWidth: scrollWidth}">
5
- <view class="u-table-row">
6
- <view v-for="(col, colIndex) in columns" :key="col.key" class="u-table-cell"
7
- :style="headerColStyle(col)"
8
- :class="[
9
- col.align ? 'u-text-' + col.align : '',
10
- headerCellClassName ? headerCellClassName(col) : '',
11
- col.fixed === 'left' ? 'u-table-fixed-left' : '',
12
- col.fixed === 'right' ? 'u-table-fixed-right' : ''
13
- ]" @click="handleHeaderClick(col)">
14
- <slot name="header" :column="col" :columnIndex="colIndex" :level="1">
15
- </slot>
16
- <text v-if="!$slots['header']">{{ col.title }}</text>
17
- <template v-if="col.sortable">
18
- <slot name="headerSort" :sortStatus="getSortValue(col.key)" :column="col"
19
- :columnIndex="colIndex" :level="1">
2
+ <view class="u-table2">
3
+ <scroll-view scroll-x class="u-table2-content" :style="{ height: height ? height + 'px' : 'auto' }" @scroll="onScroll">
4
+ <!-- 表头 -->
5
+ <view v-if="showHeader" class="u-table-header" :class="{ 'u-table-sticky': fixedHeader }" :style="{minWidth: scrollWidth}">
6
+ <view class="u-table-row">
7
+ <view v-for="(col, colIndex) in columns" :key="col.key" class="u-table-cell"
8
+ :style="headerColStyle(col)"
9
+ :class="[col.align ? 'u-text-' + col.align : '',
10
+ headerCellClassName ? headerCellClassName(col) : '',
11
+ getFixedClass(col)
12
+ ]" @click="handleHeaderClick(col)">
13
+ <slot name="header" :column="col" :columnIndex="colIndex" :level="1">
20
14
  </slot>
21
- <view v-if="!$slots['headerSort']">
22
- {{ getSortIcon(col.key) }}
23
- </view>
24
- </template>
15
+ <text v-if="!$slots['header']">{{ col.title }}</text>
16
+ <template v-if="col.sortable">
17
+ <slot name="headerSort" :sortStatus="getSortValue(col.key)" :column="col"
18
+ :columnIndex="colIndex" :level="1">
19
+ </slot>
20
+ <view v-if="!$slots['headerSort']">
21
+ {{ getSortIcon(col.key) }}
22
+ </view>
23
+ </template>
24
+ </view>
25
25
  </view>
26
26
  </view>
27
- </view>
28
27
 
29
- <!-- 表体 -->
30
- <view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
31
- <template v-if="data && data.length > 0">
32
- <template v-for="(row, index) in sortedData" :key="row[rowKey] || index">
33
- <view class="u-table-row" :class="[
34
- highlightCurrentRow && currentRow === row ? 'u-table-row-highlight' : '',
35
- rowClassName ? rowClassName(row, index) : '',
36
- stripe && index % 2 === 1 ? 'u-table-row-zebra' : ''
37
- ]" @click="handleRowClick(row)">
38
- <view v-for="(col, colIndex) in columns" :key="col.key"
39
- class="u-table-cell" :class="[
40
- col.align ? 'u-text-' + col.align : '',
41
- cellClassName ? cellClassName(row, col) : '',
42
- col.fixed === 'left' ? 'u-table-fixed-left' : '',
43
- col.fixed === 'right' ? 'u-table-fixed-right' : ''
44
- ]" :style="cellStyleInner({row: row, column: col,
45
- rowIndex: index, columnIndex: colIndex, level: 0})">
46
- <!-- 复选框列 -->
47
- <view v-if="col.type === 'selection'">
48
- <checkbox :checked="isSelected(row)"
49
- @click.stop="toggleSelect(row)" />
50
- </view>
28
+ <!-- 表体 -->
29
+ <view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
30
+ <template v-if="data && data.length > 0">
31
+ <template v-for="(row, index) in sortedData" :key="row[rowKey] || index">
32
+ <view class="u-table-row" :class="[highlightCurrentRow && currentRow === row ? 'u-table-row-highlight' : '',
33
+ rowClassName ? rowClassName(row, index) : '',
34
+ stripe && index % 2 === 1 ? 'u-table-row-zebra' : ''
35
+ ]" @click="handleRowClick(row)">
36
+ <view v-for="(col, colIndex) in columns" :key="col.key"
37
+ class="u-table-cell" :class="[col.align ? 'u-text-' + col.align : '',
38
+ cellClassName ? cellClassName(row, col) : '',
39
+ getFixedClass(col)
40
+ ]" :style="cellStyleInner({row: row, column: col,
41
+ rowIndex: index, columnIndex: colIndex, level: 0})">
42
+ <!-- 复选框列 -->
43
+ <view v-if="col.type === 'selection'">
44
+ <checkbox :checked="isSelected(row)"
45
+ @click.stop="toggleSelect(row)" />
46
+ </view>
47
+
48
+ <!-- 树形结构展开图标 -->
49
+ <view v-else-if="col.type === 'expand'" @click.stop="toggleExpand(row)">
50
+ {{ isExpanded(row) ? '▼' : '▶' }}
51
+ </view>
51
52
 
52
- <!-- 树形结构展开图标 -->
53
- <view v-else-if="col.type === 'expand'"
54
- @click.stop="toggleExpand(row)">
55
- {{ isExpanded(row) ? '▼' : '▶' }}
53
+ <!-- 默认插槽或文本 -->
54
+ <slot name="cell" :row="row" :column="col"
55
+ :rowIndex="index" :columnIndex="colIndex">
56
+ <view class="u-table-cell_content">
57
+ {{ row[col.key] }}
58
+ </view>
59
+ </slot>
56
60
  </view>
61
+ </view>
57
62
 
58
- <!-- 默认插槽或文本 -->
59
- <slot name="cell" :row="row" :column="col"
60
- :rowIndex="index" :columnIndex="colIndex">
61
- <view class="u-table-cell_content">
62
- {{ row[col.key] }}
63
+ <!-- 子级渲染 -->
64
+ <template v-if="isExpanded(row) && row[treeProps.children] && row[treeProps.children].length">
65
+ <view v-for="childRow in row[treeProps.children]" :key="childRow[rowKey]"
66
+ class="u-table-row u-table-row-child">
67
+ <view v-for="(col2, col2Index) in columns" :key="col2.key" class="u-table-cell"
68
+ :style="cellStyleInner({row: childRow, column: col2,
69
+ rowIndex: index, columnIndex: col2Index, level: 1})">
70
+ <slot name="cell" :row="childRow" :column="col2" :prow="row"
71
+ :rowIndex="index" :columnIndex="col2Index" :level="1">
72
+ <view class="u-table-cell_content">
73
+ {{ childRow[col2.key] }}
74
+ </view>
75
+ </slot>
63
76
  </view>
77
+ </view>
78
+ </template>
79
+ </template>
80
+ </template>
81
+ <template v-else>
82
+ <slot name="empty">
83
+ </slot>
84
+ <view v-if="!$slots['empty']" class="u-table-empty">{{ emptyText }}</view>
85
+ </template>
86
+ </view>
87
+ </scroll-view>
88
+
89
+ <!-- 固定列浮动视图 -->
90
+ <view v-if="showFixedColumnShadow" class="u-table-fixed-shadow" :style="{ height: tableHeight }">
91
+ <!-- 表头 -->
92
+ <view v-if="showHeader" class="u-table-header" :class="{ 'u-table-sticky': fixedHeader }" :style="{minWidth: scrollWidth}">
93
+ <view class="u-table-row">
94
+ <view v-for="(col, colIndex) in visibleFixedLeftColumns" :key="col.key" class="u-table-cell"
95
+ :style="headerColStyle(col)"
96
+ :class="[col.align ? 'u-text-' + col.align : '',
97
+ headerCellClassName ? headerCellClassName(col) : '',
98
+ getFixedClass(col)
99
+ ]" @click="handleHeaderClick(col)">
100
+ <slot name="header" :column="col" :columnIndex="colIndex" :level="1">
101
+ </slot>
102
+ <text v-if="!$slots['header']">{{ col.title }}</text>
103
+ <template v-if="col.sortable">
104
+ <slot name="headerSort" :sortStatus="getSortValue(col.key)" :column="col"
105
+ :columnIndex="colIndex" :level="1">
64
106
  </slot>
65
- </view>
107
+ <view v-if="!$slots['headerSort']">
108
+ {{ getSortIcon(col.key) }}
109
+ </view>
110
+ </template>
66
111
  </view>
112
+ </view>
113
+ </view>
67
114
 
68
- <!-- 子级渲染 -->
69
- <template v-if="isExpanded(row) && row[treeProps.children] && row[treeProps.children].length">
70
- <view v-for="childRow in row[treeProps.children]" :key="childRow[rowKey]"
71
- class="u-table-row u-table-row-child">
72
- <view v-for="(col2, col2Index) in columns" :key="col2.key" class="u-table-cell"
73
- :style="cellStyleInner({row: childRow, column: col2,
74
- rowIndex: index, columnIndex: col2Index, level: 1})">
75
- <slot name="cell" :row="childRow" :column="col2" :prow="row"
76
- :rowIndex="index" :columnIndex="col2Index" :level="1">
115
+ <!-- 表体 -->
116
+ <view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
117
+ <template v-if="data && data.length > 0">
118
+ <template v-for="(row, index) in sortedData" :key="row[rowKey] || index">
119
+ <view class="u-table-row" :class="[highlightCurrentRow && currentRow === row ? 'u-table-row-highlight' : '',
120
+ rowClassName ? rowClassName(row, index) : '',
121
+ stripe && index % 2 === 1 ? 'u-table-row-zebra' : ''
122
+ ]" @click="handleRowClick(row)">
123
+ <view v-for="(col, colIndex) in visibleFixedLeftColumns" :key="col.key"
124
+ class="u-table-cell" :class="[col.align ? 'u-text-' + col.align : '',
125
+ cellClassName ? cellClassName(row, col) : '',
126
+ getFixedClass(col)
127
+ ]" :style="cellStyleInner({row: row, column: col,
128
+ rowIndex: index, columnIndex: colIndex, level: 0})">
129
+ <!-- 复选框列 -->
130
+ <view v-if="col.type === 'selection'">
131
+ <checkbox :checked="isSelected(row)"
132
+ @click.stop="toggleSelect(row)" />
133
+ </view>
134
+
135
+ <!-- 树形结构展开图标 -->
136
+ <view v-else-if="col.type === 'expand'" @click.stop="toggleExpand(row)">
137
+ {{ isExpanded(row) ? '▼' : '▶' }}
138
+ </view>
139
+
140
+ <!-- 默认插槽或文本 -->
141
+ <slot name="cell" :row="row" :column="col"
142
+ :rowIndex="index" :columnIndex="colIndex">
77
143
  <view class="u-table-cell_content">
78
- {{ childRow[col2.key] }}
144
+ {{ row[col.key] }}
79
145
  </view>
80
146
  </slot>
81
147
  </view>
82
148
  </view>
149
+ <!-- 子级渲染 -->
150
+ <template v-if="isExpanded(row) && row[treeProps.children] && row[treeProps.children].length">
151
+ <view v-for="childRow in row[treeProps.children]" :key="childRow[rowKey]"
152
+ class="u-table-row u-table-row-child">
153
+ <view v-for="(col2, col2Index) in visibleFixedLeftColumns" :key="col2.key" class="u-table-cell"
154
+ :style="cellStyleInner({row: childRow, column: col2,
155
+ rowIndex: index, columnIndex: col2Index, level: 1})">
156
+ <slot name="cell" :row="childRow" :column="col2" :prow="row"
157
+ :rowIndex="index" :columnIndex="col2Index" :level="1">
158
+ <view class="u-table-cell_content">
159
+ {{ childRow[col2.key] }}
160
+ </view>
161
+ </slot>
162
+ </view>
163
+ </view>
164
+ </template>
83
165
  </template>
84
166
  </template>
85
- </template>
86
- <template v-else>
87
- <slot name="empty">
88
- </slot>
89
- <view v-if="!$slots['empty']" class="u-table-empty">{{ emptyText }}</view>
90
- </template>
167
+ </view>
91
168
  </view>
92
- </scroll-view>
169
+ </view>
93
170
  </template>
94
171
 
95
172
  <script>
96
- import { ref, watch, computed } from 'vue'
97
173
  import { addUnit, sleep } from '../../libs/function/index';
98
174
 
99
175
  export default {
@@ -241,26 +317,155 @@ export default {
241
317
  ],
242
318
  data() {
243
319
  return {
244
- scrollWidth: 'auto'
320
+ scrollWidth: 'auto',
321
+ // 将setup中的ref转换为data属性
322
+ expandedKeys: [...this.expandRowKeys],
323
+ selectedRows: [],
324
+ sortConditions: [],
325
+ currentRow: null,
326
+ scrollLeft: 0, // 新增滚动位置数据
327
+ showFixedColumnShadow: false, // 是否显示固定列阴影
328
+ fixedLeftColumns: [], // 左侧固定列
329
+ tableHeight: 'auto', // 表格高度
330
+ rowHeight: 40 // 行高
245
331
  }
246
332
  },
247
333
  mounted() {
248
334
  this.getComponentWidth()
335
+ // 处理currentRowKey初始化
336
+ if (this.currentRowKey !== null) {
337
+ const found = this.data.find(item => item[this.rowKey] === this.currentRowKey);
338
+ if (found) {
339
+ this.currentRow = found;
340
+ }
341
+ }
342
+ // 获取固定列
343
+ this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
344
+ },
345
+ computed: {
346
+ // 将setup中的computed转换为computed属性
347
+ filteredData() {
348
+ return this.data.filter(row => {
349
+ return Object.keys(this.filters).every(key => {
350
+ const filter = this.filters[key];
351
+ if (!filter) return true;
352
+ return row[key]?.toString().includes(filter.toString());
353
+ });
354
+ });
355
+ },
356
+ sortedData() {
357
+ if (!this.sortConditions.length) return this.filteredData;
358
+
359
+ const data = [...this.filteredData];
360
+
361
+ return data.sort((a, b) => {
362
+ for (const condition of this.sortConditions) {
363
+ const { field, order } = condition;
364
+ let valA = a[field];
365
+ let valB = b[field];
366
+
367
+ if (this.sortMethod) {
368
+ const result = this.sortMethod(a, b, field);
369
+ if (result !== 0) return result * (order === 'ascending' ? 1 : -1);
370
+ }
371
+
372
+ if (valA < valB) return order === 'ascending' ? -1 : 1;
373
+ if (valA > valB) return order === 'ascending' ? 1 : -1;
374
+ }
375
+ return 0;
376
+ });
377
+ },
378
+ // 计算当前应该显示的固定左侧列
379
+ visibleFixedLeftColumns() {
380
+ if (this.scrollLeft <= 0) {
381
+ return [];
382
+ }
383
+
384
+ let totalWidth = 0;
385
+ let fixedWidth = 0;
386
+ const visibleColumns = [];
387
+
388
+ // 遍历所有列,不仅仅是固定列
389
+ for (let i = 0; i < this.columns.length; i++) {
390
+ const col = this.columns[i];
391
+ const colWidth = col.width ? parseInt(col.width) : 100; // 默认宽度100px
392
+
393
+ // 如果是固定列且滚动位置足够显示该列
394
+ if (col.fixed === 'left' && this.scrollLeft > totalWidth - fixedWidth) {
395
+ visibleColumns.push(col);
396
+ fixedWidth += colWidth;
397
+ }
398
+
399
+ totalWidth += colWidth;
400
+ }
401
+
402
+ return visibleColumns;
403
+ }
404
+ },
405
+ watch: {
406
+ // 将setup中的watch转换为watch属性
407
+ expandRowKeys: {
408
+ handler(newVal) {
409
+ this.expandedKeys = [...newVal];
410
+ },
411
+ immediate: true
412
+ },
413
+ currentRowKey: {
414
+ handler(newVal) {
415
+ const found = this.data.find(item => item[this.rowKey] === newVal);
416
+ if (found) {
417
+ this.currentRow = found;
418
+ }
419
+ },
420
+ immediate: true
421
+ },
422
+ columns: {
423
+ handler() {
424
+ // this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
425
+ },
426
+ deep: true,
427
+ immediate: false
428
+ }
249
429
  },
250
- computed: {
251
- },
252
430
  methods: {
253
431
  addUnit,
254
- headerColStyle(col) {
255
- let style = {
256
- width: col.width ? addUnit(col.width) : 'auto',
257
- flex: col.width ? 'none' : 1
258
- };
259
- if (col?.style) {
260
- style = {...style, ...col?.style};
261
- }
262
- return style;
263
- },
432
+ onScroll(e) {
433
+ this.scrollLeft = e.detail.scrollLeft;
434
+ // 获取所有左侧固定列
435
+ this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
436
+ // 计算是否需要显示固定列阴影
437
+ if (this.fixedLeftColumns.length > 0) {
438
+ this.showFixedColumnShadow = this.scrollLeft > 0;
439
+ }
440
+ },
441
+
442
+ getFixedShadowStyle(col, index) {
443
+ let style = {
444
+ width: col.width ? addUnit(col.width) : 'auto',
445
+ };
446
+
447
+ if (col?.style) {
448
+ style = {...style, ...col?.style};
449
+ }
450
+
451
+ return style;
452
+ },
453
+
454
+ getFixedClass(col) {
455
+ return ''; // 不再使用原来的固定列样式类
456
+ },
457
+
458
+ headerColStyle(col) {
459
+ let style = {
460
+ width: col.width ? addUnit(col.width) : 'auto',
461
+ flex: col.width ? 'none' : 1
462
+ };
463
+ if (col?.style) {
464
+ style = {...style, ...col?.style};
465
+ }
466
+ return style;
467
+ },
468
+
264
469
  setCellStyle(e) {
265
470
  this.cellStyle = e
266
471
  },
@@ -285,172 +490,99 @@ export default {
285
490
  this.$uGetRect('.u-table-row').then(size => {
286
491
  this.scrollWidth = size.width + 'px'
287
492
  })
493
+
494
+ // 获取表格高度
495
+ // this.$uGetRect('.u-table2').then(size => {
496
+ // this.tableHeight = size.height + 'px';
497
+ // })
288
498
  },
289
- },
290
- setup(props, { emit }) {
291
- const expandedKeys = ref([...props.expandRowKeys]);
292
- const selectedRows = ref([]);
293
- const sortConditions = ref([]);
294
-
295
- // 当前高亮行
296
- const currentRow = ref(null);
297
-
298
- watch(
299
- () => props.expandRowKeys,
300
- newVal => {
301
- expandedKeys.value = [...newVal];
302
- }
303
- );
304
-
305
- watch(
306
- () => props.currentRowKey,
307
- newVal => {
308
- const found = props.data.find(item => item[props.rowKey] === newVal);
309
- if (found) {
310
- currentRow.value = found;
311
- }
312
- }
313
- );
314
-
315
- // 过滤后的数据
316
- const filteredData = computed(() => {
317
- return props.data.filter(row => {
318
- return Object.keys(props.filters).every(key => {
319
- const filter = props.filters[key];
320
- if (!filter) return true;
321
- return row[key]?.toString().includes(filter.toString());
322
- });
323
- });
324
- });
325
-
326
- // 排序后的数据
327
- const sortedData = computed(() => {
328
- if (!sortConditions.value.length) return filteredData.value;
329
-
330
- const data = [...filteredData.value];
331
-
332
- return data.sort((a, b) => {
333
- for (const condition of sortConditions.value) {
334
- const { field, order } = condition;
335
- let valA = a[field];
336
- let valB = b[field];
337
-
338
- if (props.sortMethod) {
339
- const result = props.sortMethod(a, b, field);
340
- if (result !== 0) return result * (order === 'ascending' ? 1 : -1);
341
- }
342
-
343
- if (valA < valB) return order === 'ascending' ? -1 : 1;
344
- if (valA > valB) return order === 'ascending' ? 1 : -1;
345
- }
346
- return 0;
347
- });
348
- });
349
-
350
- function handleRowClick(row) {
351
- if (props.highlightCurrentRow) {
352
- const oldRow = currentRow.value;
353
- currentRow.value = row;
354
- emit('current-change', row, oldRow);
499
+ // 将setup中的函数转换为methods
500
+ handleRowClick(row) {
501
+ if (this.highlightCurrentRow) {
502
+ const oldRow = this.currentRow;
503
+ this.currentRow = row;
504
+ this.$emit('current-change', row, oldRow);
355
505
  }
356
- emit('row-click', row);
357
- }
358
-
359
- function handleHeaderClick(column) {
506
+ this.$emit('row-click', row);
507
+ },
508
+ handleHeaderClick(column) {
360
509
  if (!column.sortable) return;
361
510
 
362
- const index = sortConditions.value.findIndex(c => c.field === column.key);
511
+ const index = this.sortConditions.findIndex(c => c.field === column.key);
363
512
  let newOrder = 'ascending';
364
513
 
365
514
  if (index >= 0) {
366
- if (sortConditions.value[index].order === 'ascending') {
515
+ if (this.sortConditions[index].order === 'ascending') {
367
516
  newOrder = 'descending';
368
517
  } else {
369
- sortConditions.value.splice(index, 1);
370
- emit('sort-change', sortConditions.value);
518
+ this.sortConditions.splice(index, 1);
519
+ this.$emit('sort-change', this.sortConditions);
371
520
  return;
372
521
  }
373
522
  }
374
523
 
375
- if (!props.multiSort) {
376
- sortConditions.value = [{ field: column.key, order: newOrder }];
524
+ if (!this.multiSort) {
525
+ this.sortConditions = [{ field: column.key, order: newOrder }];
377
526
  } else {
378
527
  if (index >= 0) {
379
- sortConditions.value[index].order = newOrder;
528
+ this.sortConditions[index].order = newOrder;
380
529
  } else {
381
- sortConditions.value.push({ field: column.key, order: newOrder });
530
+ this.sortConditions.push({ field: column.key, order: newOrder });
382
531
  }
383
532
  }
384
533
 
385
- emit('sort-change', sortConditions.value);
386
- }
387
-
388
- function getSortIcon(field) {
389
- const cond = sortConditions.value.find(c => c.field === field);
534
+ this.$emit('sort-change', this.sortConditions);
535
+ },
536
+ getSortIcon(field) {
537
+ const cond = this.sortConditions.find(c => c.field === field);
390
538
  if (!cond) return '';
391
539
  return cond.order === 'ascending' ? '↑' : '↓';
392
- }
393
-
394
- function getSortValue(field) {
395
- const cond = sortConditions.value.find(c => c.field === field);
540
+ },
541
+ getSortValue(field) {
542
+ const cond = this.sortConditions.find(c => c.field === field);
396
543
  if (!cond) return '';
397
544
  return cond.order === 'ascending';
398
- }
399
-
400
- function toggleSelect(row) {
401
- const index = selectedRows.value.findIndex(r => r[props.rowKey] === row[props.rowKey]);
545
+ },
546
+ toggleSelect(row) {
547
+ const index = this.selectedRows.findIndex(r => r[this.rowKey] === row[this.rowKey]);
402
548
  if (index >= 0) {
403
- selectedRows.value.splice(index, 1);
549
+ this.selectedRows.splice(index, 1);
404
550
  } else {
405
- selectedRows.value.push(row);
551
+ this.selectedRows.push(row);
406
552
  }
407
- emit('selection-change', selectedRows.value);
408
- emit('select', row);
409
- }
410
-
411
- function isSelected(row) {
412
- return selectedRows.value.some(r => r[props.rowKey] === row[props.rowKey]);
413
- }
414
-
415
- function toggleExpand(row) {
416
- const key = row[props.rowKey];
417
- const index = expandedKeys.value.indexOf(key);
553
+ this.$emit('selection-change', this.selectedRows);
554
+ this.$emit('select', row);
555
+ },
556
+ isSelected(row) {
557
+ return this.selectedRows.some(r => r[this.rowKey] === row[this.rowKey]);
558
+ },
559
+ toggleExpand(row) {
560
+ const key = row[this.rowKey];
561
+ const index = this.expandedKeys.indexOf(key);
418
562
  if (index === -1) {
419
- expandedKeys.value.push(key);
563
+ this.expandedKeys.push(key);
420
564
  } else {
421
- expandedKeys.value.splice(index, 1);
565
+ this.expandedKeys.splice(index, 1);
422
566
  }
423
- emit('expand-change', expandedKeys.value);
424
- }
425
-
426
- function isExpanded(row) {
427
- return expandedKeys.value.includes(row[props.rowKey]);
567
+ this.$emit('expand-change', this.expandedKeys);
568
+ },
569
+ isExpanded(row) {
570
+ return this.expandedKeys.includes(row[this.rowKey]);
428
571
  }
429
-
430
- return {
431
- currentRow,
432
- sortedData,
433
- expandedKeys,
434
- selectedRows,
435
- sortConditions,
436
- handleRowClick,
437
- handleHeaderClick,
438
- getSortValue,
439
- getSortIcon,
440
- toggleSelect,
441
- isSelected,
442
- toggleExpand,
443
- isExpanded
444
- };
445
572
  }
446
573
  };
447
574
  </script>
448
575
 
449
576
  <style lang="scss" scoped>
577
+ .u-table2-wrapper {
578
+ position: relative;
579
+ }
580
+
450
581
  .u-table2 {
451
582
  width: auto;
452
583
  overflow: auto;
453
584
  white-space: nowrap;
585
+ position: relative;
454
586
 
455
587
  .u-table-header {
456
588
  min-width: 100% !important;
@@ -461,6 +593,7 @@ export default {
461
593
  .u-table-body {
462
594
  min-width: 100% !important;
463
595
  width: fit-content;
596
+ position: relative;
464
597
  }
465
598
 
466
599
  .u-table-sticky {
@@ -475,6 +608,8 @@ export default {
475
608
  align-items: center;
476
609
  border-bottom: 1rpx solid #ebeef5;
477
610
  overflow: hidden;
611
+ position: relative;
612
+ min-height: 40px;
478
613
  }
479
614
 
480
615
  .u-table-cell {
@@ -488,18 +623,6 @@ export default {
488
623
  text-overflow: ellipsis;
489
624
  }
490
625
 
491
- .u-table-fixed-left {
492
- position: sticky;
493
- left: 0;
494
- z-index: 9;
495
- }
496
-
497
- .u-table-fixed-right {
498
- position: sticky;
499
- right: 0;
500
- z-index: 9;
501
- }
502
-
503
626
  .u-table-row-zebra {
504
627
  background-color: #fafafa;
505
628
  }
@@ -526,4 +649,36 @@ export default {
526
649
  text-align: right;
527
650
  }
528
651
  }
529
- </style>
652
+
653
+ // 固定列浮动视图
654
+ .u-table-fixed-shadow {
655
+ position: absolute;
656
+ top: 0;
657
+ left: 0;
658
+ width: auto;
659
+ z-index: 20;
660
+ box-shadow: 2px 0 5px rgba(0, 0, 0, 0.15);
661
+ overflow: hidden;
662
+ background-color: #ffffff;
663
+ }
664
+
665
+ .u-table-fixed-row {
666
+ display: flex;
667
+ flex-direction: row;
668
+ align-items: center;
669
+ border-bottom: 1rpx solid #ebeef5;
670
+ position: relative;
671
+ }
672
+
673
+ .u-table-fixed-cell {
674
+ flex: 1;
675
+ display: flex;
676
+ flex-direction: row;
677
+ padding: 5px 4px;
678
+ font-size: 14px;
679
+ white-space: nowrap;
680
+ overflow: hidden;
681
+ text-overflow: ellipsis;
682
+ background-color: #fff;
683
+ }
684
+ </style>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "id": "uview-plus",
3
3
  "name": "uview-plus",
4
4
  "displayName": "零云®uview-plus3.0重磅发布,全面的Vue3鸿蒙跨端移动组件库,组件丰富维护更新稳定。",
5
- "version": "3.4.78",
5
+ "version": "3.4.80",
6
6
  "description": "零云®uview-plus已兼容vue3,100+全面的组件和便捷的工具会让您信手拈来,如鱼得水。",
7
7
  "keywords": [
8
8
  "uview",