uview-plus 3.8.86 → 3.8.106

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 (82) hide show
  1. package/changelog.md +150 -3
  2. package/components/u-action-sheet/u-action-sheet.vue +21 -2
  3. package/components/u-barcode/u-barcode.vue +0 -2
  4. package/components/u-button/u-button.vue +2 -5
  5. package/components/u-canvas/u-canvas.vue +368 -74
  6. package/components/u-cell/u-cell.vue +8 -0
  7. package/components/u-datetime-picker/u-datetime-picker.vue +53 -4
  8. package/components/u-dragsort/u-dragsort.vue +55 -31
  9. package/components/u-icon/u-icon.vue +12 -3
  10. package/components/u-icon/util.js +81 -10
  11. package/components/u-index-item/u-index-item.vue +1 -1
  12. package/components/u-index-list/u-index-list.vue +1 -1
  13. package/components/u-novel-reader/content-normalizer.js +80 -0
  14. package/components/u-novel-reader/layout-engine.js +225 -0
  15. package/components/u-novel-reader/measure-adapter.js +69 -0
  16. package/components/u-novel-reader/novelReader.js +35 -0
  17. package/components/u-novel-reader/persistence.js +144 -0
  18. package/components/u-novel-reader/props.js +100 -0
  19. package/components/u-novel-reader/reader-catalog.vue +234 -0
  20. package/components/u-novel-reader/reader-content.vue +226 -0
  21. package/components/u-novel-reader/reader-core.js +151 -0
  22. package/components/u-novel-reader/reader-settings.vue +325 -0
  23. package/components/u-novel-reader/reader-toolbar.vue +313 -0
  24. package/components/u-novel-reader/theme-vars.scss +49 -0
  25. package/components/u-novel-reader/u-novel-reader.vue +836 -0
  26. package/components/u-poster/u-poster.vue +236 -219
  27. package/components/u-qrcode/qrcode.js +56 -49
  28. package/components/u-qrcode/u-qrcode.vue +159 -88
  29. package/components/u-scroll-list/scrollWxs.wxs +1 -1
  30. package/components/u-slider/u-slider.vue +1 -1
  31. package/components/u-swipe-action-item/index.wxs +43 -25
  32. package/components/u-swipe-action-item/nvue.js +9 -0
  33. package/components/u-swipe-action-item/other.js +32 -21
  34. package/components/u-swipe-action-item/props.js +5 -0
  35. package/components/u-swipe-action-item/swipeActionItem.js +1 -0
  36. package/components/u-swipe-action-item/u-swipe-action-item.vue +28 -4
  37. package/components/u-switch/u-switch.vue +1 -1
  38. package/components/u-tabbar/u-tabbar.vue +2 -1
  39. package/components/u-tabbar-item/u-tabbar-item.vue +64 -21
  40. package/components/u-tabs/u-tabs.vue +11 -8
  41. package/components/u-tabs-pro/u-tabs-pro.vue +212 -0
  42. package/components/u-text/text.js +1 -1
  43. package/components/u-text/u-text.vue +18 -6
  44. package/components/u-upload/u-upload.vue +1 -1
  45. package/components/u-waterfall/u-waterfall.vue +118 -65
  46. package/libs/config/config.js +1 -1
  47. package/libs/config/props.js +1 -0
  48. package/libs/function/index.js +66 -0
  49. package/libs/mixin/mixin.js +4 -50
  50. package/libs/root/index.js +78 -5
  51. package/libs/root/page.js +7 -7
  52. package/libs/root/root.js +73 -3
  53. package/libs/util/app-nvue-webview-canvas.js +486 -0
  54. package/libs/util/gcanvas/bridge/bridge-weex.js +0 -2
  55. package/libs/util/gcanvas/context-2d/FillStyleLinearGradient.js +0 -0
  56. package/libs/util/gcanvas/context-2d/FillStylePattern.js +0 -0
  57. package/libs/util/gcanvas/context-2d/FillStyleRadialGradient.js +0 -0
  58. package/libs/util/gcanvas/context-2d/RenderingContext.js +0 -0
  59. package/libs/util/gcanvas/context-webgl/ActiveInfo.js +0 -0
  60. package/libs/util/gcanvas/context-webgl/Buffer.js +0 -0
  61. package/libs/util/gcanvas/context-webgl/Framebuffer.js +0 -0
  62. package/libs/util/gcanvas/context-webgl/GLenum.js +0 -0
  63. package/libs/util/gcanvas/context-webgl/GLmethod.js +0 -0
  64. package/libs/util/gcanvas/context-webgl/GLtype.js +0 -0
  65. package/libs/util/gcanvas/context-webgl/Program.js +0 -0
  66. package/libs/util/gcanvas/context-webgl/Renderbuffer.js +0 -0
  67. package/libs/util/gcanvas/context-webgl/RenderingContext.js +0 -0
  68. package/libs/util/gcanvas/context-webgl/Shader.js +0 -0
  69. package/libs/util/gcanvas/context-webgl/ShaderPrecisionFormat.js +0 -0
  70. package/libs/util/gcanvas/context-webgl/Texture.js +0 -0
  71. package/libs/util/gcanvas/context-webgl/UniformLocation.js +0 -0
  72. package/libs/util/gcanvas/context-webgl/classUtils.js +0 -0
  73. package/libs/util/gcanvas/env/canvas.js +0 -0
  74. package/libs/util/gcanvas/env/image.js +0 -0
  75. package/libs/util/gcanvas/env/tool.js +0 -0
  76. package/libs/util/gcanvas/index.js +3 -3
  77. package/package.json +1 -1
  78. package/types/comps/swipeActionItem.d.ts +13 -0
  79. package/types/comps/tabs.d.ts +2 -1
  80. package/types/comps/text.d.ts +1 -1
  81. package/types/func.d.ts +23 -0
  82. package/types/index.d.ts +1 -0
@@ -22,6 +22,7 @@
22
22
  <!-- #endif -->
23
23
 
24
24
  <!-- #ifdef APP-PLUS -->
25
+ <!-- #ifndef APP-NVUE -->
25
26
  <canvas
26
27
  class="u-canvas__canvas"
27
28
  :id="canvasId"
@@ -33,15 +34,15 @@
33
34
  @touchend="onTouchEnd"
34
35
  />
35
36
  <!-- #endif -->
37
+ <!-- #endif -->
36
38
 
37
39
  <!-- #ifdef APP-NVUE -->
38
- <gcanvas
40
+ <web-view
39
41
  class="u-canvas__canvas"
40
- ref="gcanvas"
42
+ ref="web"
43
+ src="/static/app-plus/up-canvas/local.html"
41
44
  :style="{ width: actualWidth + unit, height: actualHeight + unit }"
42
- @touchstart="onTouchStart"
43
- @touchmove="onTouchMove"
44
- @touchend="onTouchEnd"
45
+ @onPostMessage="onWebViewMessage"
45
46
  />
46
47
  <!-- #endif -->
47
48
  </view>
@@ -50,10 +51,9 @@
50
51
  <script>
51
52
  // #ifdef APP-NVUE
52
53
  import {
53
- enable,
54
- WeexBridge,
55
- Image as GImage
56
- } from '../../libs/util/gcanvas/index.js';
54
+ createWebViewCanvasBridge,
55
+ createWebViewCanvasContext
56
+ } from '../../libs/util/app-nvue-webview-canvas.js';
57
57
  // #endif
58
58
 
59
59
  export default {
@@ -125,13 +125,27 @@ export default {
125
125
  this._selectorResult = null;
126
126
  this._canvasElement = null;
127
127
  this._imageCache = Object.create(null);
128
+ this._imageDataCache = Object.create(null);
128
129
  this._isNvue = false;
130
+ this._initPromise = null;
131
+ this._webViewBridge = null;
132
+ this._webViewContext = null;
133
+ this._webViewInitSignature = null;
134
+ this._webViewSessionId = null;
129
135
  },
130
136
  mounted() {
131
137
  this.$nextTick(() => {
132
138
  this.initCanvas();
133
139
  });
134
140
  },
141
+ beforeUnmount() {
142
+ if (this._webViewBridge) {
143
+ this._webViewBridge.destroy();
144
+ }
145
+ this._webViewBridge = null;
146
+ this._webViewContext = null;
147
+ this.ctx = null;
148
+ },
135
149
  methods: {
136
150
  parseSize(value) {
137
151
  if (typeof value === 'number') {
@@ -157,22 +171,29 @@ export default {
157
171
  onTouchEnd(event) {
158
172
  this.$emit('touchend', event);
159
173
  },
174
+ onWebViewMessage(event) {
175
+ if (this._webViewBridge) {
176
+ this._webViewBridge.handleMessage(event);
177
+ }
178
+ },
179
+ onWebViewTouch(message) {
180
+ const eventType = message.eventType;
181
+ if (!['touchstart', 'touchmove', 'touchend'].includes(eventType)) return;
182
+ this.$emit(eventType, {
183
+ type: eventType,
184
+ detail: {
185
+ x: message.x,
186
+ y: message.y
187
+ },
188
+ touches: message.touches || [],
189
+ changedTouches: message.changedTouches || [],
190
+ canvasWidth: message.canvasWidth,
191
+ canvasHeight: message.canvasHeight
192
+ });
193
+ },
160
194
  async getCanvasNode(id = this.canvasId, isCanvas = true) {
161
195
  return new Promise((resolve) => {
162
196
  try {
163
- // #ifdef APP-NVUE
164
- setTimeout(() => {
165
- const gcanvas = this.$refs.gcanvas;
166
- if (!gcanvas) {
167
- resolve(false);
168
- return;
169
- }
170
- this._isNvue = true;
171
- resolve(enable(gcanvas, { bridge: WeexBridge }));
172
- }, 100);
173
- // #endif
174
-
175
- // #ifndef APP-NVUE
176
197
  uni.createSelectorQuery()
177
198
  .in(this)
178
199
  .select(`#${id}`)
@@ -182,11 +203,18 @@ export default {
182
203
  size: true
183
204
  },
184
205
  (res) => {
206
+ // #ifdef APP-PLUS
207
+ resolve(res || {
208
+ width: this.actualWidth,
209
+ height: this.actualHeight
210
+ });
211
+ return;
212
+ // #endif
213
+
185
214
  resolve(res || false);
186
215
  }
187
216
  )
188
217
  .exec();
189
- // #endif
190
218
  } catch (error) {
191
219
  console.error('获取画布节点失败:', error);
192
220
  resolve(false);
@@ -200,14 +228,12 @@ export default {
200
228
  return this.ctx;
201
229
  },
202
230
  getCanvasContext() {
203
- // #ifdef APP-PLUS
204
- return uni.createCanvasContext(this.canvasId, this);
231
+ // #ifdef APP-NVUE
232
+ return this._webViewContext;
205
233
  // #endif
206
234
 
207
- // #ifdef APP-NVUE
208
- return this._canvasElement && typeof this._canvasElement.getContext === 'function'
209
- ? this._canvasElement.getContext('2d')
210
- : null;
235
+ // #ifdef APP-PLUS
236
+ return uni.createCanvasContext(this.canvasId, this);
211
237
  // #endif
212
238
 
213
239
  // #ifdef MP || H5
@@ -229,10 +255,32 @@ export default {
229
255
  }
230
256
  },
231
257
  async initCanvas(force = false) {
258
+ if (this._initPromise) {
259
+ return this._initPromise;
260
+ }
261
+
262
+ const initPromise = this._initializeCanvas(force);
263
+ this._initPromise = initPromise;
264
+
265
+ try {
266
+ return await initPromise;
267
+ } finally {
268
+ if (this._initPromise === initPromise) {
269
+ this._initPromise = null;
270
+ }
271
+ }
272
+ },
273
+ async _initializeCanvas(force = false) {
232
274
  try {
233
275
  if (this.useRootHeightAndWidth) {
234
276
  await this.setNewSize();
235
277
  }
278
+ // #ifdef APP-NVUE
279
+ if (typeof createWebViewCanvasBridge === 'function') {
280
+ return await this._initializeWebViewCanvas(force);
281
+ }
282
+ // #endif
283
+
236
284
  if (this.ctx && !force) {
237
285
  this.$emit('ready', {
238
286
  width: this.actualWidth,
@@ -247,10 +295,17 @@ export default {
247
295
  }
248
296
 
249
297
  this._selectorResult = this._canvasNode;
250
- this._canvasElement = this._canvasNode.node || this._canvasNode;
251
- this.dpr = uni.getSystemInfoSync().pixelRatio || 1;
298
+ this._canvasElement = this._isNvue
299
+ ? this._canvasNode
300
+ : (this._canvasNode.node || null);
301
+ const systemInfo = uni.getSystemInfoSync() || {};
302
+ const pixelRatio = Number(systemInfo.pixelRatio) || 1;
303
+ // 微信开发者工具的模拟器预览通常按高密度屏幕缩放,至少使用 2 倍 backing store。
304
+ this.dpr = systemInfo.platform === 'devtools'
305
+ ? Math.max(pixelRatio, 2)
306
+ : pixelRatio;
252
307
 
253
- // #ifdef MP || H5
308
+ // #ifdef MP
254
309
  if (this._canvasElement) {
255
310
  this._canvasElement.width = Math.ceil(this.actualWidth * this.dpr);
256
311
  this._canvasElement.height = Math.ceil(this.actualHeight * this.dpr);
@@ -262,7 +317,7 @@ export default {
262
317
  return false;
263
318
  }
264
319
 
265
- // #ifdef MP || H5
320
+ // #ifdef MP
266
321
  if (typeof this.ctx.setTransform === 'function') {
267
322
  this.ctx.setTransform(this.dpr, 0, 0, this.dpr, 0, 0);
268
323
  } else if (typeof this.ctx.scale === 'function') {
@@ -282,6 +337,64 @@ export default {
282
337
  return false;
283
338
  }
284
339
  },
340
+ async _initializeWebViewCanvas(force = false) {
341
+ this._isNvue = true;
342
+ const systemInfo = uni.getSystemInfoSync() || {};
343
+ this.dpr = Math.max(1, Number(systemInfo.pixelRatio) || 1);
344
+
345
+ if (!this._webViewBridge) {
346
+ this._webViewBridge = createWebViewCanvasBridge({
347
+ getWebView: () => this.$refs.web,
348
+ onTouch: message => this.onWebViewTouch(message),
349
+ onReady: (message) => {
350
+ if (
351
+ this._webViewSessionId &&
352
+ message.sessionId &&
353
+ this._webViewSessionId !== message.sessionId
354
+ ) {
355
+ this._webViewInitSignature = null;
356
+ }
357
+ this._webViewSessionId = message.sessionId || null;
358
+ },
359
+ onError: error => console.error('Canvas WebView错误:', error)
360
+ });
361
+ this._webViewContext = createWebViewCanvasContext({
362
+ bridge: this._webViewBridge,
363
+ resolveImage: source => this.resolveNvueImageSource(source),
364
+ measureText: (text, state) => {
365
+ const matched = String(state.font || '').match(/(\d+(?:\.\d+)?)px/);
366
+ const fontSize = matched ? Number(matched[1]) : this.fontSize;
367
+ return { width: String(text).length * fontSize * 0.6 };
368
+ }
369
+ });
370
+ this.ctx = this._webViewContext;
371
+ }
372
+
373
+ await this._webViewBridge.ready();
374
+ const signature = [
375
+ this.actualWidth,
376
+ this.actualHeight,
377
+ this.dpr,
378
+ this.disableScroll ? 1 : 0
379
+ ].join(':');
380
+ if (force || this._webViewInitSignature !== signature) {
381
+ await this._webViewBridge.request('init', {
382
+ width: this.actualWidth,
383
+ height: this.actualHeight,
384
+ dpr: this.dpr,
385
+ disableScroll: this.disableScroll
386
+ });
387
+ this._webViewInitSignature = signature;
388
+ this.applyFont();
389
+ await this.clearCanvas();
390
+ }
391
+
392
+ this.$emit('ready', {
393
+ width: this.actualWidth,
394
+ height: this.actualHeight
395
+ });
396
+ return true;
397
+ },
285
398
  refresh() {
286
399
  return this.initCanvas(true);
287
400
  },
@@ -300,7 +413,7 @@ export default {
300
413
  this.setFillStyle(this.bgColor);
301
414
  this.fill();
302
415
  }
303
- this.draw();
416
+ return this.draw();
304
417
  },
305
418
  callContext(method, ...args) {
306
419
  if (this.ctx && typeof this.ctx[method] === 'function') {
@@ -341,12 +454,28 @@ export default {
341
454
  arc(x, y, radius, startAngle, endAngle, anticlockwise = false) {
342
455
  return this.callContext('arc', x, y, radius, startAngle, endAngle, anticlockwise);
343
456
  },
457
+ arcTo(x1, y1, x2, y2, radius) {
458
+ return this.callContext('arcTo', x1, y1, x2, y2, radius);
459
+ },
344
460
  bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
345
461
  return this.callContext('bezierCurveTo', cp1x, cp1y, cp2x, cp2y, x, y);
346
462
  },
347
463
  quadraticCurveTo(cpx, cpy, x, y) {
348
464
  return this.callContext('quadraticCurveTo', cpx, cpy, x, y);
349
465
  },
466
+ ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise = false) {
467
+ return this.callContext(
468
+ 'ellipse',
469
+ x,
470
+ y,
471
+ radiusX,
472
+ radiusY,
473
+ rotation,
474
+ startAngle,
475
+ endAngle,
476
+ anticlockwise
477
+ );
478
+ },
350
479
  clip() {
351
480
  return this.callContext('clip');
352
481
  },
@@ -365,6 +494,15 @@ export default {
365
494
  scale(x, y) {
366
495
  return this.callContext('scale', x, y);
367
496
  },
497
+ setTransform(a, b, c, d, e, f) {
498
+ return this.callContext('setTransform', a, b, c, d, e, f);
499
+ },
500
+ transform(a, b, c, d, e, f) {
501
+ return this.callContext('transform', a, b, c, d, e, f);
502
+ },
503
+ resetTransform() {
504
+ return this.callContext('resetTransform');
505
+ },
368
506
  setFillStyle(color) {
369
507
  if (!this.ctx) return;
370
508
  if (typeof this.ctx.setFillStyle === 'function') {
@@ -405,6 +543,21 @@ export default {
405
543
  this.ctx.lineJoin = lineJoin;
406
544
  }
407
545
  },
546
+ setMiterLimit(miterLimit) {
547
+ if (!this.ctx) return;
548
+ if (typeof this.ctx.setMiterLimit === 'function') {
549
+ this.ctx.setMiterLimit(miterLimit);
550
+ } else {
551
+ this.ctx.miterLimit = miterLimit;
552
+ }
553
+ },
554
+ setLineDash(segments = []) {
555
+ return this.callContext('setLineDash', segments);
556
+ },
557
+ getLineDash() {
558
+ const result = this.callContext('getLineDash');
559
+ return Array.isArray(result) ? result : [];
560
+ },
408
561
  setTextAlign(align = 'left') {
409
562
  if (!this.ctx) return;
410
563
  if (typeof this.ctx.setTextAlign === 'function') {
@@ -448,6 +601,14 @@ export default {
448
601
  this.ctx.globalAlpha = alpha;
449
602
  }
450
603
  },
604
+ setGlobalCompositeOperation(operation) {
605
+ if (!this.ctx) return;
606
+ if (typeof this.ctx.setGlobalCompositeOperation === 'function') {
607
+ this.ctx.setGlobalCompositeOperation(operation);
608
+ } else {
609
+ this.ctx.globalCompositeOperation = operation;
610
+ }
611
+ },
451
612
  setShadow(offsetX = 0, offsetY = 0, blur = 0, color = 'rgba(0,0,0,0)') {
452
613
  if (!this.ctx) return;
453
614
  if (typeof this.ctx.setShadow === 'function') {
@@ -479,6 +640,12 @@ export default {
479
640
  fillText(text, x, y) {
480
641
  return this.callContext('fillText', String(text), x, y);
481
642
  },
643
+ strokeText(text, x, y, maxWidth) {
644
+ if (maxWidth === undefined) {
645
+ return this.callContext('strokeText', String(text), x, y);
646
+ }
647
+ return this.callContext('strokeText', String(text), x, y, maxWidth);
648
+ },
482
649
  measureText(text) {
483
650
  if (this.ctx && typeof this.ctx.measureText === 'function') {
484
651
  return this.ctx.measureText(String(text));
@@ -487,6 +654,12 @@ export default {
487
654
  width: String(text).length * this.fontSize * 0.6
488
655
  };
489
656
  },
657
+ measureTextAsync(text) {
658
+ if (this.ctx && typeof this.ctx.measureTextAsync === 'function') {
659
+ return this.ctx.measureTextAsync(String(text));
660
+ }
661
+ return Promise.resolve(this.measureText(text));
662
+ },
490
663
  createLinearGradient(x0, y0, x1, y1) {
491
664
  if (this.ctx && typeof this.ctx.createLinearGradient === 'function') {
492
665
  return this.ctx.createLinearGradient(x0, y0, x1, y1);
@@ -499,17 +672,75 @@ export default {
499
672
  }
500
673
  return null;
501
674
  },
675
+ createPattern(image, repetition = 'repeat') {
676
+ if (this.ctx && typeof this.ctx.createPattern === 'function') {
677
+ return this.ctx.createPattern(image, repetition);
678
+ }
679
+ return null;
680
+ },
681
+ async resolveNvueImageSource(src) {
682
+ if (typeof src !== 'string' || src.indexOf('data:image/') === 0) {
683
+ return src;
684
+ }
685
+ if (this._imageDataCache[src]) {
686
+ return this._imageDataCache[src];
687
+ }
688
+
689
+ const task = (async () => {
690
+ const localPath = await new Promise((resolve, reject) => {
691
+ uni.getImageInfo({
692
+ src,
693
+ success: res => resolve(res.path || res.tempFilePath),
694
+ fail: reject
695
+ });
696
+ });
697
+ if (!localPath) {
698
+ throw new Error(`Canvas图片未返回本地路径: ${src}`);
699
+ }
700
+ return this.readNvueFileAsDataURL(localPath);
701
+ })();
702
+ this._imageDataCache[src] = task;
703
+ try {
704
+ const dataUrl = await task;
705
+ this._imageDataCache[src] = dataUrl;
706
+ return dataUrl;
707
+ } catch (error) {
708
+ delete this._imageDataCache[src];
709
+ throw error;
710
+ }
711
+ },
712
+ readNvueFileAsDataURL(path) {
713
+ return new Promise((resolve, reject) => {
714
+ // #ifdef APP-NVUE
715
+ if (typeof plus === 'undefined' || !plus.io) {
716
+ reject(new Error('HTML5+ FileReader不可用'));
717
+ return;
718
+ }
719
+ plus.io.resolveLocalFileSystemURL(path, (entry) => {
720
+ entry.file((file) => {
721
+ const reader = new plus.io.FileReader();
722
+ reader.onloadend = event => resolve(event.target.result);
723
+ reader.onerror = reject;
724
+ reader.readAsDataURL(file);
725
+ }, reject);
726
+ }, reject);
727
+ return;
728
+ // #endif
729
+
730
+ resolve(path);
731
+ });
732
+ },
502
733
  loadImage(src) {
734
+ // #ifdef APP-NVUE
735
+ return this.resolveNvueImageSource(src);
736
+ // #endif
737
+
503
738
  if (this._imageCache[src]) {
504
739
  return Promise.resolve(this._imageCache[src]);
505
740
  }
506
741
  return new Promise((resolve, reject) => {
507
742
  let image = null;
508
743
 
509
- // #ifdef APP-NVUE
510
- image = new GImage();
511
- // #endif
512
-
513
744
  // #ifdef MP
514
745
  const canvas = this.getCanvasElement();
515
746
  if (canvas && typeof canvas.createImage === 'function') {
@@ -539,7 +770,11 @@ export default {
539
770
  if (!this.ctx || typeof this.ctx.drawImage !== 'function') {
540
771
  return false;
541
772
  }
542
- if (typeof source !== 'string' || (typeof this.ctx.setFillStyle === 'function' && !this._isNvue)) {
773
+ if (typeof source !== 'string') {
774
+ this.ctx.drawImage(source, ...args);
775
+ return true;
776
+ }
777
+ if (typeof this.ctx.setFillStyle === 'function' && !this._isNvue) {
543
778
  this.ctx.drawImage(source, ...args);
544
779
  return true;
545
780
  }
@@ -560,14 +795,32 @@ export default {
560
795
  return new Promise((resolve, reject) => {
561
796
  const width = options.width || this.actualWidth;
562
797
  const height = options.height || this.actualHeight;
798
+ const hasDestWidth = options.destWidth !== undefined && options.destWidth !== null;
799
+ const hasDestHeight = options.destHeight !== undefined && options.destHeight !== null;
800
+ let destWidth = hasDestWidth ? options.destWidth : width;
801
+ let destHeight = hasDestHeight ? options.destHeight : height;
802
+
803
+ // MP、H5 和 APP-PLUS 保持逻辑绘制坐标,只提升默认导出像素。
804
+ // #ifdef MP || H5 || APP-PLUS
805
+ if (!hasDestWidth) {
806
+ destWidth = Math.round(width * this.dpr);
807
+ }
808
+ if (!hasDestHeight) {
809
+ destHeight = Math.round(height * this.dpr);
810
+ }
811
+ // #endif
812
+
813
+ const defaultFileType = 'png';
563
814
  const request = {
564
815
  x: options.x || 0,
565
816
  y: options.y || 0,
566
817
  width,
567
818
  height,
568
- destWidth: options.destWidth || width,
569
- destHeight: options.destHeight || height,
570
- fileType: options.fileType || 'png',
819
+ destWidth,
820
+ destHeight,
821
+ fileType: options.fileType === undefined || options.fileType === null
822
+ ? defaultFileType
823
+ : options.fileType,
571
824
  quality: options.quality === undefined ? 1 : options.quality
572
825
  };
573
826
  const success = (res) => {
@@ -630,18 +883,14 @@ export default {
630
883
 
631
884
  // #ifdef APP-NVUE
632
885
  if (this.ctx && typeof this.ctx.toTempFilePath === 'function') {
633
- this.ctx.toTempFilePath(
634
- request.x,
635
- request.y,
636
- request.width,
637
- request.height,
638
- request.destWidth,
639
- request.destHeight,
640
- request.fileType,
641
- request.quality,
886
+ Promise.resolve(this.ctx.toTempFilePath(request)).then(
642
887
  (res) => {
643
888
  success(res);
644
889
  complete(res);
890
+ },
891
+ (error) => {
892
+ fail(error);
893
+ complete(error);
645
894
  }
646
895
  );
647
896
  return;
@@ -667,51 +916,96 @@ export default {
667
916
  fileType,
668
917
  quality,
669
918
  width: this.actualWidth,
670
- height: this.actualHeight,
671
- destWidth: this.actualWidth,
672
- destHeight: this.actualHeight
919
+ height: this.actualHeight
673
920
  });
674
921
  return res.tempFilePath || res.apFilePath;
675
922
  },
676
923
  getImageData(options = {}) {
677
924
  return new Promise((resolve, reject) => {
925
+ const success = (res) => {
926
+ if (typeof options.success === 'function') options.success(res);
927
+ resolve(res);
928
+ };
929
+ const fail = (err) => {
930
+ if (typeof options.fail === 'function') options.fail(err);
931
+ reject(err);
932
+ };
933
+ const complete = (res) => {
934
+ if (typeof options.complete === 'function') options.complete(res);
935
+ };
936
+ // #ifdef APP-NVUE
937
+ if (this.ctx && typeof this.ctx.getImageData === 'function') {
938
+ Promise.resolve(this.ctx.getImageData({
939
+ x: options.x || 0,
940
+ y: options.y || 0,
941
+ width: options.width || this.actualWidth,
942
+ height: options.height || this.actualHeight
943
+ })).then((res) => {
944
+ success(res);
945
+ complete(res);
946
+ }, (error) => {
947
+ fail(error);
948
+ complete(error);
949
+ });
950
+ return;
951
+ }
952
+ // #endif
953
+
678
954
  const request = {
679
955
  canvasId: this.canvasId,
680
956
  x: options.x || 0,
681
957
  y: options.y || 0,
682
958
  width: options.width || this.actualWidth,
683
959
  height: options.height || this.actualHeight,
684
- success: (res) => {
685
- if (typeof options.success === 'function') options.success(res);
686
- resolve(res);
687
- },
688
- fail: (err) => {
689
- if (typeof options.fail === 'function') options.fail(err);
690
- reject(err);
691
- },
692
- complete: options.complete
960
+ success,
961
+ fail,
962
+ complete
693
963
  };
694
964
  uni.canvasGetImageData(request, this);
695
965
  });
696
966
  },
697
967
  putImageData(options = {}) {
698
968
  return new Promise((resolve, reject) => {
969
+ const success = (res) => {
970
+ if (typeof options.success === 'function') options.success(res);
971
+ resolve(res);
972
+ };
973
+ const fail = (err) => {
974
+ if (typeof options.fail === 'function') options.fail(err);
975
+ reject(err);
976
+ };
977
+ const complete = (res) => {
978
+ if (typeof options.complete === 'function') options.complete(res);
979
+ };
980
+ // #ifdef APP-NVUE
981
+ if (this.ctx && typeof this.ctx.putImageData === 'function') {
982
+ Promise.resolve(this.ctx.putImageData({
983
+ x: options.x || 0,
984
+ y: options.y || 0,
985
+ width: options.width || (options.data && options.data.width) || this.actualWidth,
986
+ height: options.height || (options.data && options.data.height) || this.actualHeight,
987
+ data: options.data
988
+ })).then((res) => {
989
+ success(res);
990
+ complete(res);
991
+ }, (error) => {
992
+ fail(error);
993
+ complete(error);
994
+ });
995
+ return;
996
+ }
997
+ // #endif
998
+
699
999
  const request = {
700
1000
  canvasId: this.canvasId,
701
1001
  x: options.x || 0,
702
1002
  y: options.y || 0,
703
- width: options.width || this.actualWidth,
704
- height: options.height || this.actualHeight,
1003
+ width: options.width || (options.data && options.data.width) || this.actualWidth,
1004
+ height: options.height || (options.data && options.data.height) || this.actualHeight,
705
1005
  data: options.data,
706
- success: (res) => {
707
- if (typeof options.success === 'function') options.success(res);
708
- resolve(res);
709
- },
710
- fail: (err) => {
711
- if (typeof options.fail === 'function') options.fail(err);
712
- reject(err);
713
- },
714
- complete: options.complete
1006
+ success,
1007
+ fail,
1008
+ complete
715
1009
  };
716
1010
  uni.canvasPutImageData(request, this);
717
1011
  });
@@ -90,6 +90,11 @@
90
90
  }
91
91
  },
92
92
  mixins: [mpMixin, mixin, props],
93
+ inject: {
94
+ uActionSheet: {
95
+ default: null
96
+ }
97
+ },
93
98
  computed: {
94
99
  titleTextStyle() {
95
100
  return addStyle(this.titleStyle)
@@ -123,6 +128,9 @@
123
128
  this.$emit('click', {
124
129
  name: this.name
125
130
  })
131
+ if (this.stop && typeof this.uActionSheet?.slotClickHandler === 'function') {
132
+ this.uActionSheet.slotClickHandler()
133
+ }
126
134
  // 如果配置了url(此props参数通过mixin引入)参数,跳转页面
127
135
  this.openPage()
128
136
  // 是否阻止事件传播