uview-plus 3.8.37 → 3.8.42

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.
@@ -0,0 +1,51 @@
1
+ import { defineMixin } from '../../libs/vue'
2
+ import defProps from '../../libs/config/props.js'
3
+
4
+ export const props = defineMixin({
5
+ props: {
6
+ show: {
7
+ type: Boolean,
8
+ default: () => defProps.guide.show
9
+ },
10
+ list: {
11
+ type: Array,
12
+ default: () => defProps.guide.list
13
+ },
14
+ storageKey: {
15
+ type: String,
16
+ default: () => defProps.guide.storageKey
17
+ },
18
+ once: {
19
+ type: Boolean,
20
+ default: () => defProps.guide.once
21
+ },
22
+ showSkip: {
23
+ type: Boolean,
24
+ default: () => defProps.guide.showSkip
25
+ },
26
+ skipText: {
27
+ type: String,
28
+ default: () => defProps.guide.skipText
29
+ },
30
+ nextText: {
31
+ type: String,
32
+ default: () => defProps.guide.nextText
33
+ },
34
+ finishText: {
35
+ type: String,
36
+ default: () => defProps.guide.finishText
37
+ },
38
+ indicator: {
39
+ type: Boolean,
40
+ default: () => defProps.guide.indicator
41
+ },
42
+ bgColor: {
43
+ type: String,
44
+ default: () => defProps.guide.bgColor
45
+ },
46
+ zIndex: {
47
+ type: [String, Number],
48
+ default: () => defProps.guide.zIndex
49
+ }
50
+ }
51
+ })
@@ -0,0 +1,259 @@
1
+ <template>
2
+ <view
3
+ v-if="innerShow && pageList.length"
4
+ class="up-guide"
5
+ :style="{ zIndex: `${zIndex}` }"
6
+ @touchmove.stop.prevent
7
+ >
8
+ <swiper
9
+ class="up-guide__swiper"
10
+ :current="current"
11
+ @change="onSwiperChange"
12
+ >
13
+ <swiper-item v-for="(item, index) in pageList" :key="index">
14
+ <view class="up-guide__page" :style="{ backgroundColor: item.backgroundColor || bgColor }">
15
+ <template v-if="item.image">
16
+ <image class="up-guide__image" :src="item.image" mode="aspectFit"></image>
17
+ </template>
18
+ <view v-else class="up-guide__placeholder">暂无引导图</view>
19
+ <text v-if="item.title" class="up-guide__title">{{ item.title }}</text>
20
+ <text v-if="item.desc" class="up-guide__desc">{{ item.desc }}</text>
21
+ </view>
22
+ </swiper-item>
23
+ </swiper>
24
+
25
+ <view class="up-guide__footer">
26
+ <view v-if="indicator" class="up-guide__dots">
27
+ <view
28
+ v-for="(_, dotIndex) in pageList"
29
+ :key="dotIndex"
30
+ class="up-guide__dot"
31
+ :class="{ 'up-guide__dot--active': dotIndex === current }"
32
+ ></view>
33
+ </view>
34
+ <view class="up-guide__actions">
35
+ <view v-if="showSkip" class="up-guide__btn up-guide__btn--ghost" @tap="onSkip">
36
+ {{ skipText }}
37
+ </view>
38
+ <view class="up-guide__btn up-guide__btn--primary" @tap="onPrimaryAction">
39
+ {{ isLastPage() ? finishText : nextText }}
40
+ </view>
41
+ </view>
42
+ </view>
43
+ </view>
44
+ </template>
45
+
46
+ <script>
47
+ import { props } from './props';
48
+ import { mpMixin } from '../../libs/mixin/mpMixin';
49
+ import { mixin } from '../../libs/mixin/mixin';
50
+
51
+ /**
52
+ * Guide 首屏引导
53
+ * @description 全屏首屏引导组件,支持一次性记忆与多页滑动
54
+ */
55
+ export default {
56
+ name: 'up-guide',
57
+ mixins: [mpMixin, mixin, props],
58
+ emits: ['update:show', 'change', 'skip', 'finish', 'close'],
59
+ data() {
60
+ return {
61
+ innerShow: false,
62
+ current: 0,
63
+ closing: false
64
+ }
65
+ },
66
+ computed: {
67
+ pageList() {
68
+ return Array.isArray(this.list) ? this.list : []
69
+ },
70
+ resolvedStorageKey() {
71
+ return this.storageKey || 'up-guide-default'
72
+ }
73
+ },
74
+ watch: {
75
+ show(value) {
76
+ this.innerShow = !!value
77
+ }
78
+ },
79
+ mounted() {
80
+ this.bootstrap()
81
+ },
82
+ methods: {
83
+ bootstrap() {
84
+ if (!this.pageList.length) {
85
+ if (process.env.NODE_ENV !== 'production') {
86
+ console.warn('[up-guide] list is empty')
87
+ }
88
+ return
89
+ }
90
+ if (this.once && this.readRemembered()) {
91
+ this.innerShow = false
92
+ this.$emit('update:show', false)
93
+ return
94
+ }
95
+ this.innerShow = !!this.show
96
+ },
97
+ isLastPage() {
98
+ return this.current >= this.pageList.length - 1
99
+ },
100
+ onSwiperChange(event) {
101
+ const next = Number(event?.detail?.current ?? 0)
102
+ this.current = next
103
+ this.$emit('change', { current: next })
104
+ },
105
+ onPrimaryAction() {
106
+ if (this.isLastPage()) {
107
+ this.$emit('finish')
108
+ this.close(true)
109
+ return
110
+ }
111
+ this.current += 1
112
+ this.$emit('change', { current: this.current })
113
+ },
114
+ onSkip() {
115
+ this.$emit('skip')
116
+ this.close(true)
117
+ },
118
+ open() {
119
+ this.current = 0
120
+ this.innerShow = true
121
+ this.$emit('update:show', true)
122
+ },
123
+ close(remember = true) {
124
+ if (this.closing) return
125
+ this.closing = true
126
+ if (remember && this.once) {
127
+ this.writeRemembered()
128
+ }
129
+ this.innerShow = false
130
+ this.$emit('update:show', false)
131
+ this.$emit('close')
132
+ this.$nextTick(() => {
133
+ this.closing = false
134
+ })
135
+ },
136
+ reset() {
137
+ try {
138
+ uni.removeStorageSync(this.resolvedStorageKey)
139
+ } catch (error) {}
140
+ },
141
+ readRemembered() {
142
+ try {
143
+ const value = uni.getStorageSync(this.resolvedStorageKey)
144
+ return value === true || value === 1 || value === '1'
145
+ } catch (error) {
146
+ return false
147
+ }
148
+ },
149
+ writeRemembered() {
150
+ try {
151
+ uni.setStorageSync(this.resolvedStorageKey, 1)
152
+ } catch (error) {}
153
+ }
154
+ }
155
+ }
156
+ </script>
157
+
158
+ <style lang="scss" scoped>
159
+ .up-guide {
160
+ position: fixed;
161
+ left: 0;
162
+ top: 0;
163
+ right: 0;
164
+ bottom: 0;
165
+ display: flex;
166
+ flex-direction: column;
167
+ }
168
+
169
+ .up-guide__swiper {
170
+ flex: 1;
171
+ }
172
+
173
+ .up-guide__page {
174
+ height: 100%;
175
+ padding: 120rpx 40rpx 40rpx;
176
+ box-sizing: border-box;
177
+ display: flex;
178
+ flex-direction: column;
179
+ align-items: center;
180
+ color: #ffffff;
181
+ }
182
+
183
+ .up-guide__image {
184
+ width: 560rpx;
185
+ height: 560rpx;
186
+ }
187
+
188
+ .up-guide__placeholder {
189
+ width: 560rpx;
190
+ height: 560rpx;
191
+ border-radius: 24rpx;
192
+ background: rgba(255, 255, 255, 0.12);
193
+ display: flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+ }
197
+
198
+ .up-guide__title {
199
+ margin-top: 48rpx;
200
+ font-size: 40rpx;
201
+ font-weight: 600;
202
+ }
203
+
204
+ .up-guide__desc {
205
+ margin-top: 18rpx;
206
+ font-size: 28rpx;
207
+ opacity: 0.85;
208
+ text-align: center;
209
+ }
210
+
211
+ .up-guide__footer {
212
+ padding: 24rpx 32rpx calc(24rpx + env(safe-area-inset-bottom));
213
+ }
214
+
215
+ .up-guide__dots {
216
+ display: flex;
217
+ justify-content: center;
218
+ gap: 12rpx;
219
+ margin-bottom: 26rpx;
220
+ }
221
+
222
+ .up-guide__dot {
223
+ width: 14rpx;
224
+ height: 14rpx;
225
+ border-radius: 999px;
226
+ background: rgba(255, 255, 255, 0.35);
227
+ }
228
+
229
+ .up-guide__dot--active {
230
+ width: 34rpx;
231
+ background: #ffffff;
232
+ }
233
+
234
+ .up-guide__actions {
235
+ display: flex;
236
+ gap: 16rpx;
237
+ }
238
+
239
+ .up-guide__btn {
240
+ flex: 1;
241
+ height: 84rpx;
242
+ border-radius: 42rpx;
243
+ display: flex;
244
+ align-items: center;
245
+ justify-content: center;
246
+ font-size: 28rpx;
247
+ }
248
+
249
+ .up-guide__btn--ghost {
250
+ color: #ffffff;
251
+ border: 2rpx solid rgba(255, 255, 255, 0.42);
252
+ }
253
+
254
+ .up-guide__btn--primary {
255
+ color: #111111;
256
+ background: #ffffff;
257
+ font-weight: 600;
258
+ }
259
+ </style>
@@ -364,6 +364,17 @@
364
364
 
365
365
  this.canvasInstance.clearCanvas();
366
366
  },
367
+
368
+ // 对外暴露的清空方法(供工具栏与ref调用)
369
+ clear() {
370
+ this.pathStack = []
371
+ this.currentPath = []
372
+ this.lastPoint = null
373
+ this.isDrawing = false
374
+ this.isEmpty = true
375
+ this.clearCanvas()
376
+ this.$emit('clear')
377
+ },
367
378
 
368
379
  // 导出签名图片
369
380
  async exportSignature() {
@@ -52,6 +52,41 @@ export const props = defineMixin({
52
52
  backgroundColor: {
53
53
  type: String,
54
54
  default: () => defProps.tabbar.backgroundColor
55
+ },
56
+ // 风格类型
57
+ styleType: {
58
+ type: String,
59
+ default: () => defProps.tabbar.styleType
60
+ },
61
+ // 激活动画类型
62
+ animationType: {
63
+ type: String,
64
+ default: () => defProps.tabbar.animationType
65
+ },
66
+ // 选中项背景色
67
+ activeBackgroundColor: {
68
+ type: String,
69
+ default: () => defProps.tabbar.activeBackgroundColor
70
+ },
71
+ // 未选中项背景色
72
+ inactiveBackgroundColor: {
73
+ type: String,
74
+ default: () => defProps.tabbar.inactiveBackgroundColor
75
+ },
76
+ // item 形状
77
+ itemShape: {
78
+ type: String,
79
+ default: () => defProps.tabbar.itemShape
80
+ },
81
+ // 图标缩放比例
82
+ iconScale: {
83
+ type: [String, Number],
84
+ default: () => defProps.tabbar.iconScale
85
+ },
86
+ // 文本显示模式
87
+ textMode: {
88
+ type: String,
89
+ default: () => defProps.tabbar.textMode
55
90
  }
56
91
  }
57
92
  })
@@ -19,6 +19,13 @@ export default {
19
19
  fixed: true,
20
20
  placeholder: true,
21
21
  borderColor: '',
22
- backgroundColor: ''
22
+ backgroundColor: '',
23
+ styleType: 'default',
24
+ animationType: 'none',
25
+ activeBackgroundColor: '',
26
+ inactiveBackgroundColor: '',
27
+ itemShape: 'default',
28
+ iconScale: 1.1,
29
+ textMode: 'always'
23
30
  }
24
31
  }
@@ -4,10 +4,21 @@
4
4
  class="u-tabbar__content"
5
5
  ref="u-tabbar__content"
6
6
  @touchmove.stop.prevent="noop"
7
- :class="[border && 'u-border-top', fixed && 'u-tabbar--fixed']"
7
+ :class="[
8
+ border && 'u-border-top',
9
+ fixed && 'u-tabbar--fixed',
10
+ `u-tabbar--${styleType}`,
11
+ textMode === 'active' && 'u-tabbar--text-active'
12
+ ]"
8
13
  :style="[tabbarStyle]"
9
14
  >
10
- <view class="u-tabbar__content__item-wrapper">
15
+ <view
16
+ class="u-tabbar__content__item-wrapper"
17
+ :class="[
18
+ `u-tabbar__content__item-wrapper--${styleType}`,
19
+ itemShape !== 'default' && `u-tabbar__content__item-wrapper--shape-${itemShape}`
20
+ ]"
21
+ >
11
22
  <slot />
12
23
  </view>
13
24
  <u-safe-bottom v-if="safeAreaInsetBottom"></u-safe-bottom>
@@ -59,19 +70,36 @@
59
70
  tabbarStyle() {
60
71
  const style = {
61
72
  zIndex: this.zIndex,
62
- backgroundColor: this.backgroundColor || this.upThemeVar('--up-card-bg-color', this.upThemeIsDark ? '#1c1c1e' : '#ffffff')
73
+ backgroundColor: this.backgroundColor || this.upThemeVar('--up-card-bg-color', this.upThemeIsDark ? '#1c1c1e' : '#ffffff'),
74
+ '--up-tabbar-active-bg': this.activeBackgroundColor || 'transparent',
75
+ '--up-tabbar-inactive-bg': this.inactiveBackgroundColor || 'transparent',
76
+ '--up-tabbar-icon-scale': `${this.iconScale}`
63
77
  }
64
78
  if (this.borderColor) {
65
79
  style.borderColor = this.borderColor + ' !important'
66
80
  } else {
67
81
  style.borderColor = this.upThemeVar('--up-border-color', '#dadbde')
68
82
  }
83
+ if (['pill', 'card', 'glow', 'convex'].includes(this.styleType)) {
84
+ style.padding = '8rpx 12rpx 12rpx'
85
+ }
69
86
  // 合并来自父组件的customStyle样式
70
87
  return deepMerge(style, addStyle(this.customStyle))
71
88
  },
72
89
  // 监听多个参数的变化,通过在computed执行对应的操作
73
90
  updateChild() {
74
- return [this.value, this.activeColor, this.inactiveColor]
91
+ return [
92
+ this.value,
93
+ this.activeColor,
94
+ this.inactiveColor,
95
+ this.styleType,
96
+ this.animationType,
97
+ this.activeBackgroundColor,
98
+ this.inactiveBackgroundColor,
99
+ this.itemShape,
100
+ this.iconScale,
101
+ this.textMode
102
+ ]
75
103
  },
76
104
  updatePlaceholder() {
77
105
  return [this.fixed, this.placeholder]
@@ -138,9 +166,59 @@
138
166
  height: 50px;
139
167
  @include flex(row);
140
168
  justify-content: space-around;
169
+
170
+ &--pill,
171
+ &--card,
172
+ &--glow,
173
+ &--convex {
174
+ gap: 8rpx;
175
+ }
176
+
177
+ &--pill {
178
+ height: 50px;
179
+ }
180
+
181
+ &--shape-round {
182
+ border-radius: 999px;
183
+ }
184
+
185
+ &--shape-square {
186
+ border-radius: 16rpx;
187
+ }
141
188
  }
142
189
  }
143
190
 
191
+ &--default,
192
+ &--minimal,
193
+ &--underline,
194
+ &--dot {
195
+ padding: 0;
196
+ }
197
+
198
+ &--pill,
199
+ &--glow {
200
+ border-radius: 72rpx;
201
+ background: #ffffff;
202
+ margin-left: 24rpx;
203
+ margin-right: 24rpx;
204
+ }
205
+
206
+ &--card {
207
+ border-radius: 24rpx;
208
+ box-shadow: 0 10rpx 30rpx rgba(15, 23, 42, 0.06);
209
+ }
210
+
211
+ &--lift {
212
+ overflow: visible;
213
+ }
214
+
215
+ &--convex {
216
+ overflow: visible;
217
+ border-radius: 32rpx 32rpx 0 0;
218
+ background: #ffffff;
219
+ box-shadow: 0 -2rpx 18rpx rgba(148, 163, 184, 0.08);
220
+ }
221
+
144
222
  &--fixed {
145
223
  position: fixed;
146
224
  bottom: 0;
@@ -9,9 +9,19 @@ export const props = defineMixin({
9
9
  },
10
10
  // uview-plus内置图标或者绝对路径的图片
11
11
  icon: {
12
- icon: String,
12
+ type: String,
13
13
  default: () => defProps.tabbarItem.icon
14
14
  },
15
+ // 激活态图标
16
+ activeIcon: {
17
+ type: String,
18
+ default: () => defProps.tabbarItem.activeIcon
19
+ },
20
+ // 未激活态图标
21
+ inactiveIcon: {
22
+ type: String,
23
+ default: () => defProps.tabbarItem.inactiveIcon
24
+ },
15
25
  // 右上角的角标提示信息
16
26
  badge: {
17
27
  type: [String, Number, null],
@@ -36,6 +46,46 @@ export const props = defineMixin({
36
46
  mode: {
37
47
  type: String,
38
48
  default: () => defProps.tabbarItem.mode
49
+ },
50
+ // 激活态附加类名
51
+ activeClass: {
52
+ type: String,
53
+ default: () => defProps.tabbarItem.activeClass
54
+ },
55
+ // 未激活态附加类名
56
+ inactiveClass: {
57
+ type: String,
58
+ default: () => defProps.tabbarItem.inactiveClass
59
+ },
60
+ // 中间按钮背景色
61
+ midButtonBgColor: {
62
+ type: String,
63
+ default: () => defProps.tabbarItem.midButtonBgColor
64
+ },
65
+ // 中间按钮图标颜色
66
+ midButtonIconColor: {
67
+ type: String,
68
+ default: () => defProps.tabbarItem.midButtonIconColor
69
+ },
70
+ // 中间按钮图标大小
71
+ midButtonIconSize: {
72
+ type: [String, Number],
73
+ default: () => defProps.tabbarItem.midButtonIconSize
74
+ },
75
+ // 中间按钮阴影
76
+ midButtonBoxShadow: {
77
+ type: String,
78
+ default: () => defProps.tabbarItem.midButtonBoxShadow
79
+ },
80
+ // 中间按钮内层阴影
81
+ midButtonInnerBoxShadow: {
82
+ type: String,
83
+ default: () => defProps.tabbarItem.midButtonInnerBoxShadow
84
+ },
85
+ // 中间按钮垂直偏移(负值为上移)
86
+ midButtonOffsetY: {
87
+ type: [String, Number],
88
+ default: () => defProps.tabbarItem.midButtonOffsetY
39
89
  }
40
90
  }
41
91
  })
@@ -12,10 +12,20 @@ export default {
12
12
  tabbarItem: {
13
13
  name: null,
14
14
  icon: '',
15
+ activeIcon: '',
16
+ inactiveIcon: '',
15
17
  badge: null,
16
18
  dot: false,
17
19
  text: '',
18
20
  badgeStyle: 'top: 6px;right:2px;',
19
- mode: ''
21
+ mode: '',
22
+ activeClass: '',
23
+ inactiveClass: '',
24
+ midButtonBgColor: '',
25
+ midButtonIconColor: '',
26
+ midButtonIconSize: 26,
27
+ midButtonBoxShadow: '',
28
+ midButtonInnerBoxShadow: '',
29
+ midButtonOffsetY: -10
20
30
  }
21
31
  }