@tdesign/uniapp 0.8.1 → 0.9.1

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.
Files changed (287) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/action-sheet/README.en-US.md +4 -3
  3. package/dist/action-sheet/README.md +4 -3
  4. package/dist/action-sheet/action-sheet.vue +16 -12
  5. package/dist/action-sheet/computed.js +1 -1
  6. package/dist/action-sheet/props.ts +5 -0
  7. package/dist/action-sheet/type.ts +6 -1
  8. package/dist/avatar/README.en-US.md +1 -1
  9. package/dist/avatar/README.md +1 -1
  10. package/dist/avatar/avatar.vue +10 -9
  11. package/dist/avatar-group/avatar-group.vue +4 -4
  12. package/dist/back-top/README.en-US.md +1 -1
  13. package/dist/back-top/README.md +1 -1
  14. package/dist/back-top/back-top.vue +5 -4
  15. package/dist/badge/README.en-US.md +2 -1
  16. package/dist/badge/README.md +2 -1
  17. package/dist/badge/badge.css +1 -1
  18. package/dist/badge/badge.vue +4 -2
  19. package/dist/button/README.en-US.md +1 -1
  20. package/dist/button/README.md +1 -1
  21. package/dist/button/button.vue +17 -11
  22. package/dist/calendar/README.en-US.md +1 -1
  23. package/dist/calendar/README.md +1 -1
  24. package/dist/calendar/calendar-header.vue +2 -1
  25. package/dist/calendar/calendar.vue +15 -9
  26. package/dist/calendar/template.vue +12 -9
  27. package/dist/cascader/README.en-US.md +1 -1
  28. package/dist/cascader/README.md +1 -1
  29. package/dist/cascader/cascader.vue +8 -8
  30. package/dist/cell/README.en-US.md +1 -1
  31. package/dist/cell/README.md +1 -1
  32. package/dist/cell/cell.vue +34 -36
  33. package/dist/cell-group/cell-group.vue +5 -3
  34. package/dist/check-tag/check-tag.vue +6 -3
  35. package/dist/checkbox/README.en-US.md +1 -1
  36. package/dist/checkbox/README.md +1 -1
  37. package/dist/checkbox/checkbox.vue +5 -4
  38. package/dist/checkbox-group/checkbox-group.vue +5 -3
  39. package/dist/col/col.vue +7 -3
  40. package/dist/collapse/README.en-US.md +1 -1
  41. package/dist/collapse/README.md +1 -1
  42. package/dist/collapse/collapse.vue +6 -4
  43. package/dist/collapse-panel/collapse-panel.vue +15 -6
  44. package/dist/color-picker/README.en-US.md +1 -1
  45. package/dist/color-picker/README.md +1 -1
  46. package/dist/color-picker/color-picker.vue +9 -7
  47. package/dist/color-picker/template.vue +2 -1
  48. package/dist/common/canvas/index.js +1 -1
  49. package/dist/common/shared/color-picker/color.js +1 -0
  50. package/dist/common/src/instantiationDecorator.js +1 -1
  51. package/dist/common/style/theme/index-light.css +282 -0
  52. package/dist/common/style/theme/index-light.less +9 -0
  53. package/dist/common/style/theme/raw/_components-light.less +8 -0
  54. package/dist/common/style/theme/raw/_light-only.less +181 -0
  55. package/dist/common/version.js +1 -1
  56. package/dist/config-provider/config-provider.vue +3 -1
  57. package/dist/count-down/README.en-US.md +1 -1
  58. package/dist/count-down/README.md +1 -1
  59. package/dist/count-down/count-down.vue +5 -3
  60. package/dist/date-time-picker/README.en-US.md +1 -1
  61. package/dist/date-time-picker/README.md +1 -1
  62. package/dist/date-time-picker/date-time-picker.vue +8 -6
  63. package/dist/date-time-picker/locale/dayjs.js +6 -6
  64. package/dist/demo-navbar/demo-navbar.vue +1 -1
  65. package/dist/dialog/README.en-US.md +1 -1
  66. package/dist/dialog/README.md +1 -1
  67. package/dist/dialog/dialog.vue +10 -7
  68. package/dist/dialog/index.js +2 -1
  69. package/dist/divider/README.en-US.md +1 -1
  70. package/dist/divider/README.md +1 -1
  71. package/dist/divider/divider.vue +4 -2
  72. package/dist/draggable/draggable.vue +5 -2
  73. package/dist/drawer/README.en-US.md +1 -1
  74. package/dist/drawer/README.md +1 -1
  75. package/dist/drawer/drawer.vue +7 -5
  76. package/dist/dropdown-item/dropdown-item.vue +16 -11
  77. package/dist/dropdown-menu/README.en-US.md +1 -1
  78. package/dist/dropdown-menu/README.md +1 -1
  79. package/dist/dropdown-menu/dropdown-menu.vue +11 -9
  80. package/dist/empty/README.en-US.md +1 -1
  81. package/dist/empty/README.md +1 -1
  82. package/dist/empty/empty.vue +5 -4
  83. package/dist/fab/README.en-US.md +1 -1
  84. package/dist/fab/README.md +1 -1
  85. package/dist/fab/fab.vue +9 -6
  86. package/dist/fab/props.ts +1 -1
  87. package/dist/fab/type.ts +1 -1
  88. package/dist/footer/README.en-US.md +1 -1
  89. package/dist/footer/README.md +1 -1
  90. package/dist/footer/footer.vue +8 -7
  91. package/dist/form/README.en-US.md +3 -1
  92. package/dist/form/README.md +3 -1
  93. package/dist/form/form.vue +4 -2
  94. package/dist/form/props.ts +9 -0
  95. package/dist/form/type.ts +5 -0
  96. package/dist/form-item/README.en-US.md +2 -1
  97. package/dist/form-item/README.md +2 -1
  98. package/dist/form-item/form-item.css +2 -2
  99. package/dist/form-item/form-item.vue +36 -27
  100. package/dist/form-item/props.ts +8 -0
  101. package/dist/form-item/type.ts +4 -0
  102. package/dist/grid/README.en-US.md +1 -1
  103. package/dist/grid/README.md +1 -1
  104. package/dist/grid/grid.vue +4 -3
  105. package/dist/grid-item/README.en-US.md +1 -1
  106. package/dist/grid-item/README.md +1 -1
  107. package/dist/grid-item/grid-item.vue +8 -6
  108. package/dist/guide/README.en-US.md +1 -1
  109. package/dist/guide/README.md +1 -1
  110. package/dist/guide/guide.vue +8 -7
  111. package/dist/icon/icon.vue +5 -2
  112. package/dist/image/README.en-US.md +1 -1
  113. package/dist/image/README.md +1 -1
  114. package/dist/image/image.vue +6 -5
  115. package/dist/image-viewer/README.en-US.md +4 -3
  116. package/dist/image-viewer/README.md +4 -3
  117. package/dist/image-viewer/image-viewer.css +12 -0
  118. package/dist/image-viewer/image-viewer.vue +84 -21
  119. package/dist/image-viewer/props.ts +5 -0
  120. package/dist/image-viewer/type.ts +6 -1
  121. package/dist/indexes/README.en-US.md +1 -1
  122. package/dist/indexes/README.md +1 -1
  123. package/dist/indexes/computed.js +6 -2
  124. package/dist/indexes/indexes.css +7 -2
  125. package/dist/indexes/indexes.vue +8 -5
  126. package/dist/indexes/props.ts +5 -0
  127. package/dist/indexes/type.ts +5 -0
  128. package/dist/indexes-anchor/README.en-US.md +1 -1
  129. package/dist/indexes-anchor/README.md +1 -1
  130. package/dist/indexes-anchor/indexes-anchor.vue +5 -3
  131. package/dist/input/README.en-US.md +1 -1
  132. package/dist/input/README.md +1 -1
  133. package/dist/input/input.vue +9 -7
  134. package/dist/link/README.en-US.md +1 -1
  135. package/dist/link/README.md +1 -1
  136. package/dist/link/link.vue +6 -3
  137. package/dist/loading/README.en-US.md +1 -1
  138. package/dist/loading/README.md +1 -1
  139. package/dist/loading/loading.vue +4 -2
  140. package/dist/message/index.js +2 -1
  141. package/dist/message/message.vue +4 -3
  142. package/dist/message-item/index.js +1 -1
  143. package/dist/message-item/message-item.vue +7 -5
  144. package/dist/mixins/page-scroll.js +1 -1
  145. package/dist/mixins/using-config.js +1 -1
  146. package/dist/mixins/using-custom-navbar.js +1 -1
  147. package/dist/navbar/README.en-US.md +1 -1
  148. package/dist/navbar/README.md +2 -2
  149. package/dist/navbar/navbar.vue +5 -4
  150. package/dist/notice-bar/README.en-US.md +1 -1
  151. package/dist/notice-bar/README.md +1 -1
  152. package/dist/notice-bar/notice-bar.vue +4 -3
  153. package/dist/overlay/README.en-US.md +1 -1
  154. package/dist/overlay/README.md +1 -1
  155. package/dist/overlay/overlay.vue +6 -3
  156. package/dist/picker/README.en-US.md +1 -1
  157. package/dist/picker/README.md +1 -1
  158. package/dist/picker/picker.vue +11 -9
  159. package/dist/picker-item/README.en-US.md +1 -1
  160. package/dist/picker-item/README.md +1 -1
  161. package/dist/picker-item/picker-item.vue +6 -5
  162. package/dist/popover/README.en-US.md +1 -1
  163. package/dist/popover/README.md +1 -1
  164. package/dist/popover/popover.vue +8 -5
  165. package/dist/popup/README.en-US.md +1 -1
  166. package/dist/popup/README.md +1 -1
  167. package/dist/popup/popup.vue +8 -5
  168. package/dist/progress/README.en-US.md +1 -1
  169. package/dist/progress/README.md +1 -1
  170. package/dist/progress/progress.vue +5 -4
  171. package/dist/pull-down-refresh/README.en-US.md +1 -1
  172. package/dist/pull-down-refresh/README.md +1 -1
  173. package/dist/pull-down-refresh/pull-down-refresh.vue +7 -5
  174. package/dist/qrcode/components/qrcode-canvas/qrcode-canvas.vue +8 -7
  175. package/dist/qrcode/components/qrcode-status/qrcode-status.vue +2 -1
  176. package/dist/qrcode/qrcode.vue +5 -3
  177. package/dist/radio/README.en-US.md +1 -1
  178. package/dist/radio/README.md +1 -1
  179. package/dist/radio/radio.vue +5 -4
  180. package/dist/radio-group/radio-group.vue +5 -4
  181. package/dist/rate/README.en-US.md +1 -1
  182. package/dist/rate/README.md +1 -1
  183. package/dist/rate/rate.vue +8 -5
  184. package/dist/result/README.en-US.md +1 -1
  185. package/dist/result/README.md +1 -1
  186. package/dist/result/result.vue +5 -4
  187. package/dist/row/row.vue +7 -3
  188. package/dist/scroll-view/scroll-view.vue +1 -1
  189. package/dist/search/README.en-US.md +1 -1
  190. package/dist/search/README.md +1 -1
  191. package/dist/search/search.css +5 -0
  192. package/dist/search/search.vue +21 -21
  193. package/dist/segmented/README.en-US.md +42 -0
  194. package/dist/segmented/README.md +75 -0
  195. package/dist/segmented/props.ts +31 -0
  196. package/dist/segmented/segmented.css +66 -0
  197. package/dist/segmented/segmented.vue +177 -0
  198. package/dist/segmented/type.ts +41 -0
  199. package/dist/side-bar/README.en-US.md +1 -1
  200. package/dist/side-bar/README.md +1 -1
  201. package/dist/side-bar/side-bar.vue +5 -3
  202. package/dist/side-bar-item/side-bar-item.vue +7 -6
  203. package/dist/skeleton/README.en-US.md +1 -1
  204. package/dist/skeleton/README.md +1 -1
  205. package/dist/skeleton/skeleton.vue +6 -3
  206. package/dist/slider/README.en-US.md +1 -1
  207. package/dist/slider/README.md +1 -1
  208. package/dist/slider/slider.vue +7 -5
  209. package/dist/step-item/step-item.vue +5 -4
  210. package/dist/stepper/README.en-US.md +1 -1
  211. package/dist/stepper/README.md +1 -1
  212. package/dist/stepper/stepper.vue +5 -3
  213. package/dist/steps/README.en-US.md +1 -1
  214. package/dist/steps/README.md +1 -1
  215. package/dist/steps/steps.vue +5 -3
  216. package/dist/sticky/sticky.vue +4 -3
  217. package/dist/swipe-cell/swipe-cell.vue +7 -5
  218. package/dist/swiper/README.en-US.md +1 -1
  219. package/dist/swiper/README.md +1 -1
  220. package/dist/swiper/swiper.vue +7 -5
  221. package/dist/swiper-nav/swiper-nav.vue +6 -3
  222. package/dist/switch/README.en-US.md +1 -1
  223. package/dist/switch/README.md +1 -1
  224. package/dist/switch/switch.vue +5 -4
  225. package/dist/tab-bar/README.en-US.md +1 -1
  226. package/dist/tab-bar/README.md +1 -1
  227. package/dist/tab-bar/tab-bar.vue +5 -3
  228. package/dist/tab-bar-item/tab-bar-item.vue +10 -10
  229. package/dist/tab-panel/tab-panel.vue +5 -3
  230. package/dist/table/README.en-US.md +72 -0
  231. package/dist/table/README.md +117 -0
  232. package/dist/table/base-table-props.ts +105 -0
  233. package/dist/table/props.ts +94 -0
  234. package/dist/table/table.css +251 -0
  235. package/dist/table/table.vue +582 -0
  236. package/dist/table/type.ts +180 -0
  237. package/dist/tabs/README.en-US.md +1 -1
  238. package/dist/tabs/README.md +1 -1
  239. package/dist/tabs/tabs.css +4 -0
  240. package/dist/tabs/tabs.vue +11 -9
  241. package/dist/tag/README.en-US.md +1 -1
  242. package/dist/tag/README.md +1 -1
  243. package/dist/tag/tag.vue +6 -3
  244. package/dist/textarea/README.en-US.md +1 -1
  245. package/dist/textarea/README.md +1 -1
  246. package/dist/textarea/textarea.vue +6 -3
  247. package/dist/theme-light.css +282 -0
  248. package/dist/theme-light.css.d.ts +2 -0
  249. package/dist/theme-light.less +1 -0
  250. package/dist/theme-light.less.d.ts +2 -0
  251. package/dist/toast/README.en-US.md +1 -1
  252. package/dist/toast/README.md +1 -1
  253. package/dist/toast/toast.vue +8 -7
  254. package/dist/transition/transition.vue +2 -2
  255. package/dist/tree-select/README.en-US.md +1 -1
  256. package/dist/tree-select/README.md +1 -1
  257. package/dist/tree-select/tree-select.vue +14 -9
  258. package/dist/types/action-sheet.d.ts +1 -1
  259. package/dist/types/avatar-group.d.ts +1 -1
  260. package/dist/types/avatar.d.ts +1 -1
  261. package/dist/types/back-top.d.ts +1 -1
  262. package/dist/types/badge.d.ts +1 -1
  263. package/dist/types/button.d.ts +1 -1
  264. package/dist/types/calendar.d.ts +1 -1
  265. package/dist/types/cascader.d.ts +1 -1
  266. package/dist/types/cell-group.d.ts +1 -1
  267. package/dist/types/cell.d.ts +1 -1
  268. package/dist/types/check-tag.d.ts +1 -1
  269. package/dist/types/checkbox-group.d.ts +1 -1
  270. package/dist/types/checkbox.d.ts +1 -1
  271. package/dist/types/col.d.ts +1 -1
  272. package/dist/types/collapse-panel.d.ts +1 -1
  273. package/dist/types/collapse.d.ts +1 -1
  274. package/dist/types/color-picker.d.ts +1 -1
  275. package/dist/types/index.d.ts +2 -0
  276. package/dist/types/segmented.d.ts +7 -0
  277. package/dist/types/table.d.ts +7 -0
  278. package/dist/upload/README.en-US.md +1 -1
  279. package/dist/upload/README.md +1 -1
  280. package/dist/upload/upload.vue +32 -32
  281. package/dist/watermark/README.en-US.md +1 -1
  282. package/dist/watermark/README.md +1 -1
  283. package/dist/watermark/utils/generateBase64Url.js +6 -6
  284. package/dist/watermark/watermark.vue +4 -3
  285. package/global.d.ts +2 -0
  286. package/package.json +33 -9
  287. package/{dist/script → script}/postinstall.js +18 -2
@@ -0,0 +1,582 @@
1
+ <template>
2
+ <view
3
+ :class="[
4
+ classPrefix,
5
+ tClass,
6
+ classPrefix + '--layout-' + tableLayout,
7
+ prefix + '-vertical-align-' + verticalAlign,
8
+ bordered ? classPrefix + '--bordered' : '',
9
+ stripe ? classPrefix + '--striped' : '',
10
+ (stripe && (maxHeight || height)) ? classPrefix + '--header-fixed' : '',
11
+ loading ? classPrefix + '--loading' : '',
12
+ rowspanAndColspan ? classPrefix + '--rowspan-colspan' : '',
13
+ hasFixedColumn ? classPrefix + '--column-fixed' : '',
14
+ ]"
15
+ :style="'' + tools._style([customStyle])"
16
+ >
17
+ <scroll-view
18
+ :class="contentClasses"
19
+ :style="tableContentStylesStr"
20
+ scroll-x
21
+ :scroll-y="!!(height || maxHeight)"
22
+ @scroll="onScroll"
23
+ >
24
+ <view
25
+ :class="classPrefix + '__table-elm'"
26
+ :style="tableElementStylesStr"
27
+ >
28
+ <!-- 表头 -->
29
+ <view
30
+ v-if="showHeader"
31
+ :class="[
32
+ classPrefix + '__header',
33
+ (maxHeight || height) ? classPrefix + '__header--fixed' : '',
34
+ ]"
35
+ >
36
+ <view :class="classPrefix + '__header-tr'">
37
+ <view
38
+ v-for="(col, colIndex) in columns"
39
+ :key="col.colKey || colIndex"
40
+ :class="[
41
+ classPrefix + '__th',
42
+ getThClassName(col, colIndex),
43
+ ]"
44
+ :style="'' + getColStyle(col, colIndex)"
45
+ >
46
+ <view :class="classPrefix + '__th-content'">
47
+ {{ col.title }}
48
+ </view>
49
+ </view>
50
+ </view>
51
+ </view>
52
+
53
+ <!-- 表体 -->
54
+ <view :class="classPrefix + '__body'">
55
+ <!-- 空数据 -->
56
+ <view
57
+ v-if="isEmpty"
58
+ :class="classPrefix + '__empty-row'"
59
+ >
60
+ <view :class="classPrefix + '__empty'">
61
+ <template v-if="empty">
62
+ {{ empty }}
63
+ </template>
64
+ <slot
65
+ v-else
66
+ name="empty"
67
+ />
68
+ </view>
69
+ </view>
70
+
71
+ <!-- 数据行 -->
72
+ <view
73
+ v-for="rowItem in renderData"
74
+ :key="rowItem.rowId"
75
+ :class="[classPrefix + '__tr', rowItem.rowClass]"
76
+ :style="rowItem.rowStyle"
77
+ @click="onRowClick(rowItem.rowIndex)"
78
+ >
79
+ <!-- #ifdef VUE2 -->
80
+ <!-- eslint-disable-next-line vue/no-unused-vars -->
81
+ <template v-for="(cell, tdIndex) in rowItem.cells">
82
+ <!-- #endif -->
83
+ <!-- #ifdef VUE3 -->
84
+ <template
85
+ v-for="(cell, tdIndex) in rowItem.cells"
86
+ :key="cell.colKey"
87
+ >
88
+ <!-- #endif -->
89
+
90
+ <view
91
+ v-if="!cell.skipped"
92
+ :key="cell.colKey"
93
+ :class="[
94
+ classPrefix + '__td',
95
+ cell.className,
96
+ cell.isLastRow ? classPrefix + '__td-last-row' : '',
97
+ cell.isFirstCol ? classPrefix + '__td-first-col' : '',
98
+ ]"
99
+ :style="'' + getColStyle(columns[tdIndex], tdIndex)"
100
+ @click.stop="onCellClick(rowItem.rowIndex, tdIndex)"
101
+ >
102
+ <view :class="classPrefix + '__td-content'">
103
+ {{ cell.content }}
104
+ </view>
105
+ </view>
106
+ <!-- #ifdef VUE3 -->
107
+ </template>
108
+ <!-- #endif -->
109
+
110
+ <!-- #ifdef VUE2 -->
111
+ </template>
112
+ <!-- #endif -->
113
+ </view>
114
+ </view>
115
+ </view>
116
+
117
+ <!-- 加载中 -->
118
+ <view
119
+ v-if="loading"
120
+ :class="classPrefix + '__loading--full'"
121
+ >
122
+ <slot name="loading">
123
+ <t-loading
124
+ :delay="(loadingProps && loadingProps.delay) || 0"
125
+ :duration="(loadingProps && loadingProps.duration) || 800"
126
+ :fullscreen="!!(loadingProps && loadingProps.fullscreen)"
127
+ :indicator="loadingProps && loadingProps.indicator !== undefined ? loadingProps.indicator : true"
128
+ :inherit-color="!!(loadingProps && loadingProps.inheritColor)"
129
+ :layout="(loadingProps && loadingProps.layout) || 'horizontal'"
130
+ :loading="loadingProps && loadingProps.loading !== undefined ? loadingProps.loading : true"
131
+ :pause="!!(loadingProps && loadingProps.pause)"
132
+ :progress="loadingProps && loadingProps.progress"
133
+ :reverse="!!(loadingProps && loadingProps.reverse)"
134
+ :size="(loadingProps && loadingProps.size) || '20px'"
135
+ :text="(loadingProps && loadingProps.text) || ''"
136
+ :theme="(loadingProps && loadingProps.theme) || 'circular'"
137
+ />
138
+ </slot>
139
+ </view>
140
+ </scroll-view>
141
+
142
+ <!-- 表尾总结行 -->
143
+ <view
144
+ v-if="footerSummary"
145
+ :class="classPrefix + '__bottom-content'"
146
+ >
147
+ {{ footerSummary }}
148
+ </view>
149
+ <slot name="footer-summary" />
150
+ </view>
151
+ </template>
152
+ <script>
153
+ import { prefix } from '../common/config';
154
+ import { uniComponent } from '../common/src/index';
155
+ import tools from '../common/utils.wxs';
156
+ import TLoading from '../loading/loading.vue';
157
+
158
+ import props from './base-table-props';
159
+
160
+
161
+ const name = `${prefix}-table`;
162
+
163
+ function getVal(obj, path) {
164
+ if (!obj || !path) return undefined;
165
+ const keys = path.split('.');
166
+ let result = obj;
167
+ keys.forEach((key) => {
168
+ if (result !== undefined && result !== null) {
169
+ result = result[key];
170
+ }
171
+ });
172
+ return result;
173
+ }
174
+
175
+ function formatCSSUnit(unit) {
176
+ if (!unit) return unit;
177
+ return Number.isNaN(Number(unit)) ? unit : `${unit}px`;
178
+ }
179
+
180
+ export default {
181
+ components: {
182
+ TLoading,
183
+ },
184
+ emits: [
185
+ 'row-click',
186
+ 'cell-click',
187
+ 'scroll',
188
+ 'scroll-to-bottom',
189
+ ],
190
+ ...uniComponent({
191
+ name,
192
+ options: {
193
+ styleIsolation: 'shared',
194
+ },
195
+ externalClasses: [
196
+ `${prefix}-class`,
197
+ ],
198
+ props: {
199
+ ...props,
200
+ },
201
+ data() {
202
+ return {
203
+ prefix,
204
+ classPrefix: name,
205
+ tools,
206
+ renderData: [],
207
+ isEmpty: false,
208
+ hasFixedColumn: false,
209
+ scrollableToLeft: false,
210
+ scrollableToRight: false,
211
+ fixedLeftOffsets: [],
212
+ fixedRightOffsets: [],
213
+ lastFixedLeftIndex: -1,
214
+ firstFixedRightIndex: -1,
215
+ fixedTopRows: 0,
216
+ fixedBottomRows: 0,
217
+ };
218
+ },
219
+ computed: {
220
+ contentClasses() {
221
+ const classes = [`${this.classPrefix}__content`];
222
+ if (this.scrollableToLeft) classes.push(`${this.classPrefix}__content--scrollable-to-left`);
223
+ if (this.scrollableToRight) classes.push(`${this.classPrefix}__content--scrollable-to-right`);
224
+ return classes.join(' ');
225
+ },
226
+ tableContentStylesStr() {
227
+ const styles = [];
228
+ if (this.height) styles.push(`height: ${formatCSSUnit(this.height)}`);
229
+ if (this.maxHeight) styles.push(`max-height: ${formatCSSUnit(this.maxHeight)}`);
230
+ return styles.join('; ');
231
+ },
232
+ tableElementStylesStr() {
233
+ // 优先使用用户指定的 tableContentWidth
234
+ if (this.tableContentWidth) {
235
+ return `width: ${formatCSSUnit(this.tableContentWidth)}`;
236
+ }
237
+ // 有固定列时,自动根据列宽之和计算 tableContentWidth
238
+ if (this.hasFixedColumn && this.columns && this.columns.length > 0) {
239
+ const totalWidth = this.columns.reduce((sum, col) => sum + parseFloat(String(col.width || 80)), 0);
240
+ return `width: ${totalWidth}px`;
241
+ }
242
+ return '';
243
+ },
244
+ },
245
+ watch: {
246
+ columns: {
247
+ handler() {
248
+ this.updateRenderData();
249
+ },
250
+ deep: true,
251
+ immediate: true,
252
+ },
253
+ data: {
254
+ handler() {
255
+ this.updateRenderData();
256
+ },
257
+ deep: true,
258
+ immediate: true,
259
+ },
260
+ cellEmptyContent() {
261
+ this.updateRenderData();
262
+ },
263
+ rowKey() {
264
+ this.updateRenderData();
265
+ },
266
+ rowspanAndColspan() {
267
+ this.updateRenderData();
268
+ },
269
+ fixedRows: {
270
+ handler() {
271
+ this.updateRenderData();
272
+ },
273
+ deep: true,
274
+ },
275
+ },
276
+ methods: {
277
+ getColStyle(col, colIndex) {
278
+ if (!col) return '';
279
+ const defaultColWidth = this.tableLayout === 'fixed' ? '80px' : undefined;
280
+ const width = formatCSSUnit(col.width || defaultColWidth);
281
+ const minWidth = !formatCSSUnit(col.width || defaultColWidth) && !col.minWidth && this.tableLayout === 'fixed' ? '80px' : formatCSSUnit(col.minWidth);
282
+ const styles = [];
283
+ // 当列设置了固定宽度时,使用 flex: 0 0 auto 防止被 flex 压缩,支持横向滚动
284
+ if (col.width) {
285
+ styles.push('flex: 0 0 auto');
286
+ }
287
+ if (width) styles.push(`width: ${width}`);
288
+ if (minWidth) styles.push(`min-width: ${minWidth}`);
289
+ // 固定列定位
290
+ if (col.fixed === 'left' && this.fixedLeftOffsets[colIndex] !== undefined) {
291
+ styles.push(`left: ${this.fixedLeftOffsets[colIndex]}px`);
292
+ } else if (col.fixed === 'right' && this.fixedRightOffsets[colIndex] !== undefined) {
293
+ styles.push(`right: ${this.fixedRightOffsets[colIndex]}px`);
294
+ }
295
+ return styles.join('; ');
296
+ },
297
+
298
+ getCustomClassName(className = '') {
299
+ const calcClassName = (name) => {
300
+ if (typeof name === 'function') {
301
+ return name() || '';
302
+ }
303
+ return name;
304
+ };
305
+
306
+ if (Array.isArray(className)) {
307
+ return className.map(calcClassName);
308
+ }
309
+ return [calcClassName(className)];
310
+ },
311
+
312
+ getThClassName(col, colIndex) {
313
+ const classes = [];
314
+ if (col.colKey) classes.push(`${name}__th-${col.colKey}`);
315
+ if (col.align && col.align !== 'left') classes.push(`${prefix}-align-${col.align}`);
316
+ if (col.fixed === 'left') classes.push(`${name}__cell--fixed-left`);
317
+ if (col.fixed === 'right') classes.push(`${name}__cell--fixed-right`);
318
+ if (col.className) classes.push(...this.getCustomClassName(col.className));
319
+ if (colIndex === this.lastFixedLeftIndex) classes.push(`${name}__cell--fixed-left-last`);
320
+ if (colIndex === this.firstFixedRightIndex) classes.push(`${name}__cell--fixed-right-first`);
321
+ return classes.join(' ');
322
+ },
323
+
324
+ updateRenderData() {
325
+ const { columns, data, cellEmptyContent, rowKey, rowspanAndColspan, fixedRows } = this;
326
+
327
+ // 解析 fixedRows
328
+ const fixedTopRows = (fixedRows && fixedRows[0]) || 0;
329
+ const fixedBottomRows = (fixedRows && fixedRows[1]) || 0;
330
+ this.fixedTopRows = fixedTopRows;
331
+ this.fixedBottomRows = fixedBottomRows;
332
+
333
+ // 是否有固定表头
334
+ const hasFixedHeader = !!(this.showHeader && (this.maxHeight || this.height));
335
+
336
+ const dataLen = (data || []).length;
337
+
338
+ // 检测是否有固定列
339
+ const hasFixedColumn = (columns || []).some(col => !!col.fixed);
340
+ this.hasFixedColumn = hasFixedColumn;
341
+
342
+ // 计算固定列偏移量
343
+ if (hasFixedColumn) {
344
+ const fixedLeftOffsets = [];
345
+ const fixedRightOffsets = [];
346
+ let leftOffset = 0;
347
+ for (let i = 0; i < (columns || []).length; i += 1) {
348
+ fixedLeftOffsets[i] = leftOffset;
349
+ const col = columns[i];
350
+ if (col.fixed === 'left') {
351
+ leftOffset += parseFloat(String(col.width || 80));
352
+ }
353
+ }
354
+ let rightOffset = 0;
355
+ for (let i = (columns || []).length - 1; i >= 0; i -= 1) {
356
+ fixedRightOffsets[i] = rightOffset;
357
+ const col = columns[i];
358
+ if (col.fixed === 'right') {
359
+ rightOffset += parseFloat(String(col.width || 80));
360
+ }
361
+ }
362
+ this.fixedLeftOffsets = fixedLeftOffsets;
363
+ this.fixedRightOffsets = fixedRightOffsets;
364
+
365
+ // 找到最后一个左固定列和第一个右固定列的索引
366
+ let lastLeft = -1;
367
+ let firstRight = -1;
368
+ (columns || []).forEach((col, index) => {
369
+ if (col.fixed === 'left') lastLeft = index;
370
+ if (col.fixed === 'right' && firstRight === -1) firstRight = index;
371
+ });
372
+ this.lastFixedLeftIndex = lastLeft;
373
+ this.firstFixedRightIndex = firstRight;
374
+
375
+ // 初始状态:可向右滚动
376
+ this.scrollableToRight = true;
377
+ this.scrollableToLeft = false;
378
+ }
379
+
380
+ // 计算合并单元格
381
+ const skipSpansMap = new Map();
382
+ if (rowspanAndColspan && data?.length && columns?.length) {
383
+ for (let i = 0; i < data.length; i += 1) {
384
+ const row = data[i];
385
+ for (let j = 0; j < columns.length; j += 1) {
386
+ const col = columns[j];
387
+ const cellKey = `${getVal(row, rowKey || 'id')}_${col.colKey || j}`;
388
+ const state = skipSpansMap.get(cellKey) || {};
389
+ const o = rowspanAndColspan({ row, col, rowIndex: i, colIndex: j }) || {};
390
+ if (o.rowspan || o.colspan || state.rowspan || state.colspan) {
391
+ if (o.rowspan) state.rowspan = o.rowspan;
392
+ if (o.colspan) state.colspan = o.colspan;
393
+ skipSpansMap.set(cellKey, state);
394
+ }
395
+ if (state.rowspan || state.colspan) {
396
+ const maxRowIndex = i + (state.rowspan || 1);
397
+ const maxColIndex = j + (state.colspan || 1);
398
+ for (let ri = i; ri < maxRowIndex; ri += 1) {
399
+ for (let ci = j; ci < maxColIndex; ci += 1) {
400
+ if (ri !== i || ci !== j) {
401
+ if (data[ri] && columns[ci]) {
402
+ const key = `${getVal(data[ri], rowKey || 'id')}_${columns[ci].colKey || ci}`;
403
+ const s = skipSpansMap.get(key) || {};
404
+ s.skipped = true;
405
+ skipSpansMap.set(key, s);
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
411
+ }
412
+ }
413
+ }
414
+
415
+ // 构建渲染数据
416
+ const renderData = (data || []).map((row, rowIndex) => {
417
+ const cells = (columns || []).map((col, colIndex) => {
418
+ const cellKey = `${getVal(row, rowKey || 'id')}_${col.colKey || colIndex}`;
419
+ const spanState = skipSpansMap.get(cellKey);
420
+
421
+ const tdClasses = [];
422
+ if (col.align && col.align !== 'left') tdClasses.push(`${prefix}-align-${col.align}`);
423
+ if (col.fixed === 'left') tdClasses.push(`${name}__cell--fixed-left`);
424
+ if (col.fixed === 'right') tdClasses.push(`${name}__cell--fixed-right`);
425
+ if (colIndex === this.lastFixedLeftIndex) tdClasses.push(`${name}__cell--fixed-left-last`);
426
+ if (colIndex === this.firstFixedRightIndex) tdClasses.push(`${name}__cell--fixed-right-first`);
427
+
428
+ let cellContent = '';
429
+ if (col.colKey === 'serial-number') {
430
+ cellContent = String(rowIndex + 1);
431
+ } else if (typeof col.cell === 'function') {
432
+ cellContent = col.cell({ row, col, rowIndex, colIndex });
433
+ } else {
434
+ const val = getVal(row, col.colKey || '');
435
+ if (val !== undefined && val !== null && val !== '') {
436
+ cellContent = String(val);
437
+ } else if (cellEmptyContent) {
438
+ cellContent = cellEmptyContent;
439
+ }
440
+ }
441
+
442
+ return {
443
+ colKey: col.colKey || String(colIndex),
444
+ content: cellContent,
445
+ className: tdClasses.join(' '),
446
+ skipped: spanState?.skipped || false,
447
+ rowspan: spanState?.rowspan || 0,
448
+ colspan: spanState?.colspan || 0,
449
+ isLastRow: !!(spanState?.rowspan && rowIndex + spanState.rowspan === data.length),
450
+ isFirstCol: !!(rowspanAndColspan && colIndex === 0),
451
+ };
452
+ });
453
+
454
+ // 固定行类名和样式
455
+ const rowClasses = [];
456
+ let rowStyle = '';
457
+ // 固定行的 z-index 需要高于固定列的 z-index(右侧固定列 z-index 为 31),否则横向滚动时固定列内容会覆盖固定行
458
+ const fixedRowZIndex = hasFixedColumn ? 32 : 2;
459
+ if (fixedTopRows > 0 && rowIndex < fixedTopRows) {
460
+ rowClasses.push(`${name}__row--fixed-top`);
461
+ // top/bottom 值将在 nextTick 中通过实际 DOM 测量来设置
462
+ rowStyle = `position: sticky; top: 0; z-index: ${fixedRowZIndex};`;
463
+ }
464
+ if (fixedBottomRows > 0 && rowIndex >= dataLen - fixedBottomRows) {
465
+ rowClasses.push(`${name}__row--fixed-bottom`);
466
+ if (rowIndex === dataLen - fixedBottomRows) {
467
+ rowClasses.push(`${name}__row--fixed-bottom-first`);
468
+ }
469
+ rowStyle = `position: sticky; bottom: 0; z-index: ${fixedRowZIndex};`;
470
+ }
471
+ // 冻结表尾行时,最后一行非冻结行去除下边框
472
+ if (fixedBottomRows > 0 && rowIndex === dataLen - fixedBottomRows - 1) {
473
+ rowClasses.push(`${name}__row--without-border-bottom`);
474
+ }
475
+
476
+ return {
477
+ rowIndex,
478
+ rowId: getVal(row, rowKey || 'id'),
479
+ cells,
480
+ row,
481
+ rowClass: rowClasses.join(' '),
482
+ rowStyle,
483
+ };
484
+ });
485
+
486
+ this.renderData = renderData;
487
+ this.isEmpty = !data || data.length === 0;
488
+
489
+ // 动态测量行高,修正固定行的 top/bottom 值
490
+ if (fixedTopRows > 0 || fixedBottomRows > 0) {
491
+ this.$nextTick(() => {
492
+ this.measureAndFixStickyPositions(hasFixedHeader, fixedTopRows, fixedBottomRows, dataLen);
493
+ });
494
+ }
495
+ },
496
+
497
+ measureAndFixStickyPositions(hasFixedHeader, fixedTopRows, fixedBottomRows, dataLen) {
498
+ const query = uni.createSelectorQuery().in(this);
499
+ // 查询表头高度
500
+ const headerSelector = `.${name}__header`;
501
+ // 查询所有数据行
502
+ const rowSelector = `.${name}__tr`;
503
+
504
+ query.select(headerSelector).boundingClientRect();
505
+ query.selectAll(rowSelector).boundingClientRect();
506
+ query.exec((res) => {
507
+ if (!res) return;
508
+ const headerRect = res[0];
509
+ const rowRects = res[1];
510
+ if (!rowRects || rowRects.length === 0) return;
511
+
512
+ const headerHeight = hasFixedHeader && headerRect ? headerRect.height : 0;
513
+
514
+ const fixedRowZIndex = this.hasFixedColumn ? 32 : 2;
515
+
516
+ // 计算固定顶部行的 top 值
517
+ let topOffset = headerHeight;
518
+ for (let i = 0; i < fixedTopRows && i < rowRects.length; i += 1) {
519
+ const rd = this.renderData[i];
520
+ if (rd) {
521
+ rd.rowStyle = `position: sticky; top: ${topOffset}px; z-index: ${fixedRowZIndex};`;
522
+ topOffset += rowRects[i].height;
523
+ }
524
+ }
525
+
526
+ // 计算固定底部行的 bottom 值
527
+ let bottomOffset = 0;
528
+ for (let i = dataLen - 1; i >= dataLen - fixedBottomRows && i >= 0; i -= 1) {
529
+ const rd = this.renderData[i];
530
+ if (rd && i < rowRects.length) {
531
+ rd.rowStyle = `position: sticky; bottom: ${bottomOffset}px; z-index: ${fixedRowZIndex};`;
532
+ bottomOffset += rowRects[i].height;
533
+ }
534
+ }
535
+
536
+ // 触发视图更新
537
+ this.renderData = [...this.renderData];
538
+ });
539
+ },
540
+
541
+ onRowClick(rowIndex) {
542
+ const { data } = this;
543
+ if (data && data[rowIndex]) {
544
+ this.$emit('row-click', {
545
+ row: data[rowIndex],
546
+ index: rowIndex,
547
+ });
548
+ }
549
+ },
550
+
551
+ onCellClick(rowIndex, colIndex) {
552
+ const { data, columns } = this;
553
+ if (data && data[rowIndex] && columns && columns[colIndex]) {
554
+ this.$emit('cell-click', {
555
+ row: data[rowIndex],
556
+ col: columns[colIndex],
557
+ rowIndex,
558
+ colIndex,
559
+ });
560
+ }
561
+ },
562
+
563
+ onScroll(e) {
564
+ this.$emit('scroll', { e });
565
+
566
+ // 更新固定列滚动阴影状态
567
+ if (this.hasFixedColumn) {
568
+ const detail = e.detail || e.target || {};
569
+ const scrollLeft = detail.scrollLeft || 0;
570
+ const scrollWidth = detail.scrollWidth || 0;
571
+ const clientWidth = detail.clientWidth || detail.offsetWidth || 0;
572
+ if (scrollWidth > 0 && clientWidth > 0) {
573
+ this.scrollableToLeft = scrollLeft > 1;
574
+ this.scrollableToRight = scrollWidth - scrollLeft - clientWidth > 1;
575
+ }
576
+ }
577
+ },
578
+ },
579
+ }),
580
+ };
581
+ </script>
582
+ <style scoped src="./table.css"></style>