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
package/changelog.md CHANGED
@@ -1,3 +1,83 @@
1
+ ## 3.8.112
2
+ feat: navbar 新增 iOS 大标题模式
3
+
4
+ 新增 `mode` 属性,`ios` 值提供现代 iOS 系统应用的导航栏体验:进入页面时导航栏背景透明、标题以 34px 左对齐显示;向下滚动时大标题被压缩进导航栏,标题过渡为常规居中形态,同时出现毛玻璃磨砂背景。
5
+
6
+ - 新增 `mode` 属性,可选 `default`(默认)与 `ios`,非法值按 `default` 处理
7
+ - 新增 `scrollTop` 属性接收页面滚动距离,需由页面 `onPageScroll` 传入;不传时停留在大标题展开态
8
+ - 大标题渲染在 in-flow 层靠原生滚动位移,不经过 JS,小程序端不会因 setData 回程产生拖影
9
+ - 磨砂采用 0.82 不透明底色叠加 `backdrop-filter`:支持的端得到真实毛玻璃,不支持的端仍有 82% 不透明底色兜住文字可读性
10
+ - 玻璃与居中标题的透明度曲线分段递进(0-0.5 与 0.75-1),确保任何滚动位置都不出现两段标题文字互相透出
11
+ - 居中标题在淡入的同时由下方 12px 上浮就位,并带 0.15s 过渡补齐离散滚动事件之间的空隙
12
+ - 新增 `--up-navbar-glass-bg-color` 与 `--up-navbar-glass-blur` 主题变量,跟随明暗模式切换
13
+ - 新增 verify:navbar-ios-mode 校验脚本
14
+
15
+ 已知边界:`ios` 模式下 `fixed` 与 `placeholder` 被忽略——固定层恒定固定,in-flow 层恒定渲染,因为该层承载的是大标题这一实际内容而非可选占位。nvue 端因缺少 filter 管线、页面非原生滚动容器、`onPageScroll` 不可靠三项约束,传入 `mode="ios"` 时整体降级为 `default`。
16
+
17
+ `default` 模式的结构、样式与属性语义完全不变。
18
+
19
+ ## 3.8.111
20
+ fix: 修复小程序端使用交叉观察器组件时控制台报枚举实例键告警(#864)
21
+
22
+ 小程序端 `uni.createIntersectionObserver(this)` 会把 Vue 实例代理直接透传给原生 API,原生内部的 `Object.keys(vm)` 命中 Vue 开发模式下的 ownKeys 拦截,从而输出告警:
23
+ `[Vue warn]: Avoid app logic that relies on enumerating keys on a component instance.`
24
+ 根因是 uni-app 只为 `createSelectorQuery` 做了 `$scope` 解包,一直没有为 `createIntersectionObserver` 做同样处理。
25
+
26
+ - 新增 `upCreateIntersectionObserver(comp, options)` 公共方法:优先调用组件实例上的同名方法(内部已完成实例解包,不会外泄代理),APP 端实例上没有该方法时回退到全局 API
27
+ - u-lazy-load、u-sticky、u-cate-tab 三个组件改用该方法,小程序端不再产生告警
28
+ - u-sticky 的 `thresholds: [0.95, 0.98, 1]` 原样透传。注意不能改传 `comp.$scope`:APP 端页面的 `$scope` 仅为 `{ $getAppWebview }`,会被全局 API 误判成 options 参数,导致真实配置被静默丢弃
29
+ - u-parse/node 的观察器位于 `#ifdef H5 || APP-PLUS` 条件编译块内,不会编译进小程序,故保持不变
30
+ - 补充 `upCreateIntersectionObserver` 类型定义,新增 verify:up-create-intersection-observer 校验脚本
31
+
32
+ 组件对外行为不变,APP 端调用路径与配置均保持原样。
33
+
34
+ ## 3.8.110
35
+ feat: cropper 支持外部图片路径直接裁剪(#897)
36
+
37
+ - `chooseImage` 第二个参数新增 `imageSrc`,可传业务拍照或选图得到的本地临时路径并直接开始裁剪
38
+ - 有效 `imageSrc` 会跳过组件内置 `uni.chooseImage`;未传、空字符串或非字符串仍保持原选图行为
39
+ - 外部路径与系统选图复用同一套图片信息读取、裁剪框初始化和绘制流程
40
+ - “重选”按钮仍打开系统图片选择器;远程地址继续受目标平台读取能力和 H5 跨域限制
41
+
42
+ ## 3.8.109
43
+ feat: popup 关闭事件补齐,新增 closed 事件(#902)
44
+
45
+ close 此前只在点击遮罩、点击关闭图标时发出。外部直接把 show 置为 false 时组件内部没有走过关闭动作,不会发出任何事件,业务侧就少了一个"弹窗已关闭"的统一监听点。
46
+
47
+ - u-popup: show 由 true 变 false 时补发 close,任意关闭方式都能被监听到。内部关闭走 emitClose(),它先同步置位去重标记再 emit,因此下游在 close 的同步 handler 里修改 show 数据源不会被误判成外部关闭而重复发出
48
+ - u-popup: 新增 closed 事件,接 u-transition 已有但一直无人监听的 afterLeave,在离场动画结束、弹窗真正消失后发出。close 是"开始关闭",closed 是"已关闭"
49
+ - pageInline 模式下 transition 的 show 恒为 true、不执行离场动画,收不到 afterLeave,改由 watch 补发 closed
50
+ - closed 透传到 u-picker、u-datetime-picker、u-action-sheet、u-keyboard、u-calendar、u-color-picker、u-picker-data、u-goods-sku。其中 u-datetime-picker、u-picker-data 包裹的是 u-picker,属二级透传;u-calendar 只从主体 popup 转发,关闭内部时间选择器不会误报
51
+ - 补充 popup/picker/datetimePicker/actionSheet/keyboard/calendar 的 onClosed 类型定义
52
+ - 新增 verify:popup-close-events 校验脚本
53
+
54
+ 组件保持纯受控,渲染只依赖 show prop,未引入内部副本,老用户行为不变。
55
+
56
+ 已知取舍:业务在 close 里跨 nextTick 才把 show 置为 false 时,close 会发两次。去重标记只在当次更新周期内有效是刻意的,否则残留标记会吞掉后续真实的关闭事件。这类异步确认场景应改用 closed,它只在弹窗真正消失时发出一次。
57
+
58
+ ## 3.8.108(2026-08-18)
59
+ fix: 修复鸿蒙二维码不显示、海报文字不换行等绘图问题
60
+
61
+ 鸿蒙 CanvasContext.measureText 同步返回值恒为 0,真实宽度只通过可选 callback 经 evalJSAsync 异步回传;
62
+ 而 uni-app-plus 走 evalJSSync 同步就能拿到真值。这是同样代码在安卓
63
+ 正常、鸿蒙异常的根因。
64
+
65
+ 宽度 0 会让 drawTextWithLineClamp 里 `0 <= maxWidth` 恒成立,整段
66
+ 文本被当成一行放得下直接输出,标题横穿并压到二维码上。
67
+
68
+ - u-canvas: 新增 #ifdef APP-HARMONY 的 callback 测量分支;measureText
69
+ 不再把 0 当有效值外传;新增 estimateTextWidth 兜底
70
+ - u-poster: measureTextWidth 拿到非正数宽度时改用估算,不再 `|| 0` 静默吞掉
71
+ - 兜底估算区分全角/半角(全角 1.0、半角 0.56、空白 0.28)。原先的
72
+ length * fontSize * 0.6 会让中文短算约 40%,仍然不换行
73
+ - callback 超时从 1000ms 降到 300ms,并用 _harmonyMeasureUnavailable
74
+ 锁存状态:一次换行要二分测量十几次,逐次干等会把导出拖成十几秒
75
+ - 新增 verify:harmony-poster-text-wrap 校验脚本
76
+
77
+
78
+ ## 3.8.107(2026-08-18)
79
+ fix: 修复empty示例页面
80
+
1
81
  ## 3.8.106
2
82
  feat: 让 App 原生 nvue 页面完整复用 App.up.vue 根容器
3
83
 
@@ -3,6 +3,7 @@
3
3
  :show="show"
4
4
  mode="bottom"
5
5
  @close="closeHandler"
6
+ @closed="$emit('closed')"
6
7
  :safeAreaInsetBottom="safeAreaInsetBottom"
7
8
  :round="round"
8
9
  >
@@ -156,6 +157,7 @@
156
157
  *
157
158
  * @event {Function} select 点击ActionSheet列表项时触发
158
159
  * @event {Function} close 点击取消按钮时触发
160
+ * @event {Function} closed 弹窗已关闭(离场动画结束、弹窗真正消失后)触发
159
161
  * @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效
160
162
  * @event {Function} contact 客服消息回调,openType="contact"时有效
161
163
  * @event {Function} getphonenumber 获取用户手机号回调,openType="getPhoneNumber"时有效
@@ -224,7 +226,7 @@
224
226
  })
225
227
  }
226
228
  },
227
- emits: ["close", "select", "update:show"],
229
+ emits: ["close", "closed", "select", "update:show"],
228
230
  methods: {
229
231
  // 关闭操作菜单事件处理
230
232
  closeHandler() {
@@ -12,6 +12,7 @@
12
12
  :bgColor="bgColor"
13
13
  :closeable="!pageInline"
14
14
  @close="close"
15
+ @closed="$emit('closed')"
15
16
  :round="round"
16
17
  :pageInline="pageInline"
17
18
  :closeOnClickOverlay="closeOnClickOverlay"
@@ -236,6 +237,7 @@ import { t } from '../../libs/i18n'
236
237
  *
237
238
  * @event {Function()} confirm 点击确定按钮时触发 选择日期相关的返回参数
238
239
  * @event {Function()} close 日历关闭时触发 可定义页面关闭时的回调事件
240
+ * @event {Function()} closed 日历已关闭(离场动画结束、弹窗真正消失后)触发
239
241
  * @example <u-calendar :defaultDate="defaultDateMultiple" :show="show" mode="multiple" @confirm="confirm">
240
242
  </u-calendar>
241
243
  * */
@@ -411,7 +413,7 @@ export default {
411
413
  this.start = Date.now()
412
414
  this.init()
413
415
  },
414
- emits: ["confirm", "close"],
416
+ emits: ["confirm", "close", "closed"],
415
417
  methods: {
416
418
  addUnit,
417
419
  padTime(num) {
@@ -21,7 +21,7 @@
21
21
  />
22
22
  <!-- #endif -->
23
23
 
24
- <!-- #ifdef APP-PLUS -->
24
+ <!-- #ifdef APP-PLUS || APP-HARMONY -->
25
25
  <!-- #ifndef APP-NVUE -->
26
26
  <canvas
27
27
  class="u-canvas__canvas"
@@ -203,7 +203,7 @@ export default {
203
203
  size: true
204
204
  },
205
205
  (res) => {
206
- // #ifdef APP-PLUS
206
+ // #ifdef APP-PLUS || APP-HARMONY
207
207
  resolve(res || {
208
208
  width: this.actualWidth,
209
209
  height: this.actualHeight
@@ -232,7 +232,7 @@ export default {
232
232
  return this._webViewContext;
233
233
  // #endif
234
234
 
235
- // #ifdef APP-PLUS
235
+ // #ifdef APP-PLUS || APP-HARMONY
236
236
  return uni.createCanvasContext(this.canvasId, this);
237
237
  // #endif
238
238
 
@@ -364,7 +364,7 @@ export default {
364
364
  measureText: (text, state) => {
365
365
  const matched = String(state.font || '').match(/(\d+(?:\.\d+)?)px/);
366
366
  const fontSize = matched ? Number(matched[1]) : this.fontSize;
367
- return { width: String(text).length * fontSize * 0.6 };
367
+ return { width: this.estimateTextWidth(text, fontSize) };
368
368
  }
369
369
  });
370
370
  this.ctx = this._webViewContext;
@@ -646,18 +646,77 @@ export default {
646
646
  }
647
647
  return this.callContext('strokeText', String(text), x, y, maxWidth);
648
648
  },
649
+ /**
650
+ * 按字形宽度估算文本宽度
651
+ * @description 当平台无法给出真实测量值时的兜底。必须区分全角/半角:
652
+ * 汉字、假名、全角标点约占一个字号,按半角的 0.6 估算会短 40%,
653
+ * 中文海报因此算出"整段都放得下"而不换行。
654
+ * @param {String} text 待测量文本
655
+ * @param {Number} [fontSize] 字号,默认取组件当前字号
656
+ * @returns {Number} 估算宽度(px)
657
+ * @author jry ijry@qq.com
658
+ */
659
+ estimateTextWidth(text, fontSize) {
660
+ const size = Number(fontSize) || Number(this.fontSize) || 12;
661
+ const FULL_WIDTH = /[ᄀ-ᅟ⺀-〾ぁ-㏿㐀-䶿一-鿿ꀀ-꓏가-힣豈-﫿︰-﹯＀-⦆¢-₩]/;
662
+ return Array.from(String(text)).reduce((width, char) => {
663
+ if (FULL_WIDTH.test(char)) return width + size;
664
+ if (/\s/.test(char)) return width + size * 0.28;
665
+ return width + size * 0.56;
666
+ }, 0);
667
+ },
649
668
  measureText(text) {
650
669
  if (this.ctx && typeof this.ctx.measureText === 'function') {
651
- return this.ctx.measureText(String(text));
670
+ const metrics = this.ctx.measureText(String(text));
671
+ const width = Number(metrics && metrics.width);
672
+ // 鸿蒙同步测量恒为 0(真实值只走 callback),上下文未就绪时其他
673
+ // 平台也可能返回 0。绝不能把 0 交给调用方——换行逻辑会把它当成
674
+ // "宽度足够",于是整段文本挤成一行。
675
+ if (width > 0) return metrics;
652
676
  }
653
677
  return {
654
- width: String(text).length * this.fontSize * 0.6
678
+ width: this.estimateTextWidth(text)
655
679
  };
656
680
  },
657
681
  measureTextAsync(text) {
658
682
  if (this.ctx && typeof this.ctx.measureTextAsync === 'function') {
659
683
  return this.ctx.measureTextAsync(String(text));
660
684
  }
685
+
686
+ // #ifdef APP-HARMONY
687
+ // 鸿蒙的 CanvasContext.measureText 同步返回值恒为 0,真实宽度只通过
688
+ // callback(webview.evalJSAsync) 回传,因此必须走回调形式。
689
+ if (this.ctx && typeof this.ctx.measureText === 'function' && !this._harmonyMeasureUnavailable) {
690
+ return new Promise((resolve) => {
691
+ let settled = false;
692
+ // evalJSAsync 并非所有鸿蒙版本都提供,回调可能永远不来,
693
+ // 必须兜底避免上层 await 永久挂起。且一旦超时就标记为不可用:
694
+ // 单次换行要二分测量十几次,逐次干等会把导出拖成十几秒。
695
+ const timer = setTimeout(() => {
696
+ if (settled) return;
697
+ settled = true;
698
+ this._harmonyMeasureUnavailable = true;
699
+ resolve({ width: this.estimateTextWidth(text) });
700
+ }, 300);
701
+ const done = (metrics) => {
702
+ if (settled) return;
703
+ settled = true;
704
+ clearTimeout(timer);
705
+ const width = Number(metrics && metrics.width);
706
+ resolve({ width: width > 0 ? width : this.estimateTextWidth(text) });
707
+ };
708
+ try {
709
+ const sync = this.ctx.measureText(String(text), done);
710
+ // 若该平台其实同步返回了有效值,直接采用
711
+ const syncWidth = Number(sync && sync.width);
712
+ if (syncWidth > 0) done(sync);
713
+ } catch (error) {
714
+ done(null);
715
+ }
716
+ });
717
+ }
718
+ // #endif
719
+
661
720
  return Promise.resolve(this.measureText(text));
662
721
  },
663
722
  createLinearGradient(x0, y0, x1, y1) {
@@ -800,8 +859,8 @@ export default {
800
859
  let destWidth = hasDestWidth ? options.destWidth : width;
801
860
  let destHeight = hasDestHeight ? options.destHeight : height;
802
861
 
803
- // MP、H5 和 APP-PLUS 保持逻辑绘制坐标,只提升默认导出像素。
804
- // #ifdef MP || H5 || APP-PLUS
862
+ // MP、H5、APP-PLUS 和 APP-HARMONY 保持逻辑绘制坐标,只提升默认导出像素。
863
+ // #ifdef MP || H5 || APP-PLUS || APP-HARMONY
805
864
  if (!hasDestWidth) {
806
865
  destWidth = Math.round(width * this.dpr);
807
866
  }
@@ -47,7 +47,7 @@
47
47
  </view>
48
48
  </template>
49
49
  <script>
50
- import { addUnit, sleep } from '../../libs/function/index';
50
+ import { addUnit, sleep, upCreateIntersectionObserver } from '../../libs/function/index';
51
51
  export default {
52
52
  name: 'up-cate-tab',
53
53
  props: {
@@ -179,7 +179,7 @@
179
179
  this._observerList = [];
180
180
 
181
181
  this.tabList.map((val, index) => {
182
- let observer = uni.createIntersectionObserver(this);
182
+ let observer = upCreateIntersectionObserver(this);
183
183
  this._observerList.push(observer);
184
184
  // 检测相交状态
185
185
  observer.relativeTo('.u-cate-tab__right-box', {
@@ -4,7 +4,7 @@
4
4
  :style="{backgroundColor: value}" >
5
5
  <slot></slot>
6
6
  </view>
7
- <up-popup :show="show" mode="bottom" round="10" @close="close" :closeOnClickOverlay="true">
7
+ <up-popup :show="show" mode="bottom" round="10" @close="close" @closed="$emit('closed')" :closeOnClickOverlay="true">
8
8
  <view class="up-color-picker__content">
9
9
  <view class="up-color-picker__header">
10
10
  <text class="up-color-picker__title">选择颜色</text>
@@ -267,7 +267,7 @@ export default {
267
267
  mounted() {
268
268
  this.initColor()
269
269
  },
270
- emits: ['update:modelValue', 'confirm', 'close'],
270
+ emits: ['update:modelValue', 'confirm', 'close', 'closed'],
271
271
  methods: {
272
272
  // 初始化颜色
273
273
  initColor() {
@@ -221,68 +221,71 @@
221
221
  }
222
222
  this.hideImg();
223
223
  },
224
- select() {
225
- if (this.fSelecting) return;
226
- this.fSelecting = true;
227
- setTimeout(() => { this.fSelecting = false; }, 500);
228
- const self = this
229
- uni.chooseImage({
230
- count: 1,
231
- sizeType: ['original', 'compressed'],
232
- sourceType: ['album', 'camera'],
233
- success: (r) => {
234
- uni.showLoading({ mask: true });
235
- let path = this.imgPath = r.tempFilePaths[0];
236
- uni.getImageInfo({
237
- src: path,
238
- success: r => {
239
- this.imgWidth = r.width;
240
- this.imgHeight = r.height;
241
- this.path = path;
242
- if (!this.hasSel) {
243
- let style = this.selStyle || {};
244
- if (this.arWidth && this.arHeight) {
245
- let areaWidth = this.arWidth.indexOf('rpx') >= 0 ? parseInt(this.arWidth) * this.pxRatio : parseInt(this.arWidth),
246
- areaHeight = this.arHeight.indexOf('rpx') >= 0 ? parseInt(this.arHeight) * this.pxRatio : parseInt(this.arHeight);
247
- style.width = areaWidth + 'px';
248
- style.height = areaHeight + 'px';
249
- style.top = (this.windowHeight - areaHeight - tabHeight) / 2 + 'px';
250
- style.left = (this.windowWidth - areaWidth) / 2 + 'px';
251
- } else {
252
- uni.showModal({
253
- title: t("up.cropper.emptyWidhtOrHeight"),
254
- showCancel: false
255
- })
256
- return;
257
- }
258
- this.selStyle = style;
259
- }
260
-
261
- if (this.noBar) {
262
- this.drawInit(true);
263
- } else {
264
- uni.hideTabBar({
265
- complete: () => {
266
- this.drawInit(true);
267
- }
268
- });
269
- }
270
- },
271
- fail: () => {
272
- uni.showToast({
273
- title: "error3",
274
- duration: 2000,
275
- })
276
- },
277
- complete() {
278
- uni.hideLoading();
279
- }
280
- });
281
- }, fail(err) {
282
- self.$emit('cancel')
283
- }
284
- })
285
- },
224
+ loadImage(path) {
225
+ uni.showLoading({ mask: true });
226
+ this.imgPath = path;
227
+ uni.getImageInfo({
228
+ src: path,
229
+ success: r => {
230
+ this.imgWidth = r.width;
231
+ this.imgHeight = r.height;
232
+ this.path = path;
233
+ if (!this.hasSel) {
234
+ let style = this.selStyle || {};
235
+ if (this.arWidth && this.arHeight) {
236
+ let areaWidth = this.arWidth.indexOf('rpx') >= 0 ? parseInt(this.arWidth) * this.pxRatio : parseInt(this.arWidth),
237
+ areaHeight = this.arHeight.indexOf('rpx') >= 0 ? parseInt(this.arHeight) * this.pxRatio : parseInt(this.arHeight);
238
+ style.width = areaWidth + 'px';
239
+ style.height = areaHeight + 'px';
240
+ style.top = (this.windowHeight - areaHeight - tabHeight) / 2 + 'px';
241
+ style.left = (this.windowWidth - areaWidth) / 2 + 'px';
242
+ } else {
243
+ uni.showModal({
244
+ title: t("up.cropper.emptyWidhtOrHeight"),
245
+ showCancel: false
246
+ })
247
+ return;
248
+ }
249
+ this.selStyle = style;
250
+ }
251
+
252
+ if (this.noBar) {
253
+ this.drawInit(true);
254
+ } else {
255
+ uni.hideTabBar({
256
+ complete: () => {
257
+ this.drawInit(true);
258
+ }
259
+ });
260
+ }
261
+ },
262
+ fail: () => {
263
+ uni.showToast({
264
+ title: "error3",
265
+ duration: 2000,
266
+ })
267
+ },
268
+ complete() {
269
+ uni.hideLoading();
270
+ }
271
+ });
272
+ },
273
+ select() {
274
+ if (this.fSelecting) return;
275
+ this.fSelecting = true;
276
+ setTimeout(() => { this.fSelecting = false; }, 500);
277
+ uni.chooseImage({
278
+ count: 1,
279
+ sizeType: ['original', 'compressed'],
280
+ sourceType: ['album', 'camera'],
281
+ success: (r) => {
282
+ this.loadImage(r.tempFilePaths[0]);
283
+ },
284
+ fail: () => {
285
+ this.$emit('cancel')
286
+ }
287
+ })
288
+ },
286
289
  async confirm() {
287
290
  if (this.fUploading) return;
288
291
  this.fUploading = true;
@@ -725,9 +728,10 @@
725
728
  uni.hideLoading();
726
729
  }
727
730
  });
728
- },
729
- chooseImage(index = undefined, params = undefined, data = undefined) {
730
- if (params) {
731
+ },
732
+ chooseImage(index = undefined, params = undefined, data = undefined) {
733
+ const imageSrc = typeof params?.imageSrc === 'string' ? params.imageSrc.trim() : '';
734
+ if (params) {
731
735
  console.log(params)
732
736
  let areaWidth = params.areaWidth || this.areaWidth,
733
737
  areaHeight = params.areaHeight || this.areaHeight,
@@ -774,11 +778,15 @@
774
778
  // console.log(this.selStyle);
775
779
  this.hasSel = true;
776
780
  }
777
- }
778
- this.rtn = data;
779
- this.indx = index;
780
- this.select();
781
- },
781
+ }
782
+ this.rtn = data;
783
+ this.indx = index;
784
+ if (imageSrc) {
785
+ this.loadImage(imageSrc);
786
+ return;
787
+ }
788
+ this.select();
789
+ },
782
790
  rotate() {
783
791
  // #ifdef APP-PLUS
784
792
  if (this.platform === 'android') {
@@ -33,6 +33,7 @@
33
33
  :maskClass="maskClass"
34
34
  :maskStyle="resolvedMaskStyle"
35
35
  @close="close"
36
+ @closed="$emit('closed')"
36
37
  @cancel="cancel"
37
38
  @confirm="confirm"
38
39
  @change="change"
@@ -93,6 +94,7 @@
93
94
  * @property {Boolean} closeOnClickOverlay 是否允许点击遮罩关闭选择器 ( 默认 false )
94
95
  * @property {Array} defaultIndex 各列的默认索引
95
96
  * @event {Function} close 关闭选择器时触发
97
+ * @event {Function} closed 选择器已关闭(离场动画结束、弹窗真正消失后)触发
96
98
  * @event {Function} confirm 点击确定按钮,返回当前选择的值
97
99
  * @event {Function} change 当选择值变化时触发
98
100
  * @event {Function} cancel 点击取消按钮
@@ -191,7 +193,7 @@
191
193
  }
192
194
  },
193
195
  // #ifdef VUE3
194
- emits: ['close', 'cancel', 'confirm', 'change', 'update:modelValue'],
196
+ emits: ['close', 'closed', 'cancel', 'confirm', 'change', 'update:modelValue'],
195
197
  // #endif
196
198
  methods: {
197
199
  toInt(value, fallback = 0) {
@@ -10,6 +10,7 @@
10
10
  :pageInline="pageInline"
11
11
  :border-radius="20"
12
12
  @close="close"
13
+ @closed="$emit('closed')"
13
14
  >
14
15
  <view class="up-goods-sku-container" :style="{padding: pageInline ? '0px' : ''}">
15
16
  <view class="up-goods-sku__header">
@@ -175,7 +176,7 @@
175
176
  },
176
177
  watch: {
177
178
  },
178
- emits: ['open', 'confirm', 'close'],
179
+ emits: ['open', 'confirm', 'close', 'closed'],
179
180
  created() {
180
181
  if (this.pageInline) {
181
182
  this.show = true;
@@ -7,6 +7,7 @@
7
7
  :show="show"
8
8
  :safeAreaInsetBottom="safeAreaInsetBottom"
9
9
  @close="popupClose"
10
+ @closed="$emit('closed')"
10
11
  :zIndex="zIndex"
11
12
  :customStyle="popupStyle"
12
13
  >
@@ -111,7 +112,7 @@
111
112
  }
112
113
  }
113
114
  },
114
- emits: ["change", "close", "confirm", "cancel", "backspace"],
115
+ emits: ["change", "close", "closed", "confirm", "cancel", "backspace"],
115
116
  methods: {
116
117
  change(e) {
117
118
  this.$emit('change', e);
@@ -20,7 +20,8 @@
20
20
  import {
21
21
  addUnit,
22
22
  guid,
23
- rpx2px
23
+ rpx2px,
24
+ upCreateIntersectionObserver
24
25
  } from '../../libs/function/index.js';
25
26
  /**
26
27
  * lazyLoad 懒加载
@@ -211,10 +212,11 @@
211
212
 
212
213
  setTimeout(() => {
213
214
  // #ifndef APP-NVUE
214
- // 这里是组件内获取布局状态,不能用uni.createIntersectionObserver,而必须用this.createIntersectionObserver
215
+ // 这里是组件内获取布局状态,不能直传Vue实例给uni.createIntersectionObserver
216
+ // 否则小程序内部会Object.keys(vm)导致告警,统一走upCreateIntersectionObserver
215
217
  // this.disconnectObserver('contentObserver');
216
218
  // nvue 里不支持
217
- const contentObserver = uni.createIntersectionObserver(this);
219
+ const contentObserver = upCreateIntersectionObserver(this);
218
220
  // 要理解这里怎么计算的,请看这个:
219
221
  // https://blog.csdn.net/qq_25324335/article/details/83687695
220
222
  contentObserver.relativeToViewport({
@@ -26,7 +26,9 @@ export default {
26
26
  leftIconSize: 20,
27
27
  leftIconColor: '',
28
28
  autoBack: false,
29
- titleStyle: ''
29
+ titleStyle: '',
30
+ mode: 'default',
31
+ scrollTop: 0
30
32
  }
31
33
 
32
34
  }
@@ -94,6 +94,16 @@ export const props = defineMixin({
94
94
  titleStyle: {
95
95
  type: [String, Object],
96
96
  default: () => defProps.navbar.titleStyle
97
+ },
98
+ // 导航栏模式,default-常规,ios-大标题磨砂模式
99
+ mode: {
100
+ type: String,
101
+ default: () => defProps.navbar.mode
102
+ },
103
+ // 页面滚动距离,仅 ios 模式使用,由页面 onPageScroll 传入
104
+ scrollTop: {
105
+ type: [String, Number],
106
+ default: () => defProps.navbar.scrollTop
97
107
  }
98
108
  }
99
109
  })
@@ -2,6 +2,8 @@
2
2
  page,
3
3
  body {
4
4
  --up-navbar-bg-color: #ffffff;
5
+ --up-navbar-glass-bg-color: rgba(255, 255, 255, 0.82);
6
+ --up-navbar-glass-blur: 20px;
5
7
  }
6
8
 
7
9
  @media (prefers-color-scheme: dark) {
@@ -9,13 +11,16 @@ body {
9
11
  page,
10
12
  body {
11
13
  --up-navbar-bg-color: #1c1c1e;
14
+ --up-navbar-glass-bg-color: rgba(28, 28, 30, 0.82);
12
15
  }
13
16
  }
14
17
 
15
18
  [data-up-theme='light'] {
16
19
  --up-navbar-bg-color: #ffffff;
20
+ --up-navbar-glass-bg-color: rgba(255, 255, 255, 0.82);
17
21
  }
18
22
 
19
23
  [data-up-theme='dark'] {
20
24
  --up-navbar-bg-color: #1c1c1e;
25
+ --up-navbar-glass-bg-color: rgba(28, 28, 30, 0.82);
21
26
  }