uview-plus 3.8.106 → 3.8.112

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 (56) hide show
  1. package/changelog.md +80 -0
  2. package/components/u-action-sheet/u-action-sheet.vue +3 -1
  3. package/components/u-calendar/u-calendar.vue +3 -1
  4. package/components/u-canvas/u-canvas.vue +67 -8
  5. package/components/u-cate-tab/u-cate-tab.vue +2 -2
  6. package/components/u-color-picker/u-color-picker.vue +2 -2
  7. package/components/u-cropper/u-cropper.vue +78 -70
  8. package/components/u-datetime-picker/u-datetime-picker.vue +3 -1
  9. package/components/u-goods-sku/u-goods-sku.vue +2 -1
  10. package/components/u-keyboard/u-keyboard.vue +2 -1
  11. package/components/u-lazy-load/u-lazy-load.vue +5 -3
  12. package/components/u-navbar/navbar.js +3 -1
  13. package/components/u-navbar/props.js +10 -0
  14. package/components/u-navbar/theme-vars.scss +5 -0
  15. package/components/u-navbar/u-navbar.vue +155 -12
  16. package/components/u-picker/u-picker.vue +3 -1
  17. package/components/u-picker-data/u-picker-data.vue +3 -2
  18. package/components/u-popup/u-popup.vue +38 -5
  19. package/components/u-poster/u-poster.vue +37 -4
  20. package/components/u-sticky/u-sticky.vue +2 -2
  21. package/libs/function/index.js +18 -0
  22. package/libs/theme/runtime.js +4 -0
  23. package/libs/theme/theme.js +6 -2
  24. package/libs/util/gcanvas/bridge/bridge-weex.js +0 -0
  25. package/libs/util/gcanvas/context-2d/FillStyleLinearGradient.js +0 -0
  26. package/libs/util/gcanvas/context-2d/FillStylePattern.js +0 -0
  27. package/libs/util/gcanvas/context-2d/FillStyleRadialGradient.js +0 -0
  28. package/libs/util/gcanvas/context-2d/RenderingContext.js +0 -0
  29. package/libs/util/gcanvas/context-webgl/ActiveInfo.js +0 -0
  30. package/libs/util/gcanvas/context-webgl/Buffer.js +0 -0
  31. package/libs/util/gcanvas/context-webgl/Framebuffer.js +0 -0
  32. package/libs/util/gcanvas/context-webgl/GLenum.js +0 -0
  33. package/libs/util/gcanvas/context-webgl/GLmethod.js +0 -0
  34. package/libs/util/gcanvas/context-webgl/GLtype.js +0 -0
  35. package/libs/util/gcanvas/context-webgl/Program.js +0 -0
  36. package/libs/util/gcanvas/context-webgl/Renderbuffer.js +0 -0
  37. package/libs/util/gcanvas/context-webgl/RenderingContext.js +0 -0
  38. package/libs/util/gcanvas/context-webgl/Shader.js +0 -0
  39. package/libs/util/gcanvas/context-webgl/ShaderPrecisionFormat.js +0 -0
  40. package/libs/util/gcanvas/context-webgl/Texture.js +0 -0
  41. package/libs/util/gcanvas/context-webgl/UniformLocation.js +0 -0
  42. package/libs/util/gcanvas/context-webgl/classUtils.js +0 -0
  43. package/libs/util/gcanvas/env/canvas.js +0 -0
  44. package/libs/util/gcanvas/env/image.js +0 -0
  45. package/libs/util/gcanvas/env/tool.js +0 -0
  46. package/libs/util/gcanvas/index.js +0 -0
  47. package/package.json +1 -1
  48. package/types/comps/actionSheet.d.ts +4 -0
  49. package/types/comps/calendar.d.ts +4 -0
  50. package/types/comps/datetimePicker.d.ts +4 -0
  51. package/types/comps/keyboard.d.ts +4 -0
  52. package/types/comps/navbar.d.ts +13 -0
  53. package/types/comps/picker.d.ts +4 -0
  54. package/types/comps/popup.d.ts +6 -2
  55. package/types/func.d.ts +11 -0
  56. package/types/index.d.ts +1 -0
@@ -1,21 +1,47 @@
1
1
  <template>
2
2
  <view class="u-navbar" :class="[customClass]">
3
+ <!-- ios 模式:in-flow 层,恒定渲染,随页面原生滚动被带走 -->
4
+ <view
5
+ v-if="isIosMode"
6
+ class="u-navbar__flow"
7
+ >
8
+ <view :style="{ height: navbarFlowSpacerHeight }"></view>
9
+ <view
10
+ v-if="title"
11
+ class="u-navbar__large-title"
12
+ :style="{ height: addUnit(largeTitleHeight) }"
13
+ >
14
+ <text
15
+ class="u-line-1 u-navbar__large-title__text"
16
+ :style="[{ color: navbarTitleColor }, addStyle(titleStyle)]"
17
+ >{{ title }}</text>
18
+ </view>
19
+ </view>
20
+ <!-- default 模式:原有占位块,行为保持不变 -->
3
21
  <view
4
22
  class="u-navbar__placeholder"
5
- v-if="fixed && placeholder"
23
+ v-if="!isIosMode && fixed && placeholder"
6
24
  :style="{
7
25
  height: addUnit(getPx(height) + getWindowInfo().statusBarHeight,'px'),
8
26
  }"
9
27
  ></view>
10
28
  <view
11
29
  class="u-navbar__inner"
12
- :class="[fixed && 'u-navbar--fixed']"
30
+ :class="[(isIosMode || fixed) && 'u-navbar--fixed']"
13
31
  :style="[navbarInnerStyle]"
14
32
  >
33
+ <view
34
+ v-if="isIosMode"
35
+ class="u-navbar__glass"
36
+ :style="{
37
+ opacity: navbarGlassOpacity,
38
+ background: navbarGlassBgColor,
39
+ }"
40
+ ></view>
15
41
  <u-status-bar v-if="safeAreaInsetTop"></u-status-bar>
16
42
  <view
17
43
  class="u-navbar__content"
18
- :class="[border && 'u-border-bottom']"
44
+ :class="[border && !isIosMode && 'u-border-bottom']"
19
45
  :style="{
20
46
  height: addUnit(height),
21
47
  backgroundColor: 'transparent',
@@ -43,15 +69,20 @@
43
69
  >{{ leftText }}</text>
44
70
  </slot>
45
71
  </view>
46
- <slot name="center">
47
- <text
48
- class="u-line-1 u-navbar__content__title"
49
- :style="[{
50
- width: addUnit(titleWidth),
51
- color: navbarTitleColor,
52
- }, addStyle(titleStyle)]"
53
- >{{ title }}</text>
54
- </slot>
72
+ <view
73
+ class="u-navbar__content__center"
74
+ :style="[navbarCenterStyle]"
75
+ >
76
+ <slot name="center">
77
+ <text
78
+ class="u-line-1 u-navbar__content__title"
79
+ :style="[{
80
+ width: addUnit(titleWidth),
81
+ color: navbarTitleColor,
82
+ }, addStyle(titleStyle)]"
83
+ >{{ title }}</text>
84
+ </slot>
85
+ </view>
55
86
  <view
56
87
  class="u-navbar__content__right"
57
88
  v-if="$slots.right || rightIcon || rightText"
@@ -82,6 +113,12 @@
82
113
  import { mixin } from '../../libs/mixin/mixin';
83
114
  import config from '../../libs/config/config';
84
115
  import { addUnit, addStyle, getPx, getWindowInfo } from '../../libs/function/index';
116
+
117
+ // iOS 大标题行高。它同时是 navbarProgress 的分母,
118
+ // 因此改动此值会同步改变压缩过程的滚动区间。
119
+ const LARGE_TITLE_HEIGHT = 52
120
+ // 居中标题上浮的起始偏移,与淡入同步归零
121
+ const CENTER_TITLE_RISE = 12
85
122
  /**
86
123
  * Navbar 自定义导航栏
87
124
  * @description 此组件一般用于在特殊情况下,需要自定义导航栏的时候用到,一般建议使用uni-app带的导航栏。
@@ -104,6 +141,8 @@
104
141
  * @property {String | Number} leftIconColor 左侧返回图标的颜色(默认 #303133 )
105
142
  * @property {Boolean} autoBack 点击左侧区域(返回图标),是否自动返回上一页(默认 false )
106
143
  * @property {Object | String} titleStyle 标题的样式,对象或字符串
144
+ * @property {String} mode 导航栏模式,default-常规,ios-大标题磨砂模式(默认 'default' )
145
+ * @property {String | Number} scrollTop 页面滚动距离,仅 ios 模式使用,由页面 onPageScroll 传入(默认 0 )
107
146
  * @event {Function} leftClick 点击左侧区域
108
147
  * @event {Function} rightClick 点击右侧区域
109
148
  * @example <u-navbar title="剑未配妥,出门已是江湖" left-text="返回" right-text="帮助" @click-left="onClickBack" @click-right="onClickRight"></u-navbar>
@@ -116,6 +155,60 @@
116
155
  }
117
156
  },
118
157
  computed: {
158
+ isIosMode() {
159
+ // nvue 缺少 filter 管线、页面非原生滚动容器、onPageScroll 不可靠,
160
+ // 三条约束任意一条都足以让 ios 模式失效,整体降级为 default。
161
+ // 注意 APP-NVUE 在 app-harmony 上为 false,harmony 走 ArkWeb 应获得完整 ios 模式。
162
+ // #ifdef APP-NVUE
163
+ return false
164
+ // #endif
165
+ // #ifndef APP-NVUE
166
+ return this.mode === 'ios'
167
+ // #endif
168
+ },
169
+ // 有效大标题行高:title 为空时不渲染大标题行,行高塌陷为 0
170
+ largeTitleHeight() {
171
+ return this.title ? LARGE_TITLE_HEIGHT : 0
172
+ },
173
+ // in-flow 层顶部让位块高度,为固定层腾出空间
174
+ navbarFlowSpacerHeight() {
175
+ const statusBarHeight = this.safeAreaInsetTop ? getWindowInfo().statusBarHeight : 0
176
+ return addUnit(getPx(this.height) + statusBarHeight, 'px')
177
+ },
178
+ // 压缩进度。分母取有效大标题行高,progress=1 即大标题恰好完全没入导航栏
179
+ navbarProgress() {
180
+ if (!this.isIosMode) return 1
181
+ const height = this.largeTitleHeight
182
+ if (height <= 0) return 1
183
+ const offset = getPx(this.scrollTop) || 0
184
+ return Math.min(Math.max(offset / height, 0), 1)
185
+ },
186
+ // 磨砂在前半段走完,为居中标题的出现铺好不透明底
187
+ navbarGlassOpacity() {
188
+ if (!this.isIosMode) return 0
189
+ return Math.min(Math.max(this.navbarProgress / 0.5, 0), 1)
190
+ },
191
+ // 居中标题在后段才启动,此时玻璃已满不透明,不会与大标题互相透出
192
+ navbarCenterOpacity() {
193
+ if (!this.isIosMode) return 1
194
+ return Math.min(Math.max((this.navbarProgress - 0.75) / 0.25, 0), 1)
195
+ },
196
+ // 居中标题由下往上浮现:与淡入同一段行程,位移随之归零
197
+ navbarCenterStyle() {
198
+ if (!this.isIosMode) return {}
199
+ const opacity = this.navbarCenterOpacity
200
+ return {
201
+ opacity,
202
+ transform: `translateY(${(1 - opacity) * CENTER_TITLE_RISE}px)`
203
+ }
204
+ },
205
+ navbarGlassBgColor() {
206
+ // 0.82 是可读性下限的承重值:backdrop-filter 不生效时,
207
+ // 仅靠这个不透明度也必须保证文字不与下方内容读串。
208
+ return this.bgColor
209
+ || this.upThemeVar('--up-navbar-glass-bg-color',
210
+ this.upThemeIsDark ? 'rgba(28, 28, 30, 0.82)' : 'rgba(255, 255, 255, 0.82)')
211
+ },
119
212
  navbarBgColor() {
120
213
  if (this.bgColor) return this.bgColor
121
214
  return this.upThemeVar('--up-navbar-bg-color', this.upThemeIsDark ? '#1c1c1e' : '#ffffff')
@@ -134,6 +227,11 @@
134
227
  navbarInnerStyle() {
135
228
  const style = {}
136
229
  style.background = this.navbarBgColor
230
+ // ios 模式下固定层必须透明,否则 backdrop-filter 采样到自身底色,模糊不出内容。
231
+ // 背景由独立的 __glass 层承担,随滚动淡入。
232
+ if (this.isIosMode) {
233
+ style.background = 'transparent'
234
+ }
137
235
  return style
138
236
  }
139
237
  },
@@ -179,12 +277,46 @@
179
277
  z-index: 11;
180
278
  }
181
279
 
280
+ &__flow {
281
+ /* #ifndef APP-NVUE */
282
+ width: 100%;
283
+ /* #endif */
284
+ }
285
+
286
+ &__large-title {
287
+ @include flex(row);
288
+ align-items: center;
289
+ padding: 0 13px;
290
+
291
+ &__text {
292
+ font-size: 34px;
293
+ font-weight: 700;
294
+ line-height: 1.2;
295
+ }
296
+ }
297
+
298
+ &__glass {
299
+ position: absolute;
300
+ top: 0;
301
+ left: 0;
302
+ right: 0;
303
+ bottom: 0;
304
+ // 模糊半径写在静态 class 内而非 :style 绑定,使 -webkit- 前缀在编译期确定。
305
+ // iOS 16 之前的 WKWebView 只认前缀版本,两条都必须保留。
306
+ // CSS 变量不被支持时回落到字面量 20px。
307
+ -webkit-backdrop-filter: saturate(180%) blur(var(--up-navbar-glass-blur, 20px));
308
+ backdrop-filter: saturate(180%) blur(var(--up-navbar-glass-blur, 20px));
309
+ }
310
+
182
311
  &__content {
183
312
  @include flex(row);
184
313
  align-items: center;
185
314
  height: 44px;
186
315
  background-color: $u-bg-color;
316
+ // 玻璃层是绝对定位的,会盖住同级的非定位元素。
317
+ // 缺少这两行的表现是整个导航栏内容不可见。
187
318
  position: relative;
319
+ z-index: 1;
188
320
  justify-content: center;
189
321
 
190
322
  &__left,
@@ -211,6 +343,17 @@
211
343
  }
212
344
  }
213
345
 
346
+ &__center {
347
+ @include flex(row);
348
+ align-items: center;
349
+ justify-content: center;
350
+ // 滚动事件是离散到达的,补一段短过渡让上浮与淡入连续。
351
+ // 时长刻意短于一次滚动事件的间隔,避免落后于手指。
352
+ /* #ifndef APP-NVUE */
353
+ transition: opacity 0.15s linear, transform 0.15s ease-out;
354
+ /* #endif */
355
+ }
356
+
214
357
  &__title {
215
358
  text-align: center;
216
359
  font-size: 16px;
@@ -23,6 +23,7 @@
23
23
  :pageInline="pageInline"
24
24
  :overlayOpacity="overlayOpacity"
25
25
  @close="closeHandler"
26
+ @closed="$emit('closed')"
26
27
  >
27
28
  <view class="u-picker">
28
29
  <u-toolbar
@@ -108,6 +109,7 @@
108
109
  * @property {String | Number} duration 动画时长,单位ms (默认 300 )
109
110
  * @property {String | Number} overlayDuration 遮罩层动画时长,单位ms (默认 350 )
110
111
  * @event {Function} close 关闭选择器时触发
112
+ * @event {Function} closed 选择器已关闭(离场动画结束、弹窗真正消失后)触发
111
113
  * @event {Function} cancel 点击取消按钮触发
112
114
  * @event {Function} change 当选择值变化时触发
113
115
  * @event {Function} confirm 点击确定按钮,返回当前选择的值
@@ -195,7 +197,7 @@ export default {
195
197
  }
196
198
  }
197
199
  },
198
- emits: ['close', 'cancel', 'confirm', 'change', 'update:modelValue', 'update:show'],
200
+ emits: ['close', 'closed', 'cancel', 'confirm', 'change', 'update:modelValue', 'update:show'],
199
201
  computed: {
200
202
  // input的props
201
203
  inputPropsInner() {
@@ -20,7 +20,8 @@
20
20
  :defaultIndex="defaultIndex"
21
21
  @confirm="confirm"
22
22
  @cancel="cancel"
23
- @close="close">
23
+ @close="close"
24
+ @closed="$emit('closed')">
24
25
  </up-picker>
25
26
  </view>
26
27
  </template>
@@ -95,7 +96,7 @@ export default {
95
96
  return [this.options];
96
97
  }
97
98
  },
98
- emits: ['update:modelValue', 'cancel', 'close', 'confirm'],
99
+ emits: ['update:modelValue', 'cancel', 'close', 'closed', 'confirm'],
99
100
  methods: {
100
101
  hideKeyboard() {
101
102
  uni.hideKeyboard()
@@ -25,6 +25,7 @@
25
25
  :mode="pageInline ? 'none' : position"
26
26
  :duration="duration"
27
27
  @afterEnter="afterEnter"
28
+ @afterLeave="afterLeave"
28
29
  @click="clickHandler"
29
30
  >
30
31
  <!-- @click.stop不能去除,去除会导致居中模式下点击内容区域触发关闭弹窗 -->
@@ -99,8 +100,9 @@
99
100
  * @property {String} minHeight 最小高度,单位任意,数值默认为px(默认 '200px' )
100
101
  * @property {String} maxHeight 最大高度,单位任意,数值默认为px(默认 '80%' )
101
102
  * @property {Object} customStyle 组件的样式,对象形式
102
- * @event {Function} open 弹出层打开
103
- * @event {Function} close 弹出层收起
103
+ * @event {Function} open 弹出层打开(进场动画结束后)
104
+ * @event {Function} close 弹出层收起(关闭动作发生时,离场动画开始前;外部直接将show置为false时也会触发)
105
+ * @event {Function} closed 弹出层已关闭(离场动画结束、弹窗真正消失后)
104
106
  * @example <u-popup v-model:show="show"><text>出淤泥而不染,濯清涟而不妖</text></u-popup>
105
107
  */
106
108
  export default {
@@ -109,6 +111,8 @@
109
111
  data() {
110
112
  return {
111
113
  overlayDuration: this.duration + 50,
114
+ // close事件是否已由组件内部的关闭动作发出,避免show变化时重复发出
115
+ closeEmitted: false,
112
116
  // 触摸相关数据
113
117
  touchStartY: 0,
114
118
  touchStartHeight: 0,
@@ -120,10 +124,25 @@
120
124
  watch: {
121
125
  show(newValue, oldValue) {
122
126
  if (newValue === true) {
127
+ this.closeEmitted = false
123
128
  // #ifdef MP-WEIXIN
124
129
  const children = this.$children
125
130
  this.retryComputedComponentRect(children)
126
131
  // #endif
132
+ } else if (oldValue === true) {
133
+ // 外部直接将show置为false时,组件内部没有走过关闭动作,
134
+ // 此处补发close,保证任意关闭方式都能被监听到
135
+ if (this.closeEmitted) {
136
+ // 本次关闭已由内部动作发出过close,消费标记即可
137
+ this.closeEmitted = false
138
+ } else {
139
+ this.$emit('close')
140
+ }
141
+ // pageInline模式下transition的show恒为true,不会执行离场动画,
142
+ // 收不到afterLeave,此处按动画时长补发closed
143
+ if (this.pageInline) {
144
+ this.$emit('closed')
145
+ }
127
146
  }
128
147
  }
129
148
  },
@@ -238,25 +257,39 @@
238
257
  }
239
258
  },
240
259
  },
241
- emits: ["open", "close", "click", "update:show"],
260
+ emits: ["open", "close", "closed", "click", "update:show"],
242
261
  methods: {
262
+ // 发出close事件。标记仅在本次更新周期内有效,
263
+ // 用于抑制紧随其后的show变化导致watch重复补发close
264
+ emitClose() {
265
+ this.closeEmitted = true
266
+ this.$emit('close')
267
+ this.$nextTick(() => {
268
+ this.closeEmitted = false
269
+ })
270
+ },
243
271
  // 点击遮罩
244
272
  overlayClick() {
245
273
  if (this.closeOnClickOverlay) {
246
274
  this.$emit('update:show', false)
247
- this.$emit('close')
275
+ this.emitClose()
248
276
  }
249
277
  },
250
278
  open(e) {
279
+ this.closeEmitted = false
251
280
  this.$emit('update:show', true)
252
281
  },
253
282
  close(e) {
254
283
  this.$emit('update:show', false)
255
- this.$emit('close')
284
+ this.emitClose()
256
285
  },
257
286
  afterEnter() {
258
287
  this.$emit('open')
259
288
  },
289
+ // 离场动画结束,弹窗已真正消失
290
+ afterLeave() {
291
+ this.$emit('closed')
292
+ },
260
293
  clickHandler() {
261
294
  // 由于中部弹出时,其u-transition占据了整个页面相当于遮罩,此时需要发出遮罩点击事件,是否无法通过点击遮罩关闭弹窗
262
295
  if(this.mode === 'center') {
@@ -360,6 +360,16 @@ export default {
360
360
  const lines = [];
361
361
  const ellipsis = '...';
362
362
  const measurementCache = new Map();
363
+ const fontSize = css.fontSize ? this.convertRpxToPx(css.fontSize) : 20;
364
+ // 兜底估算:全角字符约占一个字号,半角约 0.56。测量失败时若按半角估算,
365
+ // 中文会短算 40% 而不换行,所以必须区分宽度。
366
+ const estimateWidth = (value) => Array.from(String(value)).reduce((width, char) => {
367
+ if (/[ᄀ-ᅟ⺀-〾぀-㏿㐀-䶿一-鿿ꀀ-꓏가-힣豈-﫿︰-﹯＀-⦆¢-₩]/.test(char)) {
368
+ return width + fontSize;
369
+ }
370
+ if (/\s/.test(char)) return width + fontSize * 0.28;
371
+ return width + fontSize * 0.56;
372
+ }, 0);
363
373
  const measureTextWidth = async (value) => {
364
374
  if (measurementCache.has(value)) {
365
375
  return measurementCache.get(value);
@@ -370,7 +380,12 @@ export default {
370
380
  } else {
371
381
  metrics = ctx.measureText(value);
372
382
  }
373
- const measuredWidth = Number(metrics && metrics.width) || 0;
383
+ let measuredWidth = Number(metrics && metrics.width) || 0;
384
+ // 测量不可用时(鸿蒙同步 measureText 恒返回 0)必须改用估算:
385
+ // 把 0 当作真实宽度会让下面的 <= maxWidth 恒成立,整段文本挤成一行。
386
+ if (!(measuredWidth > 0) && value) {
387
+ measuredWidth = estimateWidth(value);
388
+ }
374
389
  measurementCache.set(value, measuredWidth);
375
390
  return measuredWidth;
376
391
  };
@@ -475,15 +490,33 @@ export default {
475
490
  */
476
491
  convertRpxToPx(rpxValue) {
477
492
  if (typeof rpxValue === 'number') return rpxValue;
478
-
493
+
479
494
  // 使用rpx2px方法
480
495
  if (typeof rpxValue === 'string' && rpxValue.endsWith('rpx')) {
481
496
  const value = parseFloat(rpxValue);
482
- return rpx2px(value);
497
+ return value * this.getRpxRatio();
483
498
  }
484
-
499
+
485
500
  return parseFloat(rpxValue) || 0;
486
501
  },
502
+
503
+ /**
504
+ * 获取 rpx -> px 的统一换算比例
505
+ * @description uni.upx2px 对每个值单独判断设备宽度:当 windowWidth 超过
506
+ * rpxCalcMaxDeviceWidth(默认960)时,只有恰好等于 750 的值使用真实设备宽度,
507
+ * 其余值回退到 rpxCalcBaseDeviceWidth(默认375)。海报需要所有尺寸共用同一
508
+ * 比例,逐值换算会让宽高用上不同基准而破坏宽高比:鸿蒙 windowWidth 上报为
509
+ * 物理像素1084,750rpx算得1084、1114rpx算得557,海报因此变成横向。
510
+ * 这里只取一次比例,且刻意用非 750 的值探测,避开上面的特例分支,
511
+ * 使超宽设备统一走 baseWidth,避免画布被放大到数十MB。
512
+ * @returns {Number} 每 1rpx 对应的 px 值
513
+ * @author jry ijry@qq.com
514
+ */
515
+ getRpxRatio() {
516
+ const PROBE = 1000; // 不能用 750,750 是 upx2px 的特例值
517
+ const ratio = rpx2px(PROBE) / PROBE;
518
+ return ratio > 0 ? ratio : 1;
519
+ },
487
520
 
488
521
  /**
489
522
  * 绘制渐变背景
@@ -17,7 +17,7 @@
17
17
  import { props } from './props';
18
18
  import { mpMixin } from '../../libs/mixin/mpMixin';
19
19
  import { mixin } from '../../libs/mixin/mixin';
20
- import { addUnit, addStyle, deepMerge, getPx, guid, getDeviceInfo, os } from '../../libs/function/index';
20
+ import { addUnit, addStyle, deepMerge, getPx, guid, getDeviceInfo, os, upCreateIntersectionObserver } from '../../libs/function/index';
21
21
  import zIndex from '../../libs/config/zIndex';
22
22
  /**
23
23
  * sticky 吸顶
@@ -119,7 +119,7 @@
119
119
  observeContent() {
120
120
  // 先断掉之前的观察
121
121
  this.disconnectObserver('contentObserver')
122
- const contentObserver = uni.createIntersectionObserver(this,{
122
+ const contentObserver = upCreateIntersectionObserver(this, {
123
123
  // 检测的区间范围
124
124
  thresholds: [0.95, 0.98, 1]
125
125
  })
@@ -70,6 +70,23 @@ export function upGetRect(selector, all = false, comp = null) {
70
70
  })
71
71
  }
72
72
 
73
+ // 创建交叉观察器
74
+ // 小程序端 uni.createIntersectionObserver(vm) 会把 Vue 实例代理直接透传给原生 API,
75
+ // 原生内部的 Object.keys(vm) 会触发告警:
76
+ // Avoid app logic that relies on enumerating keys on a component instance
77
+ // (uni-app 只给 createSelectorQuery 做了 $scope 解包,没给 createIntersectionObserver 做)
78
+ // 组件实例上的同名方法内部使用 $scope(原生组件实例),不会把代理外泄,因此优先使用
79
+ export function upCreateIntersectionObserver(comp, options) {
80
+ // 各家小程序与 H5 都在组件实例上暴露了该方法,内部已完成实例解包
81
+ if (comp && typeof comp.createIntersectionObserver === 'function') {
82
+ return options ? comp.createIntersectionObserver(options) : comp.createIntersectionObserver()
83
+ }
84
+ // APP 端未在实例上暴露该方法,退回全局 API,其内部会自行解析实例,本身不产生告警
85
+ // 注意:不能传 comp.$scope,APP 端页面的 $scope 仅为 { $getAppWebview },
86
+ // 会被全局 API 误判成 options 参数从而丢失真实配置
87
+ return options ? uni.createIntersectionObserver(comp, options) : uni.createIntersectionObserver(comp)
88
+ }
89
+
73
90
  /**
74
91
  * @description 如果value小于min,取min;如果value大于max,取max
75
92
  * @param {number} min
@@ -907,6 +924,7 @@ function hslToHex(h, s, l) {
907
924
 
908
925
  export default {
909
926
  upGetRect,
927
+ upCreateIntersectionObserver,
910
928
  range,
911
929
  getPx,
912
930
  sleep,
@@ -12,6 +12,8 @@ const FALLBACK_THEME_VARS = {
12
12
  '--up-page-bg-color': '#f3f4f6',
13
13
  '--up-card-bg-color': '#ffffff',
14
14
  '--up-navbar-bg-color': '#ffffff',
15
+ '--up-navbar-glass-bg-color': 'rgba(255, 255, 255, 0.82)',
16
+ '--up-navbar-glass-blur': '20px',
15
17
  '--up-table2-header-bg-color': '#f5f7fa',
16
18
  '--up-table2-zebra-bg-color': '#fafafa',
17
19
  '--up-table2-highlight-bg-color': '#f5f7fa',
@@ -54,6 +56,8 @@ const FALLBACK_THEME_VARS = {
54
56
  '--up-page-bg-color': '#1f1f1f',
55
57
  '--up-card-bg-color': '#1c1c1e',
56
58
  '--up-navbar-bg-color': '#1c1c1e',
59
+ '--up-navbar-glass-bg-color': 'rgba(28, 28, 30, 0.82)',
60
+ '--up-navbar-glass-blur': '20px',
57
61
  '--up-table2-header-bg-color': '#2a2d33',
58
62
  '--up-table2-zebra-bg-color': '#23262b',
59
63
  '--up-table2-highlight-bg-color': '#2f3440',
@@ -73,7 +73,9 @@ const DEFAULT_THEME_EXTRA_VARS = Object.freeze({
73
73
  '--up-skeleton-shimmer-color': '#e6e6e6',
74
74
  '--up-swipe-action-button-bg-color': '#c7c6cd',
75
75
  '--up-index-list-indicator-bg-color': '#c9c9c9',
76
- '--up-calendar-month-mark-color': 'rgba(231, 232, 234, 0.83)'
76
+ '--up-calendar-month-mark-color': 'rgba(231, 232, 234, 0.83)',
77
+ '--up-navbar-glass-bg-color': 'rgba(255, 255, 255, 0.82)',
78
+ '--up-navbar-glass-blur': '20px'
77
79
  }),
78
80
  dark: Object.freeze({
79
81
  '--up-table2-header-bg-color': '#2a2d33',
@@ -84,7 +86,9 @@ const DEFAULT_THEME_EXTRA_VARS = Object.freeze({
84
86
  '--up-skeleton-shimmer-color': 'rgba(255, 255, 255, 0.12)',
85
87
  '--up-swipe-action-button-bg-color': '#4b5563',
86
88
  '--up-index-list-indicator-bg-color': '#4b5563',
87
- '--up-calendar-month-mark-color': 'rgba(255, 255, 255, 0.04)'
89
+ '--up-calendar-month-mark-color': 'rgba(255, 255, 255, 0.04)',
90
+ '--up-navbar-glass-bg-color': 'rgba(28, 28, 30, 0.82)',
91
+ '--up-navbar-glass-blur': '20px'
88
92
  })
89
93
  })
90
94
 
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.8.106",
5
+ "version": "3.8.112",
6
6
  "description": "零云®uview-plus已兼容vue3支持多语言,120+全面的组件和便捷的工具会让您信手拈来。近期新增拖动排序、条码、图片裁剪、下拉刷新、虚拟列表、签名、Markdown等。",
7
7
  "keywords": [
8
8
  "uview",
@@ -83,6 +83,10 @@ declare interface ActionSheetProps {
83
83
  * 点击取消按钮时触发
84
84
  */
85
85
  onClose?: () => any
86
+ /**
87
+ * 弹窗已关闭(离场动画结束、弹窗真正消失后)触发
88
+ */
89
+ onClosed?: () => any
86
90
  /**
87
91
  * 获取用户信息回调,openType="getUserInfo"时有效
88
92
  * @param detail 用户信息
@@ -209,6 +209,10 @@ declare interface CalendarProps {
209
209
  * 日历关闭时触发
210
210
  */
211
211
  onClose?: () => any
212
+ /**
213
+ * 日历已关闭(离场动画结束、弹窗真正消失后)触发
214
+ */
215
+ onClosed?: () => any
212
216
  }
213
217
 
214
218
  declare interface _Calendar {
@@ -122,6 +122,10 @@ declare interface DatetimePickerProps {
122
122
  * 关闭选择器时触发
123
123
  */
124
124
  onClose?: () => any
125
+ /**
126
+ * 选择器已关闭(离场动画结束、弹窗真正消失后)触发
127
+ */
128
+ onClosed?: () => any
125
129
  /**
126
130
  * 点击确定按钮,返回当前选择的值
127
131
  */
@@ -92,6 +92,10 @@ declare interface KeyboardProps {
92
92
  * 键盘关闭
93
93
  */
94
94
  onClose?: () => any
95
+ /**
96
+ * 键盘已关闭(离场动画结束、弹窗真正消失后)触发
97
+ */
98
+ onClosed?: () => any
95
99
  /**
96
100
  * 键盘顶部工具条右边的"完成"按钮被点击
97
101
  */