uview-plus 3.7.13 → 3.7.28

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 (37) hide show
  1. package/changelog.md +42 -0
  2. package/components/u-cascader/u-cascader.vue +1 -0
  3. package/components/u-copy/u-copy.vue +1 -1
  4. package/components/u-coupon/u-coupon.vue +1 -2
  5. package/components/u-form/u-form.vue +2 -2
  6. package/components/u-form-item/u-form-item.vue +6 -6
  7. package/components/u-loading-icon/u-loading-icon.vue +2 -1
  8. package/components/u-select/u-select.vue +198 -181
  9. package/components/u-steps/u-steps.vue +1 -1
  10. package/components/u-switch/props.js +10 -0
  11. package/components/u-switch/switch.js +2 -0
  12. package/components/u-switch/u-switch.vue +15 -13
  13. package/components/u-table2/u-table2.vue +266 -110
  14. package/libs/util/gcanvas/bridge/bridge-weex.js +0 -0
  15. package/libs/util/gcanvas/context-2d/FillStyleLinearGradient.js +0 -0
  16. package/libs/util/gcanvas/context-2d/FillStylePattern.js +0 -0
  17. package/libs/util/gcanvas/context-2d/FillStyleRadialGradient.js +0 -0
  18. package/libs/util/gcanvas/context-2d/RenderingContext.js +0 -0
  19. package/libs/util/gcanvas/context-webgl/ActiveInfo.js +0 -0
  20. package/libs/util/gcanvas/context-webgl/Buffer.js +0 -0
  21. package/libs/util/gcanvas/context-webgl/Framebuffer.js +0 -0
  22. package/libs/util/gcanvas/context-webgl/GLenum.js +0 -0
  23. package/libs/util/gcanvas/context-webgl/GLmethod.js +0 -0
  24. package/libs/util/gcanvas/context-webgl/GLtype.js +0 -0
  25. package/libs/util/gcanvas/context-webgl/Program.js +0 -0
  26. package/libs/util/gcanvas/context-webgl/Renderbuffer.js +0 -0
  27. package/libs/util/gcanvas/context-webgl/RenderingContext.js +0 -0
  28. package/libs/util/gcanvas/context-webgl/Shader.js +0 -0
  29. package/libs/util/gcanvas/context-webgl/ShaderPrecisionFormat.js +0 -0
  30. package/libs/util/gcanvas/context-webgl/Texture.js +0 -0
  31. package/libs/util/gcanvas/context-webgl/UniformLocation.js +0 -0
  32. package/libs/util/gcanvas/context-webgl/classUtils.js +0 -0
  33. package/libs/util/gcanvas/env/canvas.js +0 -0
  34. package/libs/util/gcanvas/env/image.js +0 -0
  35. package/libs/util/gcanvas/env/tool.js +0 -0
  36. package/libs/util/gcanvas/index.js +0 -0
  37. package/package.json +1 -1
package/changelog.md CHANGED
@@ -1,3 +1,45 @@
1
+ ## 3.7.28(2026-03-21)
2
+ feat: 添加 up-switch 组件的圆点颜色属性
3
+
4
+ ## 3.7.27(2026-03-12)
5
+ improvment: 优化up-form的错误提示message字段类型
6
+
7
+ ## 3.7.26(2026-03-09)
8
+ add: up-select增加禁用功能
9
+
10
+ ## 3.7.25(2026-03-07)
11
+ fix: 优化up-coupon规范化scss
12
+
13
+ ## 3.7.24(2026-03-06)
14
+ fix: 修复up-table2 组件在小程序不显示单元格内容的问题
15
+
16
+ ## 3.7.23(2026-03-06)
17
+ fix: up-cascader在开启auto-close时最后层级选择后未触发confirm
18
+
19
+ ## 3.7.22(2026-03-05)
20
+ improvment: floatButton组件示例改为组合式API
21
+
22
+ ## 3.7.21(2026-03-05)
23
+ feat: 新增禁用 iOS Safari 下拉刷新工具类、移除 H5 端图标复制限制、优化 u-copy 组件注释
24
+
25
+ ## 3.7.20(2026-02-26)
26
+ improvement:box组件示例改为组合式API
27
+
28
+ ## 3.7.19(2026-02-25)
29
+ improvement:agreement组件示例改为组合式API
30
+
31
+ ## 3.7.18(2026-02-24)
32
+ improvement:barcode组件示例改为组合式API
33
+
34
+ ## 3.7.17(2026-02-11)
35
+ fix: 修复steps组件current失效
36
+
37
+ ## 3.7.16(2026-02-09)
38
+ improvment: choose组件示例改为组合式API
39
+
40
+ ## 3.7.14(2026-02-08)
41
+ refactor: up-signature组件改用up-canvas组件
42
+
1
43
  ## 3.7.13(2026-02-07)
2
44
  add: 新增up-canvas组件
3
45
 
@@ -276,6 +276,7 @@
276
276
  if (this.autoClose) {
277
277
  // 如果启用自动关闭,则触发change事件并关闭
278
278
  this.emitChange();
279
+ this.handleConfirm();
279
280
  } else {
280
281
  // 否则只触发change事件,不关闭
281
282
  this.emitChange(false);
@@ -36,7 +36,7 @@ export default {
36
36
  }
37
37
  content = typeof content === 'string' ? content : content.toString() // 复制内容,必须字符串,数字需要转换为字符串
38
38
  /**
39
- * 小程序端 和 app端的复制逻辑
39
+ * 复制逻辑
40
40
  */
41
41
  let that = this;
42
42
  uni.setClipboardData({
@@ -163,6 +163,7 @@
163
163
  border-radius: 8rpx;
164
164
  background: #ffebf0;
165
165
  color: $u-main-color;
166
+ width: 100%;
166
167
 
167
168
  &--coupon {
168
169
  border-radius: 16rpx;
@@ -210,8 +211,6 @@
210
211
  &--card {
211
212
  border-radius: 16rpx;
212
213
  }
213
-
214
- width: 100%;
215
214
 
216
215
  &--small {
217
216
  // width: 520rpx;
@@ -121,7 +121,7 @@
121
121
  this.children.map((child) => {
122
122
  // 如果u-form-item的prop在props数组中,则清除对应的校验结果信息
123
123
  if (props[0] === undefined || props.includes(child.prop)) {
124
- child.message = null;
124
+ child.message = '';
125
125
  }
126
126
  });
127
127
  },
@@ -194,7 +194,7 @@
194
194
  //没有配置,或者配置了showErrorMsg为true时候,才修改子组件message,默认没有配置
195
195
  if(!options||options?.showErrorMsg==true){
196
196
  child.message =
197
- childErrors[0]?.message ? childErrors[0].message : null;
197
+ childErrors[0]?.message ? childErrors[0].message : '';
198
198
  }
199
199
  if (i == (rules.length - 1)) {
200
200
  resolve(errorsRes)
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <view class="u-form-item" :class="{'u-form-item--error':(!!message && parentData['errorType'] === 'message')}">
2
+ <view class="u-form-item" :class="{'u-form-item--error':(message != '' && parentData['errorType'] === 'message')}">
3
3
  <view
4
4
  class="u-form-item__body"
5
5
  @tap="clickHandler"
@@ -59,7 +59,7 @@
59
59
  </view>
60
60
  <slot name="error">
61
61
  <text
62
- v-if="!!message && parentData['errorType'] === 'message'"
62
+ v-if="message != '' && parentData['errorType'] === 'message'"
63
63
  class="u-form-item__body__right__message"
64
64
  :style="{
65
65
  marginLeft: addUnit((labelPosition || parentData['labelPosition']) === 'top' ? 0 : (labelWidth || parentData['labelWidth']))
@@ -68,8 +68,8 @@
68
68
  </slot>
69
69
  <u-line
70
70
  v-if="borderBottom"
71
- :color="message && parentData['errorType'] === 'border-bottom' ? color['error'] : propsLine['color']"
72
- :customStyle="`margin-top: ${message && parentData['errorType'] === 'message' ? '5px' : 0}`"
71
+ :color="message != '' && parentData['errorType'] === 'border-bottom' ? color['error'] : propsLine['color']"
72
+ :customStyle="`margin-top: ${message != '' && parentData['errorType'] === 'message' ? '5px' : 0}`"
73
73
  ></u-line>
74
74
  </view>
75
75
  </template>
@@ -167,7 +167,7 @@
167
167
  },
168
168
  // 移除u-form-item的校验结果
169
169
  clearValidate() {
170
- this.message = null
170
+ this.message = ''
171
171
  },
172
172
  // 清空当前的组件的校验结果,并重置为初始值
173
173
  resetField() {
@@ -176,7 +176,7 @@
176
176
  // 将up-form的model的prop属性链还原原始值
177
177
  setProperty(this.parent.$props['model'], this.prop, value)
178
178
  // 移除校验结果
179
- this.message = null
179
+ this.message = ''
180
180
  },
181
181
  // 点击组件
182
182
  clickHandler() {
@@ -68,7 +68,7 @@
68
68
  // #endif
69
69
  /**
70
70
  * loading 加载动画
71
- * @description 警此组件为一个小动画,目前用在uView的loadmore加载更多和switch开关等组件的正在加载状态场景。
71
+ * @description 此组件为一个小动画,目前用在uView的loadmore加载更多和switch开关等组件的正在加载状态场景。
72
72
  * @tutorial https://uview-plus.jiangruyi.com/components/loading.html
73
73
  * @property {Boolean} show 是否显示组件 (默认 true)
74
74
  * @property {String} color 动画活动区域的颜色,只对 mode = flower 模式有效(默认color['u-tips-color'])
@@ -346,3 +346,4 @@
346
346
 
347
347
  /* #endif */
348
348
  </style>
349
+
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <view class="u-select">
3
- <view class="u-select__content">
3
+ <view :class="['u-select__content', disabled && 'disabled']">
4
4
  <view class="u-select__label" @click="openSelect">
5
5
  <slot name="text" :currentLabel="currentLabel">
6
6
  <text class="u-select__text" v-if="showOptionsLabel">
@@ -14,26 +14,16 @@
14
14
  <up-icon name="arrow-down" :size="iconSize" :color="iconColor"></up-icon>
15
15
  </slot>
16
16
  </view>
17
- <u-overlay
18
- :show="isOpen"
19
- @click="overlayClick"
20
- v-if="overlay"
21
- :zIndex="zIndex"
22
- :duration="duration + 50"
23
- :customStyle="overlayStyle"
24
- :opacity="overlayOpacity"
25
- @touchmove.stop.prevent="noop"
26
- ></u-overlay>
17
+ <u-overlay :show="isOpen" @click="overlayClick" v-if="overlay" :zIndex="zIndex" :duration="duration + 50"
18
+ :customStyle="overlayStyle" :opacity="overlayOpacity" @touchmove.stop.prevent="noop"></u-overlay>
27
19
  <view class="u-select__options__wrap"
28
20
  :style="{ overflowY: 'auto', zIndex: zIndex + 1, left: optionsWrapLeft, right: optionsWrapRight, maxHeight: maxHeight}">
29
21
  <view class="u-select__options" v-if="isOpen">
30
22
  <slot name="options">
31
- <view class="u-select__options_item"
32
- :class="current == item[keyName] ? 'active': ''"
33
- :key="index" v-for="(item, index) in options"
34
- @click="selectItem(item)">
23
+ <view class="u-select__options_item" :class="current == item[keyName] ? 'active': ''"
24
+ :key="index" v-for="(item, index) in options" @click="selectItem(item)">
35
25
  <slot name="optionItem" :item="item">
36
- <text class="u-select__item_text" :style="{color: itemColor}">
26
+ <text class="u-select__item_text" :style="{color: itemColor}">
37
27
  {{item[labelName]}}
38
28
  </text>
39
29
  </slot>
@@ -46,179 +36,206 @@
46
36
  </template>
47
37
 
48
38
  <script>
49
- import { mpMixin } from '../../libs/mixin/mpMixin';
50
- import { mixin } from '../../libs/mixin/mixin';
51
- import { getWindowInfo } from '../../libs/function/index';
52
- export default {
53
- name:"up-select",
54
- mixins: [mpMixin, mixin],
55
- emits: ['update:current', 'select'],
56
- props: {
57
- maxHeight: {
58
- type: String,
59
- default: '90vh'
60
- },
61
- overlay: {
62
- type: Boolean,
63
- default: true
64
- },
65
- overlayOpacity: {
66
- type: Number,
67
- default: 0.01
68
- },
69
- overlayStyle: {
70
- type: Object,
71
- default: () => {
72
- return {}
39
+ import {
40
+ mpMixin
41
+ } from '../../libs/mixin/mpMixin';
42
+ import {
43
+ mixin
44
+ } from '../../libs/mixin/mixin';
45
+ import {
46
+ getWindowInfo
47
+ } from '../../libs/function/index';
48
+ export default {
49
+ name: "up-select",
50
+ mixins: [mpMixin, mixin],
51
+ emits: ['update:current', 'select'],
52
+ props: {
53
+ maxHeight: {
54
+ type: String,
55
+ default: '90vh'
56
+ },
57
+ overlay: {
58
+ type: Boolean,
59
+ default: true
60
+ },
61
+ overlayOpacity: {
62
+ type: Number,
63
+ default: 0.01
64
+ },
65
+ overlayStyle: {
66
+ type: Object,
67
+ default: () => {
68
+ return {}
69
+ }
70
+ },
71
+ duration: {
72
+ type: Number,
73
+ default: 300
74
+ },
75
+ label: {
76
+ type: String,
77
+ default: '选项'
78
+ },
79
+ options: {
80
+ type: Array,
81
+ default: () => {
82
+ return []
83
+ }
84
+ },
85
+ keyName: {
86
+ type: String,
87
+ default: 'id'
88
+ },
89
+ labelName: {
90
+ type: String,
91
+ default: 'name'
92
+ },
93
+ showOptionsLabel: {
94
+ type: Boolean,
95
+ default: false
96
+ },
97
+ current: {
98
+ type: [String, Number],
99
+ default: ''
100
+ },
101
+ zIndex: {
102
+ type: Number,
103
+ default: 11000
104
+ },
105
+ itemColor: {
106
+ type: String,
107
+ default: '#333333'
108
+ },
109
+ iconColor: {
110
+ type: String,
111
+ default: ''
112
+ },
113
+ iconSize: {
114
+ type: [String],
115
+ default: '13px'
116
+ },
117
+ // 是否禁用
118
+ disabled: {
119
+ type: Boolean,
120
+ default: false
73
121
  }
74
122
  },
75
- duration: {
76
- type: Number,
77
- default: 300
78
- },
79
- label: {
80
- type: String,
81
- default: '选项'
82
- },
83
- options: {
84
- type: Array,
85
- default: () => {
86
- return []
123
+ data() {
124
+ return {
125
+ isOpen: false,
126
+ optionsWrapLeft: 'auto',
127
+ optionsWrapRight: 'auto'
87
128
  }
88
129
  },
89
- keyName: {
90
- type: String,
91
- default: 'id'
92
- },
93
- labelName: {
94
- type: String,
95
- default: 'name'
96
- },
97
- showOptionsLabel: {
98
- type: Boolean,
99
- default: false
100
- },
101
- current: {
102
- type: [String, Number],
103
- default: ''
104
- },
105
- zIndex: {
106
- type: Number,
107
- default: 11000
108
- },
109
- itemColor: {
110
- type: String,
111
- default: '#333333'
112
- },
113
- iconColor: {
114
- type: String,
115
- default: ''
116
- },
117
- iconSize: {
118
- type: [String],
119
- default: '13px'
120
- }
121
- },
122
- data() {
123
- return {
124
- isOpen: false,
125
- optionsWrapLeft: 'auto',
126
- optionsWrapRight: 'auto'
127
- }
128
- },
129
- computed: {
130
- currentLabel() {
131
- let name = '';
132
- this.options.forEach((ele) => {
133
- if (ele[this.keyName] === this.current) {
134
- name = ele[this.labelName];
135
- }
136
- });
137
- return name;
138
- }
139
- },
140
- methods: {
141
- openSelect() {
142
- this.isOpen = true;
143
- this.$nextTick(() => {
144
- if (this.isOpen) {
145
- this.adjustOptionsWrapPosition();
130
+ computed: {
131
+ currentLabel() {
132
+ let name = '';
133
+ this.options.forEach((ele) => {
134
+ if (ele[this.keyName] === this.current) {
135
+ name = ele[this.labelName];
136
+ }
137
+ });
138
+ return name;
146
139
  }
147
- });
148
- },
149
- closeSelect() {
150
- this.isOpen = false;
151
- },
152
- overlayClick() {
153
- this.isOpen = false;
154
- },
155
- selectItem(item) {
156
- this.isOpen = false;
157
- this.$emit('update:current', item[this.keyName]);
158
- this.$emit('select', item);
159
- },
160
- adjustOptionsWrapPosition() {
161
- let wi = getWindowInfo();
162
- let windowWidth = wi.windowWidth;
163
- this.$uGetRect('.u-select__options__wrap').then(rect => {
164
- if (rect.left + rect.width > windowWidth) {
165
- // 如果右侧被遮挡,则调整到左侧
166
- this.optionsWrapLeft = 'auto';
167
- this.optionsWrapRight = `0px`;
140
+ },
141
+ methods: {
142
+ openSelect() {
143
+ if (this.disabled) return;
144
+ this.isOpen = true;
145
+ this.$nextTick(() => {
146
+ if (this.isOpen) {
147
+ this.adjustOptionsWrapPosition();
148
+ }
149
+ });
150
+ },
151
+ closeSelect() {
152
+ this.isOpen = false;
153
+ },
154
+ overlayClick() {
155
+ this.isOpen = false;
156
+ },
157
+ selectItem(item) {
158
+ this.isOpen = false;
159
+ this.$emit('update:current', item[this.keyName]);
160
+ this.$emit('select', item);
161
+ },
162
+ adjustOptionsWrapPosition() {
163
+ let wi = getWindowInfo();
164
+ let windowWidth = wi.windowWidth;
165
+ this.$uGetRect('.u-select__options__wrap').then(rect => {
166
+ if (rect.left + rect.width > windowWidth) {
167
+ // 如果右侧被遮挡,则调整到左侧
168
+ this.optionsWrapLeft = 'auto';
169
+ this.optionsWrapRight = `0px`;
170
+ }
171
+ });
168
172
  }
169
- });
170
- }
171
- }
172
- }
173
+ }
174
+ }
173
175
  </script>
174
176
 
175
177
  <style lang="scss" scoped>
176
- .u-select__content {
177
- position: relative;
178
- .u-select__label {
179
- display: flex;
180
- justify-content: space-between;
181
- /* #ifdef H5 */
182
- &:hover {
183
- cursor: pointer;
184
- }
185
- /* #endif */
186
- }
187
- .u-select__text {
188
- margin-right: 2px;
189
- }
190
- .u-select__options__wrap {
191
- margin-bottom: 46px;
192
- position: absolute;
193
- top: 20px;
194
- left: 0;
178
+ .u-select__content {
179
+ position: relative;
180
+
181
+ .u-select__label {
182
+ display: flex;
183
+ justify-content: space-between;
184
+
185
+ /* #ifdef H5 */
186
+ &:hover {
187
+ cursor: pointer;
188
+ }
189
+
190
+ /* #endif */
191
+ }
192
+
193
+ .u-select__text {
194
+ margin-right: 2px;
195
+ }
196
+
197
+ &.disabled {
198
+ opacity: 0.6;
199
+ pointer-events: none;
200
+ }
201
+
202
+ .u-select__options__wrap {
203
+ margin-bottom: 46px;
204
+ position: absolute;
205
+ top: 20px;
206
+ left: 0;
207
+ }
208
+
209
+ .u-select__options {
210
+ min-width: 100px;
211
+ box-sizing: border-box;
212
+ border-radius: 4px;
213
+ border: 1px solid #f1f1f1;
214
+ background-color: #fff;
215
+
216
+ .u-select__options_item {
217
+ padding: 10px 12px;
218
+ box-sizing: border-box;
219
+ width: 100%;
220
+ height: 100%;
221
+
222
+ &:hover {
223
+ background-color: #f7f7f7;
224
+ }
225
+
226
+ /* #ifdef H5 */
227
+ &:hover {
228
+ cursor: pointer;
229
+ }
230
+
231
+ .u-select__item_text {
232
+ &:hover {
233
+ cursor: pointer;
234
+ }
235
+ }
236
+
237
+ /* #endif */
238
+ }
239
+ }
195
240
  }
196
- .u-select__options {
197
- min-width: 100px;
198
- box-sizing: border-box;
199
- border-radius: 4px;
200
- border: 1px solid #f1f1f1;
201
- background-color: #fff;
202
- .u-select__options_item {
203
- padding: 10px 12px;
204
- box-sizing: border-box;
205
- width: 100%;
206
- height: 100%;
207
- &:hover {
208
- background-color: #f7f7f7;
209
- }
210
- /* #ifdef H5 */
211
- &:hover {
212
- cursor: pointer;
213
- }
214
- .u-select__item_text {
215
- &:hover {
216
- cursor: pointer;
217
- }
218
- }
219
- /* #endif */
220
- }
221
- }
222
- }
223
241
  </style>
224
-
@@ -36,7 +36,7 @@
36
36
  children() {
37
37
  this.updateChildData()
38
38
  },
39
- parentData() {
39
+ parentDataCpu() {
40
40
  this.updateChildData()
41
41
  }
42
42
  },
@@ -27,6 +27,16 @@ export const props = defineMixin({
27
27
  type: String,
28
28
  default: () => defProps.switch.inactiveColor
29
29
  },
30
+ // 打开时圆点的颜色
31
+ dotActiveColor: {
32
+ type: String,
33
+ default: () => defProps.switch.dotActiveColor
34
+ },
35
+ // 关闭时圆点的颜色
36
+ dotInactiveColor: {
37
+ type: String,
38
+ default: () => defProps.switch.dotInactiveColor
39
+ },
30
40
  // 通过v-model双向绑定的值
31
41
  // #ifdef VUE3
32
42
  modelValue: {
@@ -15,6 +15,8 @@ export default {
15
15
  size: 25,
16
16
  activeColor: '#2979ff',
17
17
  inactiveColor: '#ffffff',
18
+ dotActiveColor: '#ffffff',
19
+ dotInactiveColor: '#ffffff',
18
20
  value: false,
19
21
  activeValue: true,
20
22
  inactiveValue: false,
@@ -46,17 +46,19 @@
46
46
  * switch 开关选择器
47
47
  * @description 选择开关一般用于只有两个选择,且只能选其一的场景。
48
48
  * @tutorial https://uview-plus.jiangruyi.com/components/switch.html
49
- * @property {Boolean} loading 是否处于加载中(默认 false )
50
- * @property {Boolean} disabled 是否禁用(默认 false )
51
- * @property {String | Number} size 开关尺寸,单位px (默认 25 )
52
- * @property {String} activeColor 打开时的背景色 (默认 '#2979ff' )
53
- * @property {String} inactiveColor 关闭时的背景色 (默认 '#ffffff' )
54
- * @property {Boolean | String | Number} value 通过v-model双向绑定的值 (默认 false
55
- * @property {Boolean | String | Number} activeValue 打开选择器时通过change事件发出的值 (默认 true
56
- * @property {Boolean | String | Number} inactiveValue 关闭选择器时通过change事件发出的值 (默认 false )
57
- * @property {Boolean} asyncChange 是否开启异步变更,开启后需要手动控制输入值 (默认 false
58
- * @property {String | Number} space 圆点与外边框的距离 (默认 0
59
- * @property {Object} customStyle 定义需要用到的外部样式
49
+ * @property {Boolean} loading 是否处于加载中(默认 false )
50
+ * @property {Boolean} disabled 是否禁用(默认 false )
51
+ * @property {String | Number} size 开关尺寸,单位px (默认 25 )
52
+ * @property {String} activeColor 打开时的背景色 (默认 '#2979ff' )
53
+ * @property {String} inactiveColor 关闭时的背景色 (默认 '#ffffff' )
54
+ * @property {String} dotActiveColor 打开时圆点的颜色 (默认 '#ffffff'
55
+ * @property {String} dotInactiveColor 关闭时圆点的颜色 (默认 '#ffffff'
56
+ * @property {Boolean | String | Number} value 通过v-model双向绑定的值 (默认 false )
57
+ * @property {Boolean | String | Number} activeValue 打开选择器时通过change事件发出的值 (默认 true
58
+ * @property {Boolean | String | Number} inactiveValue 关闭选择器时通过change事件发出的值 (默认 false
59
+ * @property {Boolean} asyncChange 是否开启异步变更,开启后需要手动控制输入值 (默认 false )
60
+ * @property {String | Number} space 圆点与外边框的距离 (默认 0 )
61
+ * @property {Object} customStyle 定义需要用到的外部样式
60
62
  *
61
63
  * @event {Function} change 在switch打开或关闭时触发
62
64
  * @example <u-switch v-model="checked" active-color="red" inactive-color="#eee"></u-switch>
@@ -121,6 +123,7 @@
121
123
  style.height = addUnit(this.size - this.space)
122
124
  const translateX = this.isActive ? addUnit(this.space) : addUnit(this.size);
123
125
  style.transform = `translateX(-${translateX})`
126
+ style.backgroundColor = this.isActive ? this.dotActiveColor : this.dotInactiveColor
124
127
  return style
125
128
  },
126
129
  bgStyle() {
@@ -190,9 +193,8 @@
190
193
  justify-content: center;
191
194
  border-radius: 100px;
192
195
  background-color: #fff;
193
- border-radius: 100px;
194
196
  box-shadow: 1px 1px 1px 0 rgba(0, 0, 0, 0.25);
195
- transition-property: transform;
197
+ transition-property: transform, background-color;
196
198
  transition-duration: 0.4s;
197
199
  transition-timing-function: cubic-bezier(0.3, 1.05, 0.4, 1.05);
198
200
  }
@@ -28,47 +28,83 @@
28
28
  </view>
29
29
  </view>
30
30
 
31
- <!-- 表体 -->
32
- <view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
33
- <template v-if="data && data.length > 0">
34
- <table-row
35
- v-for="(row, rowIndex) in sortedData"
36
- :key="row[rowKey] || rowIndex"
37
- :row="row"
38
- :rowIndex="rowIndex"
39
- :parent-row="null"
40
- :columns="columns"
41
- :tree-props="treeProps"
42
- :row-key="rowKey"
43
- :expanded-keys="expandedKeys"
44
- :cell-style-inner="cellStyleInner"
45
- :is-expanded="isExpanded"
46
- :row-class-name="rowClassName"
47
- :stripe="stripe"
48
- :cell-class-name="cellClassName"
49
- :get-fixed-class="getFixedClass"
50
- :highlight-current-row="highlightCurrentRow"
51
- :current-row="currentRow"
52
- :handle-row-click="handleRowClick"
53
- :toggle-expand="toggleExpand"
54
- :level="1"
55
- :rowHeight="rowHeight"
56
- :hasTree="hasTree"
57
- :selectedRows="selectedRows"
58
- :expandWidth="expandWidth"
59
- :computedMainCol="computedMainCol"
60
- :span-method="spanMethod"
61
- @toggle-select="toggleSelect"
62
- @row-click="handleRowClick"
63
- @toggle-expand="toggleExpand"
64
- >
65
- <template v-slot:cellChild="scope">
66
- <slot name="cell" :row="scope.row" :column="scope.column" :prow="scope.prow"
67
- :rowIndex="scope.rowIndex" :columnIndex="scope.columnIndex" :level="scope.level">
68
- </slot>
69
- </template>
70
- </table-row>
71
- </template>
31
+ <!-- 表体 -->
32
+ <view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
33
+ <template v-if="data && data.length > 0">
34
+ <!-- #ifdef MP-WEIXIN -->
35
+ <template v-for="(item, flatIndex) in flattenedSortedData" :key="item.row[rowKey] || flatIndex">
36
+ <view class="u-table-row u-table-row-child" :class="[highlightCurrentRow && currentRow === item.row ? 'u-table-row-highlight' : '',
37
+ rowClassName ? rowClassName(item.row, item.rowIndex) : '',
38
+ stripe && flatIndex % 2 === 1 ? 'u-table-row-zebra' : ''
39
+ ]" :style="{ height: rowHeight }" @click="handleRowClick(item.row)">
40
+ <view v-for="(col, colIndex) in columns" :key="col.key" class="u-table-cell"
41
+ :class="[col.align ? 'u-text-' + col.align : '',
42
+ cellClassName ? cellClassName(item.row, col) : '',
43
+ getFixedClass(col),
44
+ getCellSpanClass(item.row, col, item.rowIndex, colIndex)
45
+ ]"
46
+ :style="[cellStyleInner({ row: item.row, column: col, rowIndex: item.rowIndex, columnIndex: colIndex, level: item.level }), getCellSpanStyle(item.row, col, item.rowIndex, colIndex)]">
47
+ <view v-if="col.type === 'selection'">
48
+ <checkbox :checked="isSelected(item.row)" @click.stop="toggleSelect(item.row)" />
49
+ </view>
50
+ <template v-else>
51
+ <view v-if="col.key === computedMainCol && hasTree" @click.stop="toggleExpand(item.row)"
52
+ :style="{ width: expandWidth }">
53
+ <view v-if="item.row[treeProps.children] && item.row[treeProps.children].length > 0">
54
+ {{ isExpanded(item.row) ? '▼' : '▶' }}
55
+ </view>
56
+ </view>
57
+ <slot name="cell" :row="item.row" :column="col" :prow="item.parentRow"
58
+ :rowIndex="item.rowIndex" :columnIndex="colIndex" :level="item.level">
59
+ <view class="u-table-cell_content">
60
+ {{ item.row[col.key] }}
61
+ </view>
62
+ </slot>
63
+ </template>
64
+ </view>
65
+ </view>
66
+ </template>
67
+ <!-- #endif -->
68
+ <!-- #ifndef MP-WEIXIN -->
69
+ <table-row
70
+ v-for="(row, rowIndex) in sortedData"
71
+ :key="row[rowKey] || rowIndex"
72
+ :row="row"
73
+ :rowIndex="rowIndex"
74
+ :parent-row="null"
75
+ :columns="columns"
76
+ :tree-props="treeProps"
77
+ :row-key="rowKey"
78
+ :expanded-keys="expandedKeys"
79
+ :cell-style-inner="cellStyleInner"
80
+ :is-expanded="isExpanded"
81
+ :row-class-name="rowClassName"
82
+ :stripe="stripe"
83
+ :cell-class-name="cellClassName"
84
+ :get-fixed-class="getFixedClass"
85
+ :highlight-current-row="highlightCurrentRow"
86
+ :current-row="currentRow"
87
+ :handle-row-click="handleRowClick"
88
+ :toggle-expand="toggleExpand"
89
+ :level="1"
90
+ :rowHeight="rowHeight"
91
+ :hasTree="hasTree"
92
+ :selectedRows="selectedRows"
93
+ :expandWidth="expandWidth"
94
+ :computedMainCol="computedMainCol"
95
+ :span-method="spanMethod"
96
+ @toggle-select="toggleSelect"
97
+ @row-click="handleRowClick"
98
+ @toggle-expand="toggleExpand"
99
+ >
100
+ <template v-slot:cellChild="scope">
101
+ <slot name="cell" :row="scope.row" :column="scope.column" :prow="scope.prow"
102
+ :rowIndex="scope.rowIndex" :columnIndex="scope.columnIndex" :level="scope.level">
103
+ </slot>
104
+ </template>
105
+ </table-row>
106
+ <!-- #endif -->
107
+ </template>
72
108
  <template v-else>
73
109
  <slot name="empty">
74
110
  </slot>
@@ -103,49 +139,85 @@
103
139
  </view>
104
140
  </view>
105
141
 
106
- <!-- 表体 -->
107
- <view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
108
- <template v-if="data && data.length > 0">
109
- <template v-for="(row, rowIndex) in sortedData" :key="row[rowKey] || rowIndex">
110
- <!-- 子级渲染 (递归组件) -->
111
- <table-row
112
- :row="row"
113
- :rowIndex="rowIndex"
114
- :parent-row="null"
115
- :columns="visibleFixedLeftColumns"
116
- :tree-props="treeProps"
117
- :row-key="rowKey"
118
- :expanded-keys="expandedKeys"
119
- :cell-style-inner="cellStyleInner"
120
- :is-expanded="isExpanded"
121
- :row-class-name="rowClassName"
122
- :stripe="stripe"
123
- :cell-class-name="cellClassName"
124
- :get-fixed-class="getFixedClass"
125
- :highlight-current-row="highlightCurrentRow"
126
- :current-row="currentRow"
127
- :handle-row-click="handleRowClick"
128
- :toggle-expand="toggleExpand"
129
- :level="1"
130
- :rowHeight="rowHeight"
131
- :hasTree="hasTree"
132
- :selectedRows="selectedRows"
133
- :expandWidth="expandWidth"
134
- :computedMainCol="computedMainCol"
135
- :span-method="spanMethod"
136
- @toggle-select="toggleSelect"
137
- @row-click="handleRowClick"
138
- @toggle-expand="toggleExpand"
139
- >
140
- <template v-slot:cellChild="scope">
141
- <slot name="cell" :row="scope.row" :column="scope.column" :prow="scope.prow"
142
- :rowIndex="scope.rowIndex" :columnIndex="scope.columnIndex" :level="scope.level">
143
- </slot>
144
- </template>
145
- </table-row>
146
- </template>
147
- </template>
148
- </view>
142
+ <!-- 表体 -->
143
+ <view class="u-table-body" :style="{ minWidth: scrollWidth, maxHeight: maxHeight ? maxHeight + 'px' : 'none' }">
144
+ <template v-if="data && data.length > 0">
145
+ <!-- #ifdef MP-WEIXIN -->
146
+ <template v-for="(item, flatIndex) in flattenedSortedData" :key="item.row[rowKey] || flatIndex">
147
+ <view class="u-table-row u-table-row-child" :class="[highlightCurrentRow && currentRow === item.row ? 'u-table-row-highlight' : '',
148
+ rowClassName ? rowClassName(item.row, item.rowIndex) : '',
149
+ stripe && flatIndex % 2 === 1 ? 'u-table-row-zebra' : ''
150
+ ]" :style="{ height: rowHeight }" @click="handleRowClick(item.row)">
151
+ <view v-for="(col, colIndex) in visibleFixedLeftColumns" :key="col.key" class="u-table-cell"
152
+ :class="[col.align ? 'u-text-' + col.align : '',
153
+ cellClassName ? cellClassName(item.row, col) : '',
154
+ getFixedClass(col),
155
+ getCellSpanClass(item.row, col, item.rowIndex, colIndex)
156
+ ]"
157
+ :style="[cellStyleInner({ row: item.row, column: col, rowIndex: item.rowIndex, columnIndex: colIndex, level: item.level }), getCellSpanStyle(item.row, col, item.rowIndex, colIndex)]">
158
+ <view v-if="col.type === 'selection'">
159
+ <checkbox :checked="isSelected(item.row)" @click.stop="toggleSelect(item.row)" />
160
+ </view>
161
+ <template v-else>
162
+ <view v-if="col.key === computedMainCol && hasTree" @click.stop="toggleExpand(item.row)"
163
+ :style="{ width: expandWidth }">
164
+ <view v-if="item.row[treeProps.children] && item.row[treeProps.children].length > 0">
165
+ {{ isExpanded(item.row) ? '▼' : '▶' }}
166
+ </view>
167
+ </view>
168
+ <slot name="cell" :row="item.row" :column="col" :prow="item.parentRow"
169
+ :rowIndex="item.rowIndex" :columnIndex="colIndex" :level="item.level">
170
+ <view class="u-table-cell_content">
171
+ {{ item.row[col.key] }}
172
+ </view>
173
+ </slot>
174
+ </template>
175
+ </view>
176
+ </view>
177
+ </template>
178
+ <!-- #endif -->
179
+ <!-- #ifndef MP-WEIXIN -->
180
+ <template v-for="(row, rowIndex) in sortedData" :key="row[rowKey] || rowIndex">
181
+ <!-- 子级渲染 (递归组件) -->
182
+ <table-row
183
+ :row="row"
184
+ :rowIndex="rowIndex"
185
+ :parent-row="null"
186
+ :columns="visibleFixedLeftColumns"
187
+ :tree-props="treeProps"
188
+ :row-key="rowKey"
189
+ :expanded-keys="expandedKeys"
190
+ :cell-style-inner="cellStyleInner"
191
+ :is-expanded="isExpanded"
192
+ :row-class-name="rowClassName"
193
+ :stripe="stripe"
194
+ :cell-class-name="cellClassName"
195
+ :get-fixed-class="getFixedClass"
196
+ :highlight-current-row="highlightCurrentRow"
197
+ :current-row="currentRow"
198
+ :handle-row-click="handleRowClick"
199
+ :toggle-expand="toggleExpand"
200
+ :level="1"
201
+ :rowHeight="rowHeight"
202
+ :hasTree="hasTree"
203
+ :selectedRows="selectedRows"
204
+ :expandWidth="expandWidth"
205
+ :computedMainCol="computedMainCol"
206
+ :span-method="spanMethod"
207
+ @toggle-select="toggleSelect"
208
+ @row-click="handleRowClick"
209
+ @toggle-expand="toggleExpand"
210
+ >
211
+ <template v-slot:cellChild="scope">
212
+ <slot name="cell" :row="scope.row" :column="scope.column" :prow="scope.prow"
213
+ :rowIndex="scope.rowIndex" :columnIndex="scope.columnIndex" :level="scope.level">
214
+ </slot>
215
+ </template>
216
+ </table-row>
217
+ </template>
218
+ <!-- #endif -->
219
+ </template>
220
+ </view>
149
221
  </view>
150
222
  </view>
151
223
  </template>
@@ -357,10 +429,10 @@ export default {
357
429
  });
358
430
  });
359
431
  },
360
- sortedData() {
361
- if (!this.sortConditions.length) return this.filteredData;
362
-
363
- const data = [...this.filteredData];
432
+ sortedData() {
433
+ if (!this.sortConditions.length) return this.filteredData;
434
+
435
+ const data = [...this.filteredData];
364
436
 
365
437
  return data.sort((a, b) => {
366
438
  for (const condition of this.sortConditions) {
@@ -376,14 +448,32 @@ export default {
376
448
  if (valA < valB) return order === 'ascending' ? -1 : 1;
377
449
  if (valA > valB) return order === 'ascending' ? 1 : -1;
378
450
  }
379
- return 0;
380
- });
381
- },
382
- // 计算当前应该显示的固定左侧列
383
- visibleFixedLeftColumns() {
384
- if (this.scrollLeft <= 0) {
385
- return [];
386
- }
451
+ return 0;
452
+ });
453
+ },
454
+ flattenedSortedData() {
455
+ const result = [];
456
+ const childrenKey = this.treeProps.children;
457
+
458
+ const walk = (rows, parentRow = null, level = 1) => {
459
+ if (!Array.isArray(rows) || rows.length === 0) return;
460
+ rows.forEach((row, rowIndex) => {
461
+ result.push({ row, parentRow, level, rowIndex });
462
+ const children = row && row[childrenKey];
463
+ if (children && children.length > 0 && this.isExpanded(row)) {
464
+ walk(children, row, level + 1);
465
+ }
466
+ });
467
+ };
468
+
469
+ walk(this.sortedData);
470
+ return result;
471
+ },
472
+ // 计算当前应该显示的固定左侧列
473
+ visibleFixedLeftColumns() {
474
+ if (this.scrollLeft <= 0) {
475
+ return [];
476
+ }
387
477
 
388
478
  let totalWidth = 0;
389
479
  let fixedWidth = 0;
@@ -441,13 +531,71 @@ export default {
441
531
  deep: true,
442
532
  immediate: false
443
533
  }
444
- },
445
- methods: {
446
- addUnit,
447
- onScroll(e) {
448
- this.scrollLeft = e.detail.scrollLeft;
449
- // 获取所有左侧固定列
450
- this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
534
+ },
535
+ methods: {
536
+ addUnit,
537
+ isSelected(row) {
538
+ return this.selectedRows.some(r => r[this.rowKey] === row[this.rowKey]);
539
+ },
540
+ getCellSpan(row, column, rowIndex, columnIndex) {
541
+ if (typeof this.spanMethod !== 'function') {
542
+ return { rowspan: 1, colspan: 1 };
543
+ }
544
+
545
+ const result = this.spanMethod({
546
+ row,
547
+ column,
548
+ rowIndex,
549
+ columnIndex
550
+ });
551
+
552
+ if (Array.isArray(result)) {
553
+ const [rowspan, colspan] = result;
554
+ return { rowspan: rowspan != null ? rowspan : 1, colspan: colspan != null ? colspan : 1 };
555
+ }
556
+
557
+ if (result && typeof result === 'object') {
558
+ const { rowspan, colspan } = result;
559
+ return { rowspan: rowspan != null ? rowspan : 1, colspan: colspan != null ? colspan : 1 };
560
+ }
561
+
562
+ return { rowspan: 1, colspan: 1 };
563
+ },
564
+ getCellSpanClass(row, column, rowIndex, columnIndex) {
565
+ const span = this.getCellSpan(row, column, rowIndex, columnIndex);
566
+ if (span.rowspan === 0 || span.colspan === 0) {
567
+ return 'u-table-cell-hidden';
568
+ }
569
+ if (span.rowspan > 1 || span.colspan > 1) {
570
+ return 'u-table-cell-merged';
571
+ }
572
+ return '';
573
+ },
574
+ getCellSpanStyle(row, column, rowIndex, columnIndex) {
575
+ const span = this.getCellSpan(row, column, rowIndex, columnIndex);
576
+ const style = {};
577
+
578
+ if (span.rowspan > 1) {
579
+ const currentHeight = parseInt(this.rowHeight);
580
+ if (!isNaN(currentHeight)) {
581
+ style.height = `${span.rowspan * currentHeight}px`;
582
+ }
583
+ }
584
+
585
+ if (span.colspan > 1) {
586
+ style.flex = span.colspan;
587
+ }
588
+
589
+ if (span.rowspan === 0 || span.colspan === 0) {
590
+ style.display = 'none';
591
+ }
592
+
593
+ return style;
594
+ },
595
+ onScroll(e) {
596
+ this.scrollLeft = e.detail.scrollLeft;
597
+ // 获取所有左侧固定列
598
+ this.fixedLeftColumns = this.columns.filter(col => col.fixed === 'left');
451
599
  // 计算是否需要显示固定列阴影
452
600
  if (this.fixedLeftColumns.length > 0) {
453
601
  this.showFixedColumnShadow = this.scrollLeft > 0;
@@ -716,12 +864,20 @@ export default {
716
864
  background-color: #f5f7fa;
717
865
  }
718
866
 
719
- .u-table-empty {
720
- text-align: center;
721
- padding: 20px;
722
- color: #999;
723
- }
724
- }
867
+ .u-table-empty {
868
+ text-align: center;
869
+ padding: 20px;
870
+ color: #999;
871
+ }
872
+
873
+ .u-table-cell-hidden {
874
+ opacity: 0;
875
+ }
876
+
877
+ .u-table-cell-merged {
878
+ z-index: 1;
879
+ }
880
+ }
725
881
 
726
882
  // 固定列浮动视图
727
883
  .u-table-fixed-shadow {
@@ -753,4 +909,4 @@ export default {
753
909
  border-right: none;
754
910
  }
755
911
  }
756
- </style>
912
+ </style>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
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.7.13",
5
+ "version": "3.7.28",
6
6
  "description": "零云®uview-plus已兼容vue3支持多语言,120+全面的组件和便捷的工具会让您信手拈来。近期新增拖动排序、条码、图片裁剪、下拉刷新、虚拟列表、签名、Markdown等。",
7
7
  "keywords": [
8
8
  "uview",