@wot-ui/ui 1.0.0 → 2.0.0-alpha.3

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 (385) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/attributes.json +1 -0
  4. package/changelog.md +53 -0
  5. package/common/AbortablePromise.ts +28 -0
  6. package/common/canvasHelper.ts +49 -0
  7. package/common/clickoutside.ts +25 -0
  8. package/common/event.ts +8 -0
  9. package/common/formatDate.ts +68 -0
  10. package/common/interceptor.ts +43 -0
  11. package/common/props.ts +53 -0
  12. package/common/util.ts +836 -0
  13. package/components/wd-action-sheet/index.scss +232 -0
  14. package/components/wd-action-sheet/types.ts +155 -0
  15. package/components/wd-action-sheet/wd-action-sheet.vue +176 -0
  16. package/components/wd-avatar/index.scss +150 -0
  17. package/components/wd-avatar/types.ts +98 -0
  18. package/components/wd-avatar/wd-avatar.vue +184 -0
  19. package/components/wd-avatar-group/index.scss +11 -0
  20. package/components/wd-avatar-group/types.ts +61 -0
  21. package/components/wd-avatar-group/wd-avatar-group.vue +115 -0
  22. package/components/wd-backtop/index.scss +67 -0
  23. package/components/wd-backtop/types.ts +66 -0
  24. package/components/wd-backtop/wd-backtop.vue +57 -0
  25. package/components/wd-badge/index.scss +116 -0
  26. package/components/wd-badge/types.ts +94 -0
  27. package/components/wd-badge/wd-badge.vue +78 -0
  28. package/components/wd-button/index.scss +436 -0
  29. package/components/wd-button/types.ts +204 -0
  30. package/components/wd-button/wd-button.vue +210 -0
  31. package/components/wd-calendar/index.scss +97 -0
  32. package/components/wd-calendar/types.ts +221 -0
  33. package/components/wd-calendar/wd-calendar.vue +339 -0
  34. package/components/wd-calendar-view/index.scss +41 -0
  35. package/components/wd-calendar-view/month/index.scss +144 -0
  36. package/components/wd-calendar-view/month/month.vue +389 -0
  37. package/components/wd-calendar-view/month/types.ts +70 -0
  38. package/components/wd-calendar-view/monthPanel/index.scss +84 -0
  39. package/components/wd-calendar-view/monthPanel/month-panel.vue +541 -0
  40. package/components/wd-calendar-view/monthPanel/types.ts +151 -0
  41. package/components/wd-calendar-view/types.ts +166 -0
  42. package/components/wd-calendar-view/utils.ts +318 -0
  43. package/components/wd-calendar-view/wd-calendar-view.vue +117 -0
  44. package/components/wd-calendar-view/year/index.scss +148 -0
  45. package/components/wd-calendar-view/year/types.ts +74 -0
  46. package/components/wd-calendar-view/year/year.vue +206 -0
  47. package/components/wd-calendar-view/yearPanel/index.scss +42 -0
  48. package/components/wd-calendar-view/yearPanel/types.ts +96 -0
  49. package/components/wd-calendar-view/yearPanel/year-panel.vue +249 -0
  50. package/components/wd-card/index.scss +104 -0
  51. package/components/wd-card/types.ts +47 -0
  52. package/components/wd-card/wd-card.vue +38 -0
  53. package/components/wd-cascader/index.scss +154 -0
  54. package/components/wd-cascader/types.ts +191 -0
  55. package/components/wd-cascader/wd-cascader.vue +589 -0
  56. package/components/wd-cell/index.scss +244 -0
  57. package/components/wd-cell/types.ts +205 -0
  58. package/components/wd-cell/wd-cell.vue +172 -0
  59. package/components/wd-cell-group/index.scss +53 -0
  60. package/components/wd-cell-group/types.ts +97 -0
  61. package/components/wd-cell-group/wd-cell-group.vue +48 -0
  62. package/components/wd-checkbox/index.scss +166 -0
  63. package/components/wd-checkbox/types.ts +118 -0
  64. package/components/wd-checkbox/wd-checkbox.vue +216 -0
  65. package/components/wd-checkbox-group/index.scss +5 -0
  66. package/components/wd-checkbox-group/types.ts +93 -0
  67. package/components/wd-checkbox-group/wd-checkbox-group.vue +148 -0
  68. package/components/wd-circle/index.scss +28 -0
  69. package/components/wd-circle/types.ts +54 -0
  70. package/components/wd-circle/wd-circle.vue +306 -0
  71. package/components/wd-col/index.scss +5 -0
  72. package/components/wd-col/types.ts +16 -0
  73. package/components/wd-col/wd-col.vue +83 -0
  74. package/components/wd-collapse/index.scss +71 -0
  75. package/components/wd-collapse/types.ts +68 -0
  76. package/components/wd-collapse/wd-collapse.vue +165 -0
  77. package/components/wd-collapse-item/index.scss +86 -0
  78. package/components/wd-collapse-item/types.ts +62 -0
  79. package/components/wd-collapse-item/wd-collapse-item.vue +184 -0
  80. package/components/wd-config-provider/index.scss +10 -0
  81. package/components/wd-config-provider/types.ts +2063 -0
  82. package/components/wd-config-provider/wd-config-provider.vue +61 -0
  83. package/components/wd-count-down/index.scss +16 -0
  84. package/components/wd-count-down/types.ts +58 -0
  85. package/components/wd-count-down/utils.ts +52 -0
  86. package/components/wd-count-down/wd-count-down.vue +62 -0
  87. package/components/wd-count-to/index.scss +25 -0
  88. package/components/wd-count-to/types.ts +121 -0
  89. package/components/wd-count-to/wd-count-to.vue +126 -0
  90. package/components/wd-curtain/index.scss +96 -0
  91. package/components/wd-curtain/types.ts +82 -0
  92. package/components/wd-curtain/wd-curtain.vue +172 -0
  93. package/components/wd-datetime-picker/index.scss +133 -0
  94. package/components/wd-datetime-picker/types.ts +198 -0
  95. package/components/wd-datetime-picker/wd-datetime-picker.vue +526 -0
  96. package/components/wd-datetime-picker-view/types.ts +171 -0
  97. package/components/wd-datetime-picker-view/util.ts +30 -0
  98. package/components/wd-datetime-picker-view/wd-datetime-picker-view.vue +402 -0
  99. package/components/wd-dialog/index.scss +281 -0
  100. package/components/wd-dialog/index.ts +168 -0
  101. package/components/wd-dialog/types.ts +452 -0
  102. package/components/wd-dialog/wd-dialog.vue +586 -0
  103. package/components/wd-divider/index.scss +122 -0
  104. package/components/wd-divider/types.ts +50 -0
  105. package/components/wd-divider/wd-divider.vue +54 -0
  106. package/components/wd-drop-menu/index.scss +90 -0
  107. package/components/wd-drop-menu/types.ts +38 -0
  108. package/components/wd-drop-menu/wd-drop-menu.vue +168 -0
  109. package/components/wd-drop-menu-item/index.scss +96 -0
  110. package/components/wd-drop-menu-item/types.ts +93 -0
  111. package/components/wd-drop-menu-item/wd-drop-menu-item.vue +205 -0
  112. package/components/wd-empty/index.scss +46 -0
  113. package/components/wd-empty/types.ts +37 -0
  114. package/components/wd-empty/wd-empty.vue +47 -0
  115. package/components/wd-fab/index.scss +124 -0
  116. package/components/wd-fab/types.ts +119 -0
  117. package/components/wd-fab/wd-fab.vue +322 -0
  118. package/components/wd-floating-panel/index.scss +73 -0
  119. package/components/wd-floating-panel/type.ts +32 -0
  120. package/components/wd-floating-panel/wd-floating-panel.vue +142 -0
  121. package/components/wd-form/adapters/zod.ts +56 -0
  122. package/components/wd-form/types.ts +147 -0
  123. package/components/wd-form/wd-form.vue +121 -0
  124. package/components/wd-form-item/index.scss +26 -0
  125. package/components/wd-form-item/types.ts +134 -0
  126. package/components/wd-form-item/wd-form-item.vue +182 -0
  127. package/components/wd-gap/index.scss +9 -0
  128. package/components/wd-gap/types.ts +26 -0
  129. package/components/wd-gap/wd-gap.vue +38 -0
  130. package/components/wd-grid/index.scss +11 -0
  131. package/components/wd-grid/types.ts +97 -0
  132. package/components/wd-grid/wd-grid.vue +48 -0
  133. package/components/wd-grid-item/index.scss +187 -0
  134. package/components/wd-grid-item/types.ts +98 -0
  135. package/components/wd-grid-item/wd-grid-item.vue +295 -0
  136. package/components/wd-icon/index.scss +46 -0
  137. package/components/wd-icon/types.ts +44 -0
  138. package/components/wd-icon/wd-icon.vue +66 -0
  139. package/components/wd-image-preview/index.scss +94 -0
  140. package/components/wd-image-preview/index.ts +95 -0
  141. package/components/wd-image-preview/types.ts +165 -0
  142. package/components/wd-image-preview/wd-image-preview.vue +233 -0
  143. package/components/wd-img/index.scss +82 -0
  144. package/components/wd-img/types.ts +96 -0
  145. package/components/wd-img/wd-img.vue +91 -0
  146. package/components/wd-img-cropper/index.scss +259 -0
  147. package/components/wd-img-cropper/types.ts +101 -0
  148. package/components/wd-img-cropper/wd-img-cropper.vue +653 -0
  149. package/components/wd-index-anchor/index.scss +34 -0
  150. package/components/wd-index-anchor/type.ts +9 -0
  151. package/components/wd-index-anchor/wd-index-anchor.vue +55 -0
  152. package/components/wd-index-bar/index.scss +68 -0
  153. package/components/wd-index-bar/type.ts +23 -0
  154. package/components/wd-index-bar/wd-index-bar.vue +157 -0
  155. package/components/wd-input/index.scss +129 -0
  156. package/components/wd-input/types.ts +165 -0
  157. package/components/wd-input/wd-input.vue +237 -0
  158. package/components/wd-input-number/index.scss +233 -0
  159. package/components/wd-input-number/types.ts +131 -0
  160. package/components/wd-input-number/wd-input-number.vue +473 -0
  161. package/components/wd-keyboard/constants.ts +81 -0
  162. package/components/wd-keyboard/index.scss +104 -0
  163. package/components/wd-keyboard/key/index.scss +103 -0
  164. package/components/wd-keyboard/key/index.vue +84 -0
  165. package/components/wd-keyboard/key/types.ts +44 -0
  166. package/components/wd-keyboard/types.ts +138 -0
  167. package/components/wd-keyboard/wd-keyboard.vue +236 -0
  168. package/components/wd-loading/index.scss +205 -0
  169. package/components/wd-loading/types.ts +61 -0
  170. package/components/wd-loading/wd-loading.vue +70 -0
  171. package/components/wd-loadmore/index.scss +62 -0
  172. package/components/wd-loadmore/types.ts +42 -0
  173. package/components/wd-loadmore/wd-loadmore.vue +68 -0
  174. package/components/wd-navbar/index.scss +96 -0
  175. package/components/wd-navbar/types.ts +74 -0
  176. package/components/wd-navbar/wd-navbar.vue +136 -0
  177. package/components/wd-navbar-capsule/index.scss +70 -0
  178. package/components/wd-navbar-capsule/types.ts +11 -0
  179. package/components/wd-navbar-capsule/wd-navbar-capsule.vue +48 -0
  180. package/components/wd-notice-bar/index.scss +94 -0
  181. package/components/wd-notice-bar/types.ts +97 -0
  182. package/components/wd-notice-bar/wd-notice-bar.vue +270 -0
  183. package/components/wd-notify/index.scss +114 -0
  184. package/components/wd-notify/index.ts +63 -0
  185. package/components/wd-notify/types.ts +130 -0
  186. package/components/wd-notify/wd-notify.vue +162 -0
  187. package/components/wd-overlay/index.scss +14 -0
  188. package/components/wd-overlay/types.ts +42 -0
  189. package/components/wd-overlay/wd-overlay.vue +55 -0
  190. package/components/wd-pagination/index.scss +71 -0
  191. package/components/wd-pagination/types.ts +69 -0
  192. package/components/wd-pagination/wd-pagination.vue +118 -0
  193. package/components/wd-password-input/index.scss +134 -0
  194. package/components/wd-password-input/types.ts +42 -0
  195. package/components/wd-password-input/wd-password-input.vue +51 -0
  196. package/components/wd-picker/index.scss +72 -0
  197. package/components/wd-picker/types.ts +141 -0
  198. package/components/wd-picker/wd-picker.vue +220 -0
  199. package/components/wd-picker-view/index.scss +93 -0
  200. package/components/wd-picker-view/types.ts +145 -0
  201. package/components/wd-picker-view/useSelection.ts +385 -0
  202. package/components/wd-picker-view/wd-picker-view.vue +227 -0
  203. package/components/wd-popover/index.scss +117 -0
  204. package/components/wd-popover/types.ts +106 -0
  205. package/components/wd-popover/wd-popover.vue +212 -0
  206. package/components/wd-popup/index.scss +89 -0
  207. package/components/wd-popup/types.ts +110 -0
  208. package/components/wd-popup/wd-popup.vue +174 -0
  209. package/components/wd-progress/index.scss +155 -0
  210. package/components/wd-progress/types.ts +94 -0
  211. package/components/wd-progress/wd-progress.vue +249 -0
  212. package/components/wd-radio/index.scss +189 -0
  213. package/components/wd-radio/types.ts +64 -0
  214. package/components/wd-radio/wd-radio.vue +164 -0
  215. package/components/wd-radio-group/index.scss +5 -0
  216. package/components/wd-radio-group/types.ts +70 -0
  217. package/components/wd-radio-group/wd-radio-group.vue +53 -0
  218. package/components/wd-rate/index.scss +57 -0
  219. package/components/wd-rate/types.ts +86 -0
  220. package/components/wd-rate/wd-rate.vue +168 -0
  221. package/components/wd-resize/index.scss +31 -0
  222. package/components/wd-resize/types.ts +14 -0
  223. package/components/wd-resize/wd-resize.vue +157 -0
  224. package/components/wd-root-portal/wd-root-portal.vue +77 -0
  225. package/components/wd-row/index.scss +6 -0
  226. package/components/wd-row/types.ts +36 -0
  227. package/components/wd-row/wd-row.vue +88 -0
  228. package/components/wd-search/index.scss +171 -0
  229. package/components/wd-search/types.ts +107 -0
  230. package/components/wd-search/wd-search.vue +198 -0
  231. package/components/wd-segmented/index.scss +155 -0
  232. package/components/wd-segmented/types.ts +81 -0
  233. package/components/wd-segmented/wd-segmented.vue +169 -0
  234. package/components/wd-select-picker/index.scss +72 -0
  235. package/components/wd-select-picker/types.ts +72 -0
  236. package/components/wd-select-picker/wd-select-picker.vue +371 -0
  237. package/components/wd-sidebar/index.scss +25 -0
  238. package/components/wd-sidebar/types.ts +34 -0
  239. package/components/wd-sidebar/wd-sidebar.vue +57 -0
  240. package/components/wd-sidebar-item/index.scss +91 -0
  241. package/components/wd-sidebar-item/types.ts +28 -0
  242. package/components/wd-sidebar-item/wd-sidebar-item.vue +118 -0
  243. package/components/wd-signature/index.scss +42 -0
  244. package/components/wd-signature/types.ts +295 -0
  245. package/components/wd-signature/wd-signature.vue +664 -0
  246. package/components/wd-skeleton/index.scss +112 -0
  247. package/components/wd-skeleton/types.ts +124 -0
  248. package/components/wd-skeleton/wd-skeleton.vue +110 -0
  249. package/components/wd-slide-verify/index.scss +112 -0
  250. package/components/wd-slide-verify/types.ts +98 -0
  251. package/components/wd-slide-verify/wd-slide-verify.vue +222 -0
  252. package/components/wd-slider/index.scss +485 -0
  253. package/components/wd-slider/types.ts +166 -0
  254. package/components/wd-slider/wd-slider.vue +529 -0
  255. package/components/wd-sort-button/index.scss +126 -0
  256. package/components/wd-sort-button/types.ts +68 -0
  257. package/components/wd-sort-button/wd-sort-button.vue +67 -0
  258. package/components/wd-step/index.scss +366 -0
  259. package/components/wd-step/types.ts +43 -0
  260. package/components/wd-step/wd-step.vue +181 -0
  261. package/components/wd-steps/index.scss +7 -0
  262. package/components/wd-steps/types.ts +50 -0
  263. package/components/wd-steps/wd-steps.vue +39 -0
  264. package/components/wd-sticky/index.scss +9 -0
  265. package/components/wd-sticky/types.ts +13 -0
  266. package/components/wd-sticky/wd-sticky.vue +192 -0
  267. package/components/wd-sticky-box/index.scss +6 -0
  268. package/components/wd-sticky-box/types.ts +20 -0
  269. package/components/wd-sticky-box/wd-sticky-box.vue +157 -0
  270. package/components/wd-swipe-action/index.scss +22 -0
  271. package/components/wd-swipe-action/types.ts +87 -0
  272. package/components/wd-swipe-action/wd-swipe-action.vue +320 -0
  273. package/components/wd-swiper/index.scss +69 -0
  274. package/components/wd-swiper/types.ts +275 -0
  275. package/components/wd-swiper/wd-swiper.vue +332 -0
  276. package/components/wd-swiper-nav/index.scss +179 -0
  277. package/components/wd-swiper-nav/types.ts +42 -0
  278. package/components/wd-swiper-nav/wd-swiper-nav.vue +42 -0
  279. package/components/wd-switch/index.scss +177 -0
  280. package/components/wd-switch/types.ts +93 -0
  281. package/components/wd-switch/wd-switch.vue +107 -0
  282. package/components/wd-tab/index.scss +16 -0
  283. package/components/wd-tab/types.ts +45 -0
  284. package/components/wd-tab/wd-tab.vue +99 -0
  285. package/components/wd-tabbar/index.scss +71 -0
  286. package/components/wd-tabbar/types.ts +79 -0
  287. package/components/wd-tabbar/wd-tabbar.vue +109 -0
  288. package/components/wd-tabbar-item/index.scss +50 -0
  289. package/components/wd-tabbar-item/types.ts +45 -0
  290. package/components/wd-tabbar-item/wd-tabbar-item.vue +101 -0
  291. package/components/wd-table/index.scss +128 -0
  292. package/components/wd-table/types.ts +160 -0
  293. package/components/wd-table/wd-table.vue +331 -0
  294. package/components/wd-table-column/index.scss +15 -0
  295. package/components/wd-table-column/types.ts +81 -0
  296. package/components/wd-table-column/wd-table-column.vue +198 -0
  297. package/components/wd-tabs/index.scss +332 -0
  298. package/components/wd-tabs/types.ts +155 -0
  299. package/components/wd-tabs/wd-tabs.vue +508 -0
  300. package/components/wd-tag/index.scss +325 -0
  301. package/components/wd-tag/types.ts +90 -0
  302. package/components/wd-tag/wd-tag.vue +158 -0
  303. package/components/wd-text/index.scss +52 -0
  304. package/components/wd-text/types.ts +107 -0
  305. package/components/wd-text/wd-text.vue +141 -0
  306. package/components/wd-textarea/index.scss +112 -0
  307. package/components/wd-textarea/types.ts +151 -0
  308. package/components/wd-textarea/wd-textarea.vue +212 -0
  309. package/components/wd-toast/index.scss +92 -0
  310. package/components/wd-toast/index.ts +97 -0
  311. package/components/wd-toast/types.ts +190 -0
  312. package/components/wd-toast/wd-toast.vue +158 -0
  313. package/components/wd-tooltip/index.scss +77 -0
  314. package/components/wd-tooltip/types.ts +105 -0
  315. package/components/wd-tooltip/wd-tooltip.vue +169 -0
  316. package/components/wd-tour/index.scss +106 -0
  317. package/components/wd-tour/types.ts +268 -0
  318. package/components/wd-tour/wd-tour.vue +518 -0
  319. package/components/wd-transition/index.scss +67 -0
  320. package/components/wd-transition/types.ts +106 -0
  321. package/components/wd-transition/wd-transition.vue +238 -0
  322. package/components/wd-upload/index.scss +204 -0
  323. package/components/wd-upload/types.ts +390 -0
  324. package/components/wd-upload/wd-upload.vue +565 -0
  325. package/components/wd-video-preview/index.scss +54 -0
  326. package/components/wd-video-preview/index.ts +64 -0
  327. package/components/wd-video-preview/types.ts +66 -0
  328. package/components/wd-video-preview/wd-video-preview.vue +141 -0
  329. package/components/wd-watermark/index.scss +21 -0
  330. package/components/wd-watermark/types.ts +130 -0
  331. package/components/wd-watermark/wd-watermark.vue +718 -0
  332. package/components/wot-ui/wot-ui.vue +5 -0
  333. package/composables/index.ts +12 -0
  334. package/composables/useCell.ts +34 -0
  335. package/composables/useChildren.ts +120 -0
  336. package/composables/useConfigProvider.ts +45 -0
  337. package/composables/useCountDown.ts +138 -0
  338. package/composables/useDeviceInfo.ts +136 -0
  339. package/composables/useLockScroll.ts +37 -0
  340. package/composables/useParent.ts +51 -0
  341. package/composables/usePopover.ts +212 -0
  342. package/composables/useQueue.ts +52 -0
  343. package/composables/useRaf.ts +37 -0
  344. package/composables/useTouch.ts +43 -0
  345. package/composables/useTranslate.ts +12 -0
  346. package/composables/useUpload.ts +366 -0
  347. package/global.d.ts +106 -0
  348. package/index.ts +11 -0
  349. package/locale/index.ts +32 -0
  350. package/locale/lang/ar-SA.ts +150 -0
  351. package/locale/lang/de-DE.ts +150 -0
  352. package/locale/lang/en-US.ts +150 -0
  353. package/locale/lang/es-ES.ts +150 -0
  354. package/locale/lang/fr-FR.ts +150 -0
  355. package/locale/lang/ja-JP.ts +150 -0
  356. package/locale/lang/ko-KR.ts +150 -0
  357. package/locale/lang/pt-PT.ts +150 -0
  358. package/locale/lang/ru-RU.ts +150 -0
  359. package/locale/lang/th-TH.ts +150 -0
  360. package/locale/lang/tr-TR.ts +155 -0
  361. package/locale/lang/ug-CN.ts +154 -0
  362. package/locale/lang/vi-VN.ts +89 -0
  363. package/locale/lang/zh-CN.ts +154 -0
  364. package/locale/lang/zh-HK.ts +78 -0
  365. package/locale/lang/zh-TW.ts +78 -0
  366. package/package.json +1 -11
  367. package/styles/iconfont/iconfont.scss +1243 -0
  368. package/styles/mixin/_config.scss +7 -0
  369. package/styles/mixin/_function.scss +44 -0
  370. package/styles/mixin/_mixin.scss +473 -0
  371. package/styles/theme/base/color.scss +210 -0
  372. package/styles/theme/base/font.scss +13 -0
  373. package/styles/theme/base/index.scss +8 -0
  374. package/styles/theme/base/insets.scss +32 -0
  375. package/styles/theme/base/number.scss +36 -0
  376. package/styles/theme/base/opacity.scss +9 -0
  377. package/styles/theme/base/radius.scss +13 -0
  378. package/styles/theme/base/stroke.scss +9 -0
  379. package/styles/theme/base/typography.scss +44 -0
  380. package/styles/theme/dark.scss +101 -0
  381. package/styles/theme/index.scss +16 -0
  382. package/styles/theme/light.scss +101 -0
  383. package/styles/variable.scss +472 -0
  384. package/tags.json +1 -0
  385. package/web-types.json +1 -0
@@ -0,0 +1,718 @@
1
+ <template>
2
+ <view :class="rootClass" :style="rootStyle">
3
+ <canvas
4
+ v-if="!canvasOffScreenable && showCanvas"
5
+ type="2d"
6
+ :style="{ height: canvasHeight + 'px', width: canvasWidth + 'px', visibility: 'hidden' }"
7
+ :canvas-id="canvasId"
8
+ :id="canvasId"
9
+ />
10
+ </view>
11
+ </template>
12
+
13
+ <script lang="ts">
14
+ export default {
15
+ name: 'wd-watermark',
16
+ options: {
17
+ addGlobalClass: true,
18
+ // #ifndef MP-TOUTIAO
19
+ virtualHost: true,
20
+ // #endif
21
+ styleIsolation: 'shared'
22
+ }
23
+ }
24
+ </script>
25
+
26
+ <script lang="ts" setup>
27
+ import { computed, onMounted, ref, watch, nextTick, type CSSProperties } from 'vue'
28
+ import { addUnit, buildUrlWithParams, getSystemInfo, isBase64Image, isDef, objToStyle, uuid } from '../../common/util'
29
+ import { watermarkProps, type WatermarkFontStyle, type WatermarkLayout } from './types'
30
+
31
+ const props = defineProps(watermarkProps)
32
+
33
+ watch(
34
+ () => props,
35
+ () => {
36
+ doReset()
37
+ },
38
+ { deep: true }
39
+ )
40
+
41
+ const canvasId = ref<string>(`water${uuid()}`) // canvas 组件的唯一标识符
42
+ const waterMarkUrl = ref<string>('') // canvas生成base64水印
43
+ const canvasOffScreenable = ref<boolean>(uni.canIUse('createOffscreenCanvas') && Boolean(uni.createOffscreenCanvas)) // 是否可以使用离屏canvas
44
+ const pixelRatio = ref<number>(getSystemInfo().pixelRatio) // 像素比
45
+ const canvasHeight = ref<number>((props.height + props.gutterY) * pixelRatio.value) // canvas画布高度
46
+ const canvasWidth = ref<number>((props.width + props.gutterX) * pixelRatio.value) // canvas画布宽度
47
+ const showCanvas = ref<boolean>(true) // 是否展示canvas
48
+
49
+ /**
50
+ * 水印css类
51
+ */
52
+ const rootClass = computed(() => {
53
+ let classess: string = 'wd-watermark'
54
+ if (props.fullScreen) {
55
+ classess = `${classess} is-fullscreen`
56
+ }
57
+ return `${classess} ${props.customClass}`
58
+ })
59
+
60
+ /**
61
+ * 水印样式
62
+ */
63
+ const rootStyle = computed(() => {
64
+ let width = props.width + props.gutterX
65
+ if (props.layout === 'staggered') {
66
+ width *= 2
67
+ }
68
+ const style: CSSProperties = {
69
+ backgroundSize: addUnit(width),
70
+ zIndex: props.zIndex
71
+ }
72
+ if (isDef(props.opacity)) {
73
+ style['opacity'] = props.opacity
74
+ }
75
+ if (waterMarkUrl.value) {
76
+ style['backgroundImage'] = `url('${waterMarkUrl.value}')`
77
+ }
78
+ return `${objToStyle(style)}${props.customStyle}`
79
+ })
80
+
81
+ onMounted(() => {
82
+ doInit()
83
+ })
84
+
85
+ /**
86
+ * 重置画布内容并重新初始化
87
+ * @returns {void}
88
+ */
89
+ function doReset() {
90
+ showCanvas.value = true
91
+ const cols = props.layout === 'staggered' ? 2 : 1
92
+ const rows = props.layout === 'staggered' ? 2 : 1
93
+ canvasHeight.value = (props.height + props.gutterY) * pixelRatio.value * rows
94
+ canvasWidth.value = (props.width + props.gutterX) * pixelRatio.value * cols
95
+ nextTick(() => {
96
+ doInit()
97
+ })
98
+ }
99
+
100
+ /**
101
+ * 初始化水印配置并调用创建水印的方法
102
+ * @returns {void}
103
+ */
104
+ function doInit() {
105
+ // #ifdef H5
106
+ // h5使用document.createElement创建canvas,不用展示canvas标签
107
+ showCanvas.value = false
108
+ // #endif
109
+ const { width, height, color, size, fontStyle, fontWeight, fontFamily, content, rotate, gutterX, gutterY, image, imageHeight, imageWidth, layout } =
110
+ props
111
+
112
+ // 创建水印
113
+ createWaterMark(
114
+ width,
115
+ height,
116
+ color,
117
+ size,
118
+ fontStyle,
119
+ fontWeight,
120
+ fontFamily,
121
+ content,
122
+ rotate,
123
+ gutterX,
124
+ gutterY,
125
+ image,
126
+ imageHeight,
127
+ imageWidth,
128
+ layout
129
+ )
130
+ }
131
+
132
+ /**
133
+ * 创建水印图片
134
+ * @param {number} width canvas宽度
135
+ * @param {number} height canvas高度
136
+ * @param {string} color canvas字体颜色
137
+ * @param {number} size canvas字体大小
138
+ * @param {WatermarkFontStyle} fontStyle canvas字体样式
139
+ * @param {number | string} fontWeight canvas字体字重
140
+ * @param {string} fontFamily canvas字体系列
141
+ * @param {string} content canvas内容
142
+ * @param {number} rotate 倾斜角度
143
+ * @param {number} gutterX X轴间距
144
+ * @param {number} gutterY Y轴间距
145
+ * @param {string} image canvas图片
146
+ * @param {number} imageHeight canvas图片高度
147
+ * @param {number} imageWidth canvas图片宽度
148
+ * @param {WatermarkLayout} layout 布局模式
149
+ * @returns {Promise<void>}
150
+ */
151
+ async function createWaterMark(
152
+ width: number,
153
+ height: number,
154
+ color: string,
155
+ size: number,
156
+ fontStyle: WatermarkFontStyle,
157
+ fontWeight: number | string,
158
+ fontFamily: string,
159
+ content: string,
160
+ rotate: number,
161
+ gutterX: number,
162
+ gutterY: number,
163
+ image: string,
164
+ imageHeight: number,
165
+ imageWidth: number,
166
+ layout: WatermarkLayout
167
+ ) {
168
+ const cols = layout === 'staggered' ? 2 : 1
169
+ const rows = layout === 'staggered' ? 2 : 1
170
+ const canvasHeight = (height + gutterY) * pixelRatio.value * rows
171
+ const canvasWidth = (width + gutterX) * pixelRatio.value * cols
172
+ const contentWidth = width * pixelRatio.value
173
+ const contentHeight = height * pixelRatio.value
174
+ const fontSize = size * pixelRatio.value
175
+
176
+ // #ifndef H5
177
+ if (canvasOffScreenable.value) {
178
+ await createOffscreenCanvas(
179
+ canvasHeight,
180
+ canvasWidth,
181
+ contentWidth,
182
+ contentHeight,
183
+ rotate,
184
+ fontSize,
185
+ fontFamily,
186
+ fontStyle,
187
+ fontWeight,
188
+ color,
189
+ content,
190
+ image,
191
+ imageHeight,
192
+ imageWidth,
193
+ layout
194
+ )
195
+ } else {
196
+ await createCanvas(
197
+ canvasHeight,
198
+ canvasWidth,
199
+ contentWidth,
200
+ contentHeight,
201
+ rotate,
202
+ fontSize,
203
+ color,
204
+ content,
205
+ image,
206
+ imageHeight,
207
+ imageWidth,
208
+ layout
209
+ )
210
+ }
211
+ // #endif
212
+ // #ifdef H5
213
+ await createH5Canvas(
214
+ canvasHeight,
215
+ canvasWidth,
216
+ contentWidth,
217
+ contentHeight,
218
+ rotate,
219
+ fontSize,
220
+ fontFamily,
221
+ fontStyle,
222
+ fontWeight,
223
+ color,
224
+ content,
225
+ image,
226
+ imageHeight,
227
+ imageWidth,
228
+ layout
229
+ )
230
+ // #endif
231
+ }
232
+
233
+ /**
234
+ * 创建离屏canvas
235
+ * @param {number} canvasHeight canvas高度
236
+ * @param {number} canvasWidth canvas宽度
237
+ * @param {number} contentWidth 内容宽度
238
+ * @param {number} contentHeight 内容高度
239
+ * @param {number} rotate 内容倾斜角度
240
+ * @param {number} fontSize 字体大小
241
+ * @param {string} fontFamily 字体系列
242
+ * @param {string} fontStyle 字体样式
243
+ * @param {string | number} fontWeight 字体字重
244
+ * @param {string} color 字体颜色
245
+ * @param {string} content 内容
246
+ * @param {string} image canvas图片
247
+ * @param {number} imageHeight canvas图片高度
248
+ * @param {number} imageWidth canvas图片宽度
249
+ * @param {string} layout 布局模式
250
+ * @returns {Promise<void>}
251
+ */
252
+ async function createOffscreenCanvas(
253
+ canvasHeight: number,
254
+ canvasWidth: number,
255
+ contentWidth: number,
256
+ contentHeight: number,
257
+ rotate: number,
258
+ fontSize: number,
259
+ fontFamily: string,
260
+ fontStyle: string,
261
+ fontWeight: string | number,
262
+ color: string,
263
+ content: string,
264
+ image: string,
265
+ imageHeight: number,
266
+ imageWidth: number,
267
+ layout: string
268
+ ) {
269
+ // 创建离屏canvas
270
+ const canvas: any = uni.createOffscreenCanvas({ height: canvasHeight, width: canvasWidth, type: '2d' })
271
+ const ctx: any = canvas.getContext('2d')
272
+ if (ctx) {
273
+ if (image) {
274
+ const img = canvas.createImage() as HTMLImageElement
275
+ drawImageOffScreen(ctx, img, image, imageHeight, imageWidth, rotate, contentWidth, contentHeight, canvas, layout)
276
+ } else {
277
+ await drawTextOffScreen(ctx, content, contentWidth, contentHeight, rotate, fontSize, fontFamily, fontStyle, fontWeight, color, canvas, layout)
278
+ }
279
+ } else {
280
+ console.error('无法获取canvas上下文,请确认当前环境是否支持canvas')
281
+ }
282
+ }
283
+
284
+ /**
285
+ * 非H5创建canvas
286
+ * 不支持创建离屏canvas时调用
287
+ * @param {number} canvasHeight canvas高度
288
+ * @param {number} canvasWidth canvas宽度
289
+ * @param {number} contentWidth 内容宽度
290
+ * @param {number} contentHeight 内容高度
291
+ * @param {number} rotate 内容倾斜角度
292
+ * @param {number} fontSize 字体大小
293
+ * @param {string} color 字体颜色
294
+ * @param {string} content 内容
295
+ * @param {string} image canvas图片
296
+ * @param {number} imageHeight canvas图片高度
297
+ * @param {number} imageWidth canvas图片宽度
298
+ * @param {string} layout 布局模式
299
+ * @returns {Promise<void>}
300
+ */
301
+ async function createCanvas(
302
+ canvasHeight: number,
303
+ canvasWidth: number,
304
+ contentWidth: number,
305
+ contentHeight: number,
306
+ rotate: number,
307
+ fontSize: number,
308
+ color: string,
309
+ content: string,
310
+ image: string,
311
+ imageHeight: number,
312
+ imageWidth: number,
313
+ layout: string
314
+ ) {
315
+ const ctx = uni.createCanvasContext(canvasId.value)
316
+
317
+ if (ctx) {
318
+ if (image) {
319
+ drawImageOnScreen(ctx, image, imageHeight, imageWidth, rotate, contentWidth, contentHeight, layout, canvasWidth, canvasHeight)
320
+ } else {
321
+ await drawTextOnScreen(ctx, content, contentWidth, contentHeight, rotate, fontSize, color, layout, canvasWidth, canvasHeight)
322
+ }
323
+ } else {
324
+ console.error('无法获取canvas上下文,请确认当前环境是否支持canvas')
325
+ }
326
+ }
327
+
328
+ /**
329
+ * h5创建canvas
330
+ * @param {number} canvasHeight canvas高度
331
+ * @param {number} canvasWidth canvas宽度
332
+ * @param {number} contentWidth 水印内容宽度
333
+ * @param {number} contentHeight 水印内容高度
334
+ * @param {number} rotate 水印内容倾斜角度
335
+ * @param {number} fontSize 水印字体大小
336
+ * @param {string} fontFamily 水印字体系列
337
+ * @param {string} fontStyle 水印字体样式
338
+ * @param {string | number} fontWeight 水印字体字重
339
+ * @param {string} color 水印字体颜色
340
+ * @param {string} content 水印内容
341
+ * @param {string} image canvas图片
342
+ * @param {number} imageHeight canvas图片高度
343
+ * @param {number} imageWidth canvas图片宽度
344
+ * @param {string} layout 布局模式
345
+ * @returns {Promise<void>}
346
+ */
347
+ async function createH5Canvas(
348
+ canvasHeight: number,
349
+ canvasWidth: number,
350
+ contentWidth: number,
351
+ contentHeight: number,
352
+ rotate: number,
353
+ fontSize: number,
354
+ fontFamily: string,
355
+ fontStyle: string,
356
+ fontWeight: string | number,
357
+ color: string,
358
+ content: string,
359
+ image: string,
360
+ imageHeight: number,
361
+ imageWidth: number,
362
+ layout: string
363
+ ) {
364
+ const canvas = document.createElement('canvas')
365
+ const ctx = canvas.getContext('2d')
366
+ canvas.setAttribute('width', `${canvasWidth}px`)
367
+ canvas.setAttribute('height', `${canvasHeight}px`)
368
+ if (ctx) {
369
+ if (image) {
370
+ const img = new Image()
371
+ drawImageOffScreen(ctx, img, image, imageHeight, imageWidth, rotate, contentWidth, contentHeight, canvas, layout)
372
+ } else {
373
+ await drawTextOffScreen(ctx, content, contentWidth, contentHeight, rotate, fontSize, fontFamily, fontStyle, fontWeight, color, canvas, layout)
374
+ }
375
+ } else {
376
+ console.error('无法获取canvas上下文,请确认当前环境是否支持canvas')
377
+ }
378
+ }
379
+
380
+ /**
381
+ * 获取文本宽度(兼容 HarmonyOS Next 异步及钉钉小程序排除)
382
+ * @param {any} ctx Canvas 上下文
383
+ * @param {string} text 需要测量的文本
384
+ * @returns {Promise<number>} 文本宽度
385
+ */
386
+ function getTextWidth(ctx: any, text: string): Promise<number> {
387
+ return new Promise((resolve) => {
388
+ // #ifdef MP-DINGTALK
389
+ resolve(0)
390
+ // #endif
391
+
392
+ // #ifndef MP-DINGTALK
393
+ const metrics = ctx.measureText(text)
394
+ if (metrics && typeof metrics.width === 'number') {
395
+ resolve(metrics.width)
396
+ } else {
397
+ resolve(0)
398
+ }
399
+ // #endif
400
+ })
401
+ }
402
+
403
+ /**
404
+ * 计算文本换行
405
+ * @param {any} ctx canvas上下文
406
+ * @param {string} text 需要处理换行的文本
407
+ * @param {number} maxWidth 最大文本宽度
408
+ * @returns {Promise<string[]>} 分行后的文本数组
409
+ */
410
+ async function getWrappedLines(ctx: any, text: string, maxWidth: number): Promise<string[]> {
411
+ const lines: string[] = []
412
+
413
+ // #ifdef MP-DINGTALK
414
+ lines.push(text)
415
+ // #endif
416
+
417
+ // #ifndef MP-DINGTALK
418
+ let currentLine = ''
419
+
420
+ for (let i = 0; i < text.length; i++) {
421
+ const char = text[i]
422
+ const testLine = currentLine + char
423
+ const width = await getTextWidth(ctx, testLine)
424
+
425
+ if (width > maxWidth && i > 0) {
426
+ lines.push(currentLine)
427
+ currentLine = char
428
+ } else {
429
+ currentLine = testLine
430
+ }
431
+ }
432
+ lines.push(currentLine)
433
+ // #endif
434
+
435
+ return lines
436
+ }
437
+
438
+ /**
439
+ * 绘制离屏文字canvas
440
+ * @param {CanvasRenderingContext2D} ctx canvas上下文
441
+ * @param {string} content 水印内容
442
+ * @param {number} contentWidth 水印宽度
443
+ * @param {number} contentHeight 水印高度
444
+ * @param {number} rotate 水印内容倾斜角度
445
+ * @param {number} fontSize 水印字体大小
446
+ * @param {string} fontFamily 水印字体系列
447
+ * @param {string} fontStyle 水印字体样式
448
+ * @param {string | number} fontWeight 水印字体字重
449
+ * @param {string} color 水印字体颜色
450
+ * @param {HTMLCanvasElement} canvas canvas实例
451
+ * @param {string} layout 布局模式
452
+ * @returns {Promise<void>}
453
+ */
454
+ async function drawTextOffScreen(
455
+ ctx: CanvasRenderingContext2D,
456
+ content: string,
457
+ contentWidth: number,
458
+ contentHeight: number,
459
+ rotate: number,
460
+ fontSize: number,
461
+ fontFamily: string,
462
+ fontStyle: string,
463
+ fontWeight: string | number,
464
+ color: string,
465
+ canvas: HTMLCanvasElement,
466
+ layout: string
467
+ ) {
468
+ ctx.font = `${fontStyle} normal ${fontWeight} ${fontSize}px/${contentHeight}px ${fontFamily}`
469
+ const lines = await getWrappedLines(ctx, content, contentWidth)
470
+ const lineHeight = fontSize * 1.2
471
+ const totalHeight = lines.length * lineHeight
472
+ const startY = -totalHeight / 2 + lineHeight / 2
473
+
474
+ const draws = layout === 'staggered' ? 2 : 1
475
+ const cols = layout === 'staggered' ? 2 : 1
476
+ const rows = layout === 'staggered' ? 2 : 1
477
+ const canvasWidth = canvas.width
478
+ const canvasHeight = canvas.height
479
+ const itemWidth = canvasWidth / cols
480
+ const itemHeight = canvasHeight / rows
481
+
482
+ for (let i = 0; i < draws; i++) {
483
+ const offsetX = i === 1 ? itemWidth : 0
484
+ const offsetY = i === 1 ? itemHeight : 0
485
+ ctx.save()
486
+ ctx.textBaseline = 'middle'
487
+ ctx.textAlign = 'center'
488
+ ctx.translate(offsetX + contentWidth / 2, offsetY + contentHeight / 2)
489
+ ctx.rotate((Math.PI / 180) * rotate)
490
+ ctx.font = `${fontStyle} normal ${fontWeight} ${fontSize}px/${contentHeight}px ${fontFamily}`
491
+ ctx.fillStyle = color
492
+
493
+ lines.forEach((line, index) => {
494
+ ctx.fillText(line, 0, startY + index * lineHeight)
495
+ })
496
+ ctx.restore()
497
+ }
498
+
499
+ waterMarkUrl.value = canvas.toDataURL()
500
+ }
501
+
502
+ /**
503
+ * 绘制在屏文字canvas
504
+ * @param {UniApp.CanvasContext} ctx canvas上下文
505
+ * @param {string} content 水印内容
506
+ * @param {number} contentWidth 水印宽度
507
+ * @param {number} contentHeight 水印高度
508
+ * @param {number} rotate 水印内容倾斜角度
509
+ * @param {number} fontSize 水印字体大小
510
+ * @param {string} color 水印字体颜色
511
+ * @param {string} layout 布局模式
512
+ * @param {number} canvasWidth canvas宽度
513
+ * @param {number} canvasHeight canvas高度
514
+ * @returns {Promise<void>}
515
+ */
516
+ async function drawTextOnScreen(
517
+ ctx: UniApp.CanvasContext,
518
+ content: string,
519
+ contentWidth: number,
520
+ contentHeight: number,
521
+ rotate: number,
522
+ fontSize: number,
523
+ color: string,
524
+ layout: string,
525
+ canvasWidth: number,
526
+ canvasHeight: number
527
+ ) {
528
+ ctx.setFontSize(fontSize)
529
+ const lines = await getWrappedLines(ctx, content, contentWidth)
530
+ const lineHeight = fontSize * 1.2
531
+ const totalHeight = lines.length * lineHeight
532
+ const startY = -totalHeight / 2 + lineHeight / 2
533
+
534
+ const draws = layout === 'staggered' ? 2 : 1
535
+ const cols = layout === 'staggered' ? 2 : 1
536
+ const rows = layout === 'staggered' ? 2 : 1
537
+ const itemWidth = canvasWidth / cols
538
+ const itemHeight = canvasHeight / rows
539
+
540
+ for (let i = 0; i < draws; i++) {
541
+ const offsetX = i === 1 ? itemWidth : 0
542
+ const offsetY = i === 1 ? itemHeight : 0
543
+
544
+ ctx.save()
545
+ ctx.setTextBaseline('middle')
546
+ ctx.setTextAlign('center')
547
+ ctx.translate(offsetX + contentWidth / 2, offsetY + contentHeight / 2)
548
+ ctx.rotate((Math.PI / 180) * rotate)
549
+ ctx.setFillStyle(color)
550
+ ctx.setFontSize(fontSize)
551
+
552
+ lines.forEach((line, index) => {
553
+ ctx.fillText(line, 0, startY + index * lineHeight)
554
+ })
555
+ ctx.restore()
556
+ }
557
+
558
+ ctx.draw()
559
+
560
+ // #ifdef MP-DINGTALK
561
+ // 钉钉小程序的canvasToTempFilePath接口与其他平台不一样
562
+ ;(ctx as any).toTempFilePath({
563
+ success(res: any) {
564
+ showCanvas.value = false
565
+ waterMarkUrl.value = res.filePath
566
+ }
567
+ })
568
+ // #endif
569
+ // #ifndef MP-DINGTALK
570
+ uni.canvasToTempFilePath({
571
+ canvasId: canvasId.value,
572
+ success: (res) => {
573
+ showCanvas.value = false
574
+ waterMarkUrl.value = res.tempFilePath
575
+ }
576
+ })
577
+ // #endif
578
+ }
579
+
580
+ /**
581
+ * 绘制离屏图片canvas
582
+ * @param {CanvasRenderingContext2D} ctx canvas上下文
583
+ * @param {HTMLImageElement} img 水印图片对象
584
+ * @param {string} image 水印图片地址
585
+ * @param {number} imageHeight 水印图片高度
586
+ * @param {number} imageWidth 水印图片宽度
587
+ * @param {number} rotate 水印内容倾斜角度
588
+ * @param {number} contentWidth 水印宽度
589
+ * @param {number} contentHeight 水印高度
590
+ * @param {HTMLCanvasElement} canvas canvas实例
591
+ * @param {string} layout 布局模式
592
+ * @returns {void}
593
+ */
594
+ function drawImageOffScreen(
595
+ ctx: CanvasRenderingContext2D,
596
+ img: HTMLImageElement,
597
+ image: string,
598
+ imageHeight: number,
599
+ imageWidth: number,
600
+ rotate: number,
601
+ contentWidth: number,
602
+ contentHeight: number,
603
+ canvas: HTMLCanvasElement,
604
+ layout: string
605
+ ) {
606
+ img.crossOrigin = 'anonymous'
607
+ img.referrerPolicy = 'no-referrer'
608
+
609
+ if (isBase64Image(image)) {
610
+ img.src = image
611
+ } else {
612
+ img.src = buildUrlWithParams(image, {
613
+ timestamp: `${new Date().getTime()}`
614
+ })
615
+ }
616
+ img.onload = () => {
617
+ const draws = layout === 'staggered' ? 2 : 1
618
+ const cols = layout === 'staggered' ? 2 : 1
619
+ const rows = layout === 'staggered' ? 2 : 1
620
+ const canvasWidth = canvas.width
621
+ const canvasHeight = canvas.height
622
+ const itemWidth = canvasWidth / cols
623
+ const itemHeight = canvasHeight / rows
624
+
625
+ for (let i = 0; i < draws; i++) {
626
+ const offsetX = i === 1 ? itemWidth : 0
627
+ const offsetY = i === 1 ? itemHeight : 0
628
+ ctx.save()
629
+ ctx.translate(offsetX + contentWidth / 2, offsetY + contentHeight / 2)
630
+ ctx.rotate((Math.PI / 180) * Number(rotate))
631
+ ctx.drawImage(
632
+ img,
633
+ (-imageWidth * pixelRatio.value) / 2,
634
+ (-imageHeight * pixelRatio.value) / 2,
635
+ imageWidth * pixelRatio.value,
636
+ imageHeight * pixelRatio.value
637
+ )
638
+ ctx.restore()
639
+ }
640
+ waterMarkUrl.value = canvas.toDataURL()
641
+ }
642
+ }
643
+
644
+ /**
645
+ * 绘制在屏图片canvas
646
+ * @param {UniApp.CanvasContext} ctx canvas上下文
647
+ * @param {string} image 水印图片地址
648
+ * @param {number} imageHeight 水印图片高度
649
+ * @param {number} imageWidth 水印图片宽度
650
+ * @param {number} rotate 水印内容倾斜角度
651
+ * @param {number} contentWidth 水印宽度
652
+ * @param {number} contentHeight 水印高度
653
+ * @param {string} layout 布局模式
654
+ * @param {number} canvasWidth canvas宽度
655
+ * @param {number} canvasHeight canvas高度
656
+ * @returns {void}
657
+ */
658
+ function drawImageOnScreen(
659
+ ctx: UniApp.CanvasContext,
660
+ image: string,
661
+ imageHeight: number,
662
+ imageWidth: number,
663
+ rotate: number,
664
+ contentWidth: number,
665
+ contentHeight: number,
666
+ layout: string,
667
+ canvasWidth: number,
668
+ canvasHeight: number
669
+ ) {
670
+ const draws = layout === 'staggered' ? 2 : 1
671
+ const cols = layout === 'staggered' ? 2 : 1
672
+ const rows = layout === 'staggered' ? 2 : 1
673
+ const itemWidth = canvasWidth / cols
674
+ const itemHeight = canvasHeight / rows
675
+
676
+ for (let i = 0; i < draws; i++) {
677
+ const offsetX = i === 1 ? itemWidth : 0
678
+ const offsetY = i === 1 ? itemHeight : 0
679
+ ctx.save()
680
+ ctx.translate(offsetX + contentWidth / 2, offsetY + contentHeight / 2)
681
+ ctx.rotate((Math.PI / 180) * Number(rotate))
682
+
683
+ ctx.drawImage(
684
+ image,
685
+ (-imageWidth * pixelRatio.value) / 2,
686
+ (-imageHeight * pixelRatio.value) / 2,
687
+ imageWidth * pixelRatio.value,
688
+ imageHeight * pixelRatio.value
689
+ )
690
+ ctx.restore()
691
+ }
692
+
693
+ ctx.draw(false, () => {
694
+ // #ifdef MP-DINGTALK
695
+ // 钉钉小程序的canvasToTempFilePath接口与其他平台不一样
696
+ ;(ctx as any).toTempFilePath({
697
+ success(res: any) {
698
+ showCanvas.value = false
699
+ waterMarkUrl.value = res.filePath
700
+ }
701
+ })
702
+ // #endif
703
+ // #ifndef MP-DINGTALK
704
+ uni.canvasToTempFilePath({
705
+ canvasId: canvasId.value,
706
+ success: (res) => {
707
+ showCanvas.value = false
708
+ waterMarkUrl.value = res.tempFilePath
709
+ }
710
+ })
711
+ // #endif
712
+ })
713
+ }
714
+ </script>
715
+
716
+ <style lang="scss">
717
+ @use './index.scss';
718
+ </style>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <view></view>
3
+ </template>
4
+ <script></script>
5
+ <style lang="scss" scoped></style>