@tplc/wot 0.0.1

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 (328) hide show
  1. package/components/common/AbortablePromise.ts +36 -0
  2. package/components/common/abstracts/_config.scss +7 -0
  3. package/components/common/abstracts/_function.scss +76 -0
  4. package/components/common/abstracts/_mixin.scss +339 -0
  5. package/components/common/abstracts/variable.scss +1346 -0
  6. package/components/common/base64.ts +30 -0
  7. package/components/common/canvasHelper.ts +49 -0
  8. package/components/common/clickoutside.ts +34 -0
  9. package/components/common/dayjs.ts +157 -0
  10. package/components/common/event.ts +8 -0
  11. package/components/common/props.ts +51 -0
  12. package/components/common/util.ts +751 -0
  13. package/components/composables/useCell.ts +13 -0
  14. package/components/composables/useChildren.ts +122 -0
  15. package/components/composables/useCountDown.ts +138 -0
  16. package/components/composables/useLockScroll.ts +39 -0
  17. package/components/composables/useParent.ts +41 -0
  18. package/components/composables/usePopover.ts +193 -0
  19. package/components/composables/useQueue.ts +52 -0
  20. package/components/composables/useRaf.ts +37 -0
  21. package/components/composables/useTouch.ts +44 -0
  22. package/components/composables/useTranslate.ts +22 -0
  23. package/components/wd-action-sheet/index.scss +204 -0
  24. package/components/wd-action-sheet/types.ts +128 -0
  25. package/components/wd-action-sheet/wd-action-sheet.vue +174 -0
  26. package/components/wd-backtop/index.scss +25 -0
  27. package/components/wd-backtop/types.ts +37 -0
  28. package/components/wd-backtop/wd-backtop.vue +48 -0
  29. package/components/wd-badge/index.scss +59 -0
  30. package/components/wd-badge/types.ts +53 -0
  31. package/components/wd-badge/wd-badge.vue +69 -0
  32. package/components/wd-button/index.scss +340 -0
  33. package/components/wd-button/types.ts +112 -0
  34. package/components/wd-button/wd-button.vue +176 -0
  35. package/components/wd-calendar/index.scss +244 -0
  36. package/components/wd-calendar/types.ts +235 -0
  37. package/components/wd-calendar/wd-calendar.vue +456 -0
  38. package/components/wd-calendar-view/index.scss +9 -0
  39. package/components/wd-calendar-view/month/index.scss +151 -0
  40. package/components/wd-calendar-view/month/month.vue +391 -0
  41. package/components/wd-calendar-view/month/types.ts +19 -0
  42. package/components/wd-calendar-view/monthPanel/index.scss +89 -0
  43. package/components/wd-calendar-view/monthPanel/month-panel.vue +388 -0
  44. package/components/wd-calendar-view/monthPanel/types.ts +48 -0
  45. package/components/wd-calendar-view/types.ts +134 -0
  46. package/components/wd-calendar-view/utils.ts +451 -0
  47. package/components/wd-calendar-view/wd-calendar-view.vue +111 -0
  48. package/components/wd-calendar-view/year/index.scss +148 -0
  49. package/components/wd-calendar-view/year/types.ts +19 -0
  50. package/components/wd-calendar-view/year/year.vue +220 -0
  51. package/components/wd-calendar-view/yearPanel/index.scss +24 -0
  52. package/components/wd-calendar-view/yearPanel/types.ts +38 -0
  53. package/components/wd-calendar-view/yearPanel/year-panel.vue +140 -0
  54. package/components/wd-card/index.scss +70 -0
  55. package/components/wd-card/types.ts +30 -0
  56. package/components/wd-card/wd-card.vue +40 -0
  57. package/components/wd-cell/index.scss +189 -0
  58. package/components/wd-cell/types.ts +96 -0
  59. package/components/wd-cell/wd-cell.vue +135 -0
  60. package/components/wd-cell-group/index.scss +55 -0
  61. package/components/wd-cell-group/types.ts +41 -0
  62. package/components/wd-cell-group/wd-cell-group.vue +45 -0
  63. package/components/wd-checkbox/index.scss +285 -0
  64. package/components/wd-checkbox/types.ts +68 -0
  65. package/components/wd-checkbox/wd-checkbox.vue +185 -0
  66. package/components/wd-checkbox-group/index.scss +20 -0
  67. package/components/wd-checkbox-group/types.ts +59 -0
  68. package/components/wd-checkbox-group/wd-checkbox-group.vue +103 -0
  69. package/components/wd-circle/index.scss +18 -0
  70. package/components/wd-circle/types.ts +54 -0
  71. package/components/wd-circle/wd-circle.vue +318 -0
  72. package/components/wd-col/index.scss +19 -0
  73. package/components/wd-col/types.ts +15 -0
  74. package/components/wd-col/wd-col.vue +91 -0
  75. package/components/wd-col-picker/index.scss +241 -0
  76. package/components/wd-col-picker/types.ts +170 -0
  77. package/components/wd-col-picker/wd-col-picker.vue +550 -0
  78. package/components/wd-collapse/index.scss +55 -0
  79. package/components/wd-collapse/types.ts +63 -0
  80. package/components/wd-collapse/wd-collapse.vue +160 -0
  81. package/components/wd-collapse-item/index.scss +79 -0
  82. package/components/wd-collapse-item/types.ts +36 -0
  83. package/components/wd-collapse-item/wd-collapse-item.vue +182 -0
  84. package/components/wd-config-provider/types.ts +1023 -0
  85. package/components/wd-config-provider/wd-config-provider.vue +82 -0
  86. package/components/wd-count-down/index.scss +14 -0
  87. package/components/wd-count-down/types.ts +41 -0
  88. package/components/wd-count-down/utils.ts +52 -0
  89. package/components/wd-count-down/wd-count-down.vue +60 -0
  90. package/components/wd-count-to/index.scss +6 -0
  91. package/components/wd-count-to/types.ts +110 -0
  92. package/components/wd-count-to/wd-count-to.vue +134 -0
  93. package/components/wd-curtain/index.scss +80 -0
  94. package/components/wd-curtain/types.ts +45 -0
  95. package/components/wd-curtain/wd-curtain.vue +174 -0
  96. package/components/wd-datetime-picker/index.scss +243 -0
  97. package/components/wd-datetime-picker/types.ts +225 -0
  98. package/components/wd-datetime-picker/wd-datetime-picker.vue +827 -0
  99. package/components/wd-datetime-picker-view/index.scss +0 -0
  100. package/components/wd-datetime-picker-view/types.ts +137 -0
  101. package/components/wd-datetime-picker-view/wd-datetime-picker-view.vue +514 -0
  102. package/components/wd-divider/index.scss +32 -0
  103. package/components/wd-divider/types.ts +12 -0
  104. package/components/wd-divider/wd-divider.vue +29 -0
  105. package/components/wd-drop-menu/index.scss +89 -0
  106. package/components/wd-drop-menu/types.ts +38 -0
  107. package/components/wd-drop-menu/wd-drop-menu.vue +128 -0
  108. package/components/wd-drop-menu-item/index.scss +66 -0
  109. package/components/wd-drop-menu-item/types.ts +78 -0
  110. package/components/wd-drop-menu-item/wd-drop-menu-item.vue +230 -0
  111. package/components/wd-fab/index.scss +115 -0
  112. package/components/wd-fab/types.ts +61 -0
  113. package/components/wd-fab/wd-fab.vue +257 -0
  114. package/components/wd-form/index.scss +10 -0
  115. package/components/wd-form/types.ts +93 -0
  116. package/components/wd-form/wd-form.vue +185 -0
  117. package/components/wd-form-item/index.scss +17 -0
  118. package/components/wd-form-item/types.ts +22 -0
  119. package/components/wd-form-item/wd-form-item.vue +65 -0
  120. package/components/wd-gap/index.scss +9 -0
  121. package/components/wd-gap/types.ts +23 -0
  122. package/components/wd-gap/wd-gap.vue +39 -0
  123. package/components/wd-grid/index.scss +9 -0
  124. package/components/wd-grid/types.ts +54 -0
  125. package/components/wd-grid/wd-grid.vue +107 -0
  126. package/components/wd-grid-item/index.scss +137 -0
  127. package/components/wd-grid-item/types.ts +74 -0
  128. package/components/wd-grid-item/wd-grid-item.vue +181 -0
  129. package/components/wd-icon/index.scss +1222 -0
  130. package/components/wd-icon/types.ts +21 -0
  131. package/components/wd-icon/wd-icon.vue +53 -0
  132. package/components/wd-icon/wd-icons.ttf +0 -0
  133. package/components/wd-img/index.scss +19 -0
  134. package/components/wd-img/types.ts +53 -0
  135. package/components/wd-img/wd-img.vue +76 -0
  136. package/components/wd-img-cropper/index.scss +227 -0
  137. package/components/wd-img-cropper/types.ts +87 -0
  138. package/components/wd-img-cropper/wd-img-cropper.vue +659 -0
  139. package/components/wd-index-anchor/index.scss +34 -0
  140. package/components/wd-index-anchor/type.ts +9 -0
  141. package/components/wd-index-anchor/wd-index-anchor.vue +57 -0
  142. package/components/wd-index-bar/index.scss +39 -0
  143. package/components/wd-index-bar/type.ts +28 -0
  144. package/components/wd-index-bar/wd-index-bar.vue +158 -0
  145. package/components/wd-input/index.scss +326 -0
  146. package/components/wd-input/types.ts +182 -0
  147. package/components/wd-input/wd-input.vue +327 -0
  148. package/components/wd-input-number/index.scss +132 -0
  149. package/components/wd-input-number/types.ts +78 -0
  150. package/components/wd-input-number/wd-input-number.vue +221 -0
  151. package/components/wd-loading/index.scss +34 -0
  152. package/components/wd-loading/types.ts +31 -0
  153. package/components/wd-loading/wd-loading.vue +90 -0
  154. package/components/wd-loadmore/index.scss +39 -0
  155. package/components/wd-loadmore/types.ts +24 -0
  156. package/components/wd-loadmore/wd-loadmore.vue +53 -0
  157. package/components/wd-message-box/index.scss +121 -0
  158. package/components/wd-message-box/index.ts +95 -0
  159. package/components/wd-message-box/types.ts +116 -0
  160. package/components/wd-message-box/wd-message-box.vue +326 -0
  161. package/components/wd-navbar/index.scss +103 -0
  162. package/components/wd-navbar/types.ts +52 -0
  163. package/components/wd-navbar/wd-navbar.vue +142 -0
  164. package/components/wd-navbar-capsule/index.scss +65 -0
  165. package/components/wd-navbar-capsule/types.ts +0 -0
  166. package/components/wd-navbar-capsule/wd-navbar-capsule.vue +31 -0
  167. package/components/wd-notice-bar/index.scss +86 -0
  168. package/components/wd-notice-bar/types.ts +56 -0
  169. package/components/wd-notice-bar/wd-notice-bar.vue +223 -0
  170. package/components/wd-notify/index.scss +34 -0
  171. package/components/wd-notify/index.ts +59 -0
  172. package/components/wd-notify/types.ts +62 -0
  173. package/components/wd-notify/wd-notify.vue +83 -0
  174. package/components/wd-number-keyboard/index.scss +78 -0
  175. package/components/wd-number-keyboard/key/index.scss +79 -0
  176. package/components/wd-number-keyboard/key/index.vue +76 -0
  177. package/components/wd-number-keyboard/key/types.ts +11 -0
  178. package/components/wd-number-keyboard/types.ts +79 -0
  179. package/components/wd-number-keyboard/wd-number-keyboard.vue +173 -0
  180. package/components/wd-overlay/index.scss +17 -0
  181. package/components/wd-overlay/types.ts +25 -0
  182. package/components/wd-overlay/wd-overlay.vue +46 -0
  183. package/components/wd-pagination/index.scss +57 -0
  184. package/components/wd-pagination/types.ts +41 -0
  185. package/components/wd-pagination/wd-pagination.vue +121 -0
  186. package/components/wd-password-input/index.scss +123 -0
  187. package/components/wd-password-input/types.ts +48 -0
  188. package/components/wd-password-input/wd-password-input.vue +58 -0
  189. package/components/wd-picker/index.scss +216 -0
  190. package/components/wd-picker/types.ts +186 -0
  191. package/components/wd-picker/wd-picker.vue +409 -0
  192. package/components/wd-picker-view/index.scss +91 -0
  193. package/components/wd-picker-view/types.ts +162 -0
  194. package/components/wd-picker-view/wd-picker-view.vue +361 -0
  195. package/components/wd-popover/index.scss +123 -0
  196. package/components/wd-popover/types.ts +69 -0
  197. package/components/wd-popover/wd-popover.vue +216 -0
  198. package/components/wd-popup/index.scss +112 -0
  199. package/components/wd-popup/types.ts +68 -0
  200. package/components/wd-popup/wd-popup.vue +227 -0
  201. package/components/wd-progress/index.scss +62 -0
  202. package/components/wd-progress/types.ts +40 -0
  203. package/components/wd-progress/wd-progress.vue +201 -0
  204. package/components/wd-radio/index.scss +300 -0
  205. package/components/wd-radio/types.ts +42 -0
  206. package/components/wd-radio/wd-radio.vue +136 -0
  207. package/components/wd-radio-group/index.scss +23 -0
  208. package/components/wd-radio-group/types.ts +36 -0
  209. package/components/wd-radio-group/wd-radio-group.vue +54 -0
  210. package/components/wd-rate/index.scss +24 -0
  211. package/components/wd-rate/types.ts +91 -0
  212. package/components/wd-rate/wd-rate.vue +131 -0
  213. package/components/wd-resize/index.scss +26 -0
  214. package/components/wd-resize/types.ts +6 -0
  215. package/components/wd-resize/wd-resize.vue +155 -0
  216. package/components/wd-row/index.scss +10 -0
  217. package/components/wd-row/types.ts +16 -0
  218. package/components/wd-row/wd-row.vue +63 -0
  219. package/components/wd-search/index.scss +148 -0
  220. package/components/wd-search/types.ts +83 -0
  221. package/components/wd-search/wd-search.vue +237 -0
  222. package/components/wd-segmented/index.scss +97 -0
  223. package/components/wd-segmented/types.ts +68 -0
  224. package/components/wd-segmented/wd-segmented.vue +143 -0
  225. package/components/wd-select-picker/index.scss +177 -0
  226. package/components/wd-select-picker/types.ts +116 -0
  227. package/components/wd-select-picker/wd-select-picker.vue +486 -0
  228. package/components/wd-sidebar/index.scss +25 -0
  229. package/components/wd-sidebar/types.ts +28 -0
  230. package/components/wd-sidebar/wd-sidebar.vue +41 -0
  231. package/components/wd-sidebar-item/index.scss +93 -0
  232. package/components/wd-sidebar-item/types.ts +31 -0
  233. package/components/wd-sidebar-item/wd-sidebar-item.vue +114 -0
  234. package/components/wd-skeleton/index.scss +101 -0
  235. package/components/wd-skeleton/index.ts +1 -0
  236. package/components/wd-skeleton/types.ts +69 -0
  237. package/components/wd-skeleton/wd-skeleton.vue +135 -0
  238. package/components/wd-slider/index.scss +91 -0
  239. package/components/wd-slider/types.ts +104 -0
  240. package/components/wd-slider/wd-slider.vue +377 -0
  241. package/components/wd-sort-button/index.scss +86 -0
  242. package/components/wd-sort-button/types.ts +43 -0
  243. package/components/wd-sort-button/wd-sort-button.vue +76 -0
  244. package/components/wd-status-tip/index.scss +37 -0
  245. package/components/wd-status-tip/types.ts +59 -0
  246. package/components/wd-status-tip/wd-status-tip.vue +94 -0
  247. package/components/wd-step/index.scss +236 -0
  248. package/components/wd-step/types.ts +33 -0
  249. package/components/wd-step/wd-step.vue +151 -0
  250. package/components/wd-steps/index.scss +10 -0
  251. package/components/wd-steps/types.ts +59 -0
  252. package/components/wd-steps/wd-steps.vue +37 -0
  253. package/components/wd-sticky/index.scss +9 -0
  254. package/components/wd-sticky/types.ts +13 -0
  255. package/components/wd-sticky/wd-sticky.vue +190 -0
  256. package/components/wd-sticky-box/index.scss +6 -0
  257. package/components/wd-sticky-box/types.ts +20 -0
  258. package/components/wd-sticky-box/wd-sticky-box.vue +154 -0
  259. package/components/wd-swipe-action/index.scss +22 -0
  260. package/components/wd-swipe-action/types.ts +43 -0
  261. package/components/wd-swipe-action/wd-swipe-action.vue +307 -0
  262. package/components/wd-swiper/index.scss +23 -0
  263. package/components/wd-swiper/types.ts +189 -0
  264. package/components/wd-swiper/wd-swiper.vue +202 -0
  265. package/components/wd-swiper-nav/index.scss +153 -0
  266. package/components/wd-swiper-nav/types.ts +42 -0
  267. package/components/wd-swiper-nav/wd-swiper-nav.vue +37 -0
  268. package/components/wd-switch/index.scss +58 -0
  269. package/components/wd-switch/types.ts +56 -0
  270. package/components/wd-switch/wd-switch.vue +83 -0
  271. package/components/wd-tab/index.scss +8 -0
  272. package/components/wd-tab/types.ts +20 -0
  273. package/components/wd-tab/wd-tab.vue +100 -0
  274. package/components/wd-tabbar/index.scss +57 -0
  275. package/components/wd-tabbar/types.ts +88 -0
  276. package/components/wd-tabbar/wd-tabbar.vue +104 -0
  277. package/components/wd-tabbar-item/index.scss +52 -0
  278. package/components/wd-tabbar-item/types.ts +51 -0
  279. package/components/wd-tabbar-item/wd-tabbar-item.vue +101 -0
  280. package/components/wd-table/index.scss +132 -0
  281. package/components/wd-table/types.ts +69 -0
  282. package/components/wd-table/wd-table.vue +255 -0
  283. package/components/wd-table-col/index.scss +44 -0
  284. package/components/wd-table-col/types.ts +54 -0
  285. package/components/wd-table-col/wd-table-col.vue +149 -0
  286. package/components/wd-tabs/index.scss +280 -0
  287. package/components/wd-tabs/types.ts +71 -0
  288. package/components/wd-tabs/wd-tabs.vue +528 -0
  289. package/components/wd-tag/index.scss +115 -0
  290. package/components/wd-tag/types.ts +81 -0
  291. package/components/wd-tag/wd-tag.vue +154 -0
  292. package/components/wd-text/index.scss +34 -0
  293. package/components/wd-text/types.ts +98 -0
  294. package/components/wd-text/wd-text.vue +138 -0
  295. package/components/wd-textarea/index.scss +343 -0
  296. package/components/wd-textarea/types.ts +298 -0
  297. package/components/wd-textarea/wd-textarea.vue +303 -0
  298. package/components/wd-toast/index.scss +66 -0
  299. package/components/wd-toast/index.ts +109 -0
  300. package/components/wd-toast/types.ts +76 -0
  301. package/components/wd-toast/wd-toast.vue +212 -0
  302. package/components/wd-tooltip/index.scss +61 -0
  303. package/components/wd-tooltip/types.ts +102 -0
  304. package/components/wd-tooltip/wd-tooltip.vue +167 -0
  305. package/components/wd-transition/index.scss +91 -0
  306. package/components/wd-transition/types.ts +89 -0
  307. package/components/wd-transition/wd-transition.vue +221 -0
  308. package/components/wd-upload/index.scss +173 -0
  309. package/components/wd-upload/types.ts +378 -0
  310. package/components/wd-upload/utils.ts +152 -0
  311. package/components/wd-upload/wd-upload.vue +737 -0
  312. package/components/wd-video-preview/index.scss +34 -0
  313. package/components/wd-video-preview/types.ts +32 -0
  314. package/components/wd-video-preview/wd-video-preview.vue +76 -0
  315. package/components/wd-watermark/index.scss +18 -0
  316. package/components/wd-watermark/types.ts +82 -0
  317. package/components/wd-watermark/wd-watermark.vue +592 -0
  318. package/components/wot-design-uni/wot-design-uni.vue +14 -0
  319. package/global.d.ts +108 -0
  320. package/index.ts +30 -0
  321. package/locale/index.ts +41 -0
  322. package/locale/lang/en-US.ts +128 -0
  323. package/locale/lang/th-TH.ts +127 -0
  324. package/locale/lang/vi-VN.ts +89 -0
  325. package/locale/lang/zh-CN.ts +127 -0
  326. package/locale/lang/zh-HK.ts +84 -0
  327. package/locale/lang/zh-TW.ts +84 -0
  328. package/package.json +20 -0
@@ -0,0 +1,659 @@
1
+ <template>
2
+ <!-- 绘制的图片canvas -->
3
+ <view
4
+ v-if="modelValue"
5
+ :class="`wd-img-cropper ${customClass}`"
6
+ :style="customStyle"
7
+ @touchmove="preventTouchMove"
8
+ >
9
+ <!-- 展示在用户面前的裁剪框 -->
10
+ <view class="wd-img-cropper__wrapper">
11
+ <!-- 画出裁剪框 -->
12
+ <view class="wd-img-cropper__cut">
13
+ <!-- 上方阴影块 -->
14
+ <view
15
+ :class="`wd-img-cropper__cut--top ${IS_TOUCH_END ? '' : 'is-hightlight'}`"
16
+ :style="`height: ${cutTop}px;`"
17
+ ></view>
18
+ <view class="wd-img-cropper__cut--middle">
19
+ <!-- 左侧阴影块 -->
20
+ <view
21
+ :class="`wd-img-cropper__cut--left ${IS_TOUCH_END ? '' : 'is-hightlight'}`"
22
+ :style="`width: ${cutLeft}px; height: ${cutWidth}px;`"
23
+ ></view>
24
+ <!-- 裁剪框 -->
25
+ <view
26
+ class="wd-img-cropper__cut--body"
27
+ :style="`width: ${cutWidth}px; height: ${cutHeight}px;`"
28
+ >
29
+ <!-- 内部网格线 -->
30
+ <view class="is-gridlines-x"></view>
31
+ <view class="is-gridlines-y"></view>
32
+ <!-- 裁剪窗体四个对角 -->
33
+ <view class="is-left-top"></view>
34
+ <view class="is-left-bottom"></view>
35
+ <view class="is-right-top"></view>
36
+ <view class="is-right-bottom"></view>
37
+ </view>
38
+ <!-- 右侧阴影块 -->
39
+ <view :class="`wd-img-cropper__cut--right ${IS_TOUCH_END ? '' : 'is-hightlight'}`"></view>
40
+ </view>
41
+
42
+ <!-- 底部阴影块 -->
43
+ <view :class="`wd-img-cropper__cut--bottom ${IS_TOUCH_END ? '' : 'is-hightlight'}`"></view>
44
+ </view>
45
+ <!-- 展示的传过来的图片: 控制图片的旋转角度(rotate)、缩放程度(imgScale)、移动位置(translate) -->
46
+ <image
47
+ :prop="isAnimation"
48
+ :change:prop="animation ? animation.setAnimation : ''"
49
+ class="wd-img-cropper__img"
50
+ :src="imgSrc"
51
+ :style="imageStyle"
52
+ :lazy-load="false"
53
+ @touchstart="handleImgTouchStart"
54
+ @touchmove="handleImgTouchMove"
55
+ @touchend="handleImgTouchEnd"
56
+ @error="handleImgLoadError"
57
+ @load="handleImgLoaded"
58
+ />
59
+ </view>
60
+ <!-- 绘制的图片canvas -->
61
+ <canvas
62
+ canvas-id="wd-img-cropper-canvas"
63
+ id="wd-img-cropper-canvas"
64
+ class="wd-img-cropper__canvas"
65
+ :disable-scroll="true"
66
+ :style="`width: ${Number(canvasWidth) * canvasScale}px; height: ${Number(canvasHeight) * canvasScale}px;`"
67
+ />
68
+ <!-- 下方按钮 -->
69
+ <view class="wd-img-cropper__footer">
70
+ <wd-icon
71
+ custom-class="wd-img-cropper__rotate"
72
+ v-if="!disabledRotate"
73
+ name="rotate"
74
+ @click="handleRotate"
75
+ ></wd-icon>
76
+ <view class="wd-img-cropper__footer--button">
77
+ <view class="is-cancel" @click="handleCancel">
78
+ {{ cancelButtonText || translate('cancel') }}
79
+ </view>
80
+ <wd-button size="small" :custom-style="buttonStyle" @click="handleConfirm">
81
+ {{ confirmButtonText || translate('confirm') }}
82
+ </wd-button>
83
+ </view>
84
+ </view>
85
+ </view>
86
+ </template>
87
+
88
+ <script lang="ts">
89
+ export default {
90
+ name: 'wd-img-cropper',
91
+ options: {
92
+ virtualHost: true,
93
+ addGlobalClass: true,
94
+ styleIsolation: 'shared',
95
+ },
96
+ }
97
+ </script>
98
+
99
+ <script lang="ts" setup>
100
+ import { computed, getCurrentInstance, ref, watch } from 'vue'
101
+ import { addUnit, objToStyle } from '../common/util'
102
+ import { useTranslate } from '../composables/useTranslate'
103
+ import { imgCropperProps, type ImgCropperExpose } from './types'
104
+
105
+ // 延时动画设置
106
+ let CHANGE_TIME: any | null = null
107
+ // 移动节流
108
+ let MOVE_THROTTLE: any | null = null
109
+ // 节流标志
110
+ let MOVE_THROTTLE_FLAG: boolean = true
111
+ // 图片设置尺寸,此值不变(记录最初设定的尺寸)
112
+ let INIT_IMGWIDTH: null | number | string = null
113
+ // 图片设置尺寸,此值不变(记录最初设定的尺寸)
114
+ let INIT_IMGHEIGHT: null | number | string = null
115
+ // 顶部裁剪框占比
116
+ const TOP_PERCENT = 0.85
117
+
118
+ const props = defineProps(imgCropperProps)
119
+ const emit = defineEmits(['imgloaded', 'imgloaderror', 'cancel', 'confirm', 'update:modelValue'])
120
+
121
+ const { translate } = useTranslate('img-cropper')
122
+
123
+ // 旋转角度
124
+ const imgAngle = ref<number>(0)
125
+ // 是否开启动画
126
+ const isAnimation = ref<boolean>(false)
127
+ // #ifdef MP-ALIPAY || APP-PLUS
128
+ // hack 避免钉钉小程序、支付宝小程序、app抛出相关异常
129
+ const animation: any = null
130
+ // #endif
131
+
132
+ // 裁剪框的宽高
133
+ const picWidth = ref<number>(0)
134
+ const picHeight = ref<number>(0)
135
+ const cutWidth = ref<number>(0)
136
+ const cutHeight = ref<number>(0)
137
+ const offset = ref<number>(20)
138
+ // 裁剪框的距顶距左
139
+ const cutLeft = ref<number>(0)
140
+ const cutTop = ref<number>(0)
141
+ // canvas最终成像宽高
142
+ const canvasWidth = ref<string | number>('')
143
+ const canvasHeight = ref<string | number>('')
144
+ const canvasScale = ref<number>(2)
145
+ // 当前缩放大小
146
+ const imgScale = ref<number>(1)
147
+ // // 图片宽高
148
+ // imgWidth: null,
149
+ // imgHeight: null,
150
+ // 图片中心轴点距左的距离
151
+ const imgLeft = ref<number>(uni.getSystemInfoSync().windowWidth / 2)
152
+ const imgTop = ref<number>((uni.getSystemInfoSync().windowHeight / 2) * TOP_PERCENT)
153
+
154
+ const imgInfo = ref<UniApp.GetImageInfoSuccessData | null>(null)
155
+ const info = ref<UniApp.GetSystemInfoResult>(uni.getSystemInfoSync())
156
+
157
+ // 是否移动中设置 同时控制背景颜色是否高亮
158
+ const IS_TOUCH_END = ref<boolean>(true)
159
+ // 记录移动中的双指位置 [0][1]分别代表两根手指 [1]做待用参数
160
+ const movingPosRecord = ref<Record<string, string | number>[]>([
161
+ {
162
+ x: '',
163
+ y: '',
164
+ },
165
+ {
166
+ x: '',
167
+ y: '',
168
+ },
169
+ ])
170
+ // 双指缩放时 两个坐标点斜边长度
171
+ const fingerDistance = ref<string | number>('')
172
+
173
+ const ctx = ref<UniApp.CanvasContext | null>(null)
174
+
175
+ const { proxy } = getCurrentInstance() as any
176
+
177
+ watch(
178
+ () => props.modelValue,
179
+ (newValue) => {
180
+ if (newValue) {
181
+ INIT_IMGWIDTH = props.imgWidth
182
+ INIT_IMGHEIGHT = props.imgHeight
183
+ info.value = uni.getSystemInfoSync()
184
+ const tempCutSize = info.value.windowWidth - offset.value * 2
185
+ cutWidth.value = tempCutSize
186
+ cutHeight.value = tempCutSize
187
+ cutTop.value = (info.value.windowHeight * TOP_PERCENT - tempCutSize) / 2
188
+ cutLeft.value = offset.value
189
+ canvasScale.value = props.exportScale
190
+ canvasHeight.value = tempCutSize
191
+ canvasWidth.value = tempCutSize
192
+ // 根据开发者设置的图片目标尺寸计算实际尺寸
193
+ initImageSize()
194
+ // 初始化canvas
195
+ initCanvas()
196
+ // 加载图片
197
+ props.imgSrc && loadImg()
198
+ } else {
199
+ resetImg()
200
+ }
201
+ },
202
+ {
203
+ deep: true,
204
+ immediate: true,
205
+ },
206
+ )
207
+
208
+ watch(
209
+ () => props.imgSrc,
210
+ (newValue) => {
211
+ newValue && loadImg()
212
+ },
213
+ {
214
+ deep: true,
215
+ immediate: true,
216
+ },
217
+ )
218
+
219
+ watch(
220
+ () => imgAngle.value,
221
+ (newValue) => {
222
+ if (newValue % 90) {
223
+ imgAngle.value = Math.round(newValue / 90) * 90
224
+ }
225
+ },
226
+ {
227
+ deep: true,
228
+ immediate: true,
229
+ },
230
+ )
231
+ watch(
232
+ () => isAnimation.value,
233
+ (newValue) => {
234
+ // 开启过渡300毫秒之后自动关闭
235
+ CHANGE_TIME && clearTimeout(CHANGE_TIME)
236
+ if (newValue) {
237
+ CHANGE_TIME = setTimeout(() => {
238
+ revertIsAnimation(false)
239
+ clearTimeout(CHANGE_TIME)
240
+ }, 300)
241
+ }
242
+ },
243
+ {
244
+ deep: true,
245
+ immediate: true,
246
+ },
247
+ )
248
+
249
+ const buttonStyle = computed(() => {
250
+ const style: Record<string, string | number> = {
251
+ position: 'absolute',
252
+ right: 0,
253
+ // height: 32px;
254
+ width: '56px',
255
+ 'border-radius': '16px',
256
+ 'font-size': '16px',
257
+ }
258
+
259
+ return objToStyle(style)
260
+ })
261
+
262
+ const imageStyle = computed(() => {
263
+ const style: Record<string, string | number> = {
264
+ width: picWidth.value ? addUnit(picWidth.value) : 'auto',
265
+ height: picHeight.value ? addUnit(picHeight.value) : 'auto',
266
+ transform: `translate(${addUnit(imgLeft.value - picWidth.value / 2)}, ${addUnit(imgTop.value - picHeight.value / 2)}) scale(${
267
+ imgScale.value
268
+ }) rotate(${imgAngle.value}deg)`,
269
+ 'transition-duration': (isAnimation.value ? 0.4 : 0) + 's',
270
+ }
271
+ return objToStyle(style)
272
+ })
273
+
274
+ /**
275
+ * 逆转是否使用动画
276
+ */
277
+ function revertIsAnimation(animation: boolean) {
278
+ isAnimation.value = animation
279
+ }
280
+
281
+ /**
282
+ * 控制旋转角度
283
+ * @param angle 角度
284
+ */
285
+ function setRoate(angle: number) {
286
+ if (!angle || props.disabledRotate) return
287
+ revertIsAnimation(true)
288
+ imgAngle.value = angle
289
+ // 设置旋转后需要判定旋转后宽高是否不符合贴边的标准
290
+ detectImgPosIsEdge()
291
+ }
292
+
293
+ /**
294
+ * 初始化图片的大小和角度以及距离
295
+ */
296
+ function resetImg() {
297
+ const { windowHeight, windowWidth } = uni.getSystemInfoSync()
298
+ imgScale.value = 1
299
+ imgAngle.value = 0
300
+ imgLeft.value = windowWidth / 2
301
+ imgTop.value = (windowHeight / 2) * TOP_PERCENT
302
+ }
303
+
304
+ /**
305
+ * 加载图片资源文件,并初始化裁剪框内图片信息
306
+ */
307
+ function loadImg() {
308
+ if (!props.imgSrc) return
309
+
310
+ uni.getImageInfo({
311
+ src: props.imgSrc,
312
+ success: (res) => {
313
+ // 存储img图片信息
314
+ imgInfo.value = res
315
+ // 计算最后图片尺寸
316
+ computeImgSize()
317
+ // 初始化尺寸
318
+ resetImg()
319
+ },
320
+ fail: () => {
321
+ // this.setData({ imgSrc: '' })
322
+ },
323
+ })
324
+ }
325
+
326
+ /**
327
+ * 设置图片尺寸,使其有一边小于裁剪框尺寸
328
+ * 1、图片宽或高 小于裁剪框,自动放大至一边与高平齐
329
+ * 2、图片宽或高 大于裁剪框,自动缩小至一边与高平齐
330
+ */
331
+ function computeImgSize() {
332
+ let tempPicWidth: number = picWidth.value
333
+ let tempPicHeight: number = picHeight.value
334
+
335
+ if (!INIT_IMGHEIGHT && !INIT_IMGWIDTH) {
336
+ // 没有设置宽高,写入图片的真实宽高
337
+ tempPicWidth = imgInfo.value!.width
338
+ tempPicHeight = imgInfo.value!.height
339
+ /**
340
+ * 设 a = imgWidth; b = imgHeight; x = cutWidth; y = cutHeight
341
+ * 共有三种宽高比:1、a/b > x/y 2、a/b < x/y 3、a/b = x/y
342
+ * 1、已知 b = y => a = a/b*y
343
+ * 2、已知 a = x => b = b/a*x
344
+ * 3、可用上方任意公式
345
+ */
346
+ if (picWidth.value / picHeight.value > cutWidth.value / cutHeight.value) {
347
+ tempPicHeight = cutHeight.value
348
+ tempPicWidth = (imgInfo.value!.width / imgInfo.value!.height) * cutHeight.value
349
+ } else {
350
+ tempPicWidth = cutWidth.value
351
+ tempPicHeight = (imgInfo.value!.height / imgInfo.value!.width) * cutWidth.value
352
+ }
353
+ } else if (INIT_IMGHEIGHT && !INIT_IMGWIDTH) {
354
+ tempPicWidth = (imgInfo.value!.width / imgInfo.value!.height) * Number(INIT_IMGHEIGHT)
355
+ } else if ((!INIT_IMGHEIGHT && INIT_IMGWIDTH) || (INIT_IMGHEIGHT && INIT_IMGWIDTH)) {
356
+ tempPicHeight = (imgInfo.value!.height / imgInfo.value!.width) * Number(INIT_IMGWIDTH)
357
+ }
358
+ picWidth.value = tempPicWidth
359
+ picHeight.value = tempPicHeight
360
+ }
361
+
362
+ /**
363
+ * canvas 初始化
364
+ */
365
+ function initCanvas() {
366
+ if (!ctx.value) {
367
+ ctx.value = uni.createCanvasContext('wd-img-cropper-canvas', proxy)
368
+ }
369
+ }
370
+
371
+ /**
372
+ * 图片初始化,处理宽高特殊单位
373
+ */
374
+ function initImageSize() {
375
+ // 处理宽高特殊单位 %>px
376
+ if (INIT_IMGWIDTH && typeof INIT_IMGWIDTH === 'string' && INIT_IMGWIDTH.indexOf('%') !== -1) {
377
+ const width: string = INIT_IMGWIDTH.replace('%', '')
378
+ INIT_IMGWIDTH = (info.value.windowWidth / 100) * Number(width)
379
+ picWidth.value = INIT_IMGWIDTH
380
+ } else if (INIT_IMGWIDTH && typeof INIT_IMGWIDTH === 'number') {
381
+ picWidth.value = INIT_IMGWIDTH
382
+ }
383
+ if (INIT_IMGHEIGHT && typeof INIT_IMGHEIGHT === 'string' && INIT_IMGHEIGHT.indexOf('%') !== -1) {
384
+ const height = (props.imgHeight as string).replace('%', '')
385
+ // INIT_IMGHEIGHT = this.data.imgHeight = (info.value.windowHeight / 100) * Number(height)
386
+ INIT_IMGHEIGHT = (info.value.windowHeight / 100) * Number(height)
387
+ picWidth.value = INIT_IMGHEIGHT
388
+ } else if (INIT_IMGHEIGHT && typeof INIT_IMGHEIGHT === 'number') {
389
+ picWidth.value = Number(INIT_IMGWIDTH)
390
+ }
391
+ }
392
+
393
+ /**
394
+ * 图片拖动边缘检测:检测移动或缩放时 是否触碰到图片边缘位置
395
+ */
396
+ function detectImgPosIsEdge(scale?: number) {
397
+ const currentScale = scale || imgScale.value
398
+ let currentImgLeft = imgLeft.value
399
+ let currentImgTop = imgTop.value
400
+ let currentPicWidth = picWidth.value
401
+ let currentPicHeight = picHeight.value
402
+
403
+ // 翻转后宽高切换
404
+ if ((imgAngle.value / 90) % 2) {
405
+ currentPicWidth = picHeight.value
406
+ currentPicHeight = picWidth.value
407
+ }
408
+ // 左
409
+ currentImgLeft =
410
+ (currentPicWidth * currentScale) / 2 + cutLeft.value >= currentImgLeft
411
+ ? currentImgLeft
412
+ : (currentPicWidth * imgScale.value) / 2 + cutLeft.value
413
+ // 右
414
+ currentImgLeft =
415
+ cutLeft.value + cutWidth.value - (currentPicWidth * currentScale) / 2 <= currentImgLeft
416
+ ? currentImgLeft
417
+ : cutLeft.value + cutWidth.value - (currentPicWidth * currentScale) / 2
418
+ // 上
419
+ currentImgTop =
420
+ (currentPicHeight * currentScale) / 2 + cutTop.value >= currentImgTop
421
+ ? currentImgTop
422
+ : (currentPicHeight * currentScale) / 2 + cutTop.value
423
+ // 下
424
+ currentImgTop =
425
+ cutTop.value + cutHeight.value - (currentPicHeight * currentScale) / 2 <= currentImgTop
426
+ ? currentImgTop
427
+ : cutTop.value + cutHeight.value - (currentPicHeight * currentScale) / 2
428
+
429
+ imgScale.value = currentScale
430
+ imgTop.value = currentImgTop
431
+ imgLeft.value = currentImgLeft
432
+ }
433
+
434
+ /**
435
+ * 缩放边缘检测:检测移动或缩放时 是否触碰到图片边缘位置
436
+ */
437
+ function detectImgScaleIsEdge() {
438
+ let tempPicWidth = picWidth.value
439
+ let tempPicHeight = picHeight.value
440
+ let tempImgScale = imgScale.value
441
+
442
+ // 翻转后宽高切换
443
+ if ((imgAngle.value / 90) % 2) {
444
+ tempPicWidth = picHeight.value
445
+ tempPicHeight = picWidth.value
446
+ }
447
+ if (tempPicWidth * tempImgScale < cutWidth.value) {
448
+ tempImgScale = cutWidth.value / tempPicWidth
449
+ }
450
+ if (tempPicHeight * tempImgScale < cutHeight.value) {
451
+ tempImgScale = cutHeight.value / tempPicHeight
452
+ }
453
+ detectImgPosIsEdge(tempImgScale)
454
+ }
455
+
456
+ /**
457
+ * 节流
458
+ */
459
+ function throttle() {
460
+ if (info.value.platform === 'android') {
461
+ MOVE_THROTTLE && clearTimeout(MOVE_THROTTLE)
462
+ MOVE_THROTTLE = setTimeout(() => {
463
+ MOVE_THROTTLE_FLAG = true
464
+ }, 1000 / 40)
465
+ } else {
466
+ !MOVE_THROTTLE_FLAG && (MOVE_THROTTLE_FLAG = true)
467
+ }
468
+ }
469
+
470
+ /**
471
+ * {图片区} 开始拖动
472
+ */
473
+ function handleImgTouchStart(event: any) {
474
+ // 如果处于在拖动中,背景为淡色展示全部,拖动结束则为 0.85 透明度
475
+ IS_TOUCH_END.value = false
476
+ if (event.touches.length === 1) {
477
+ // 单指拖动
478
+ movingPosRecord.value[0] = {
479
+ x: event.touches[0].clientX - imgLeft.value,
480
+ y: event.touches[0].clientY - imgTop.value,
481
+ }
482
+ } else {
483
+ // 以两指为坐标点 做直角三角形 a2 + b2 = c2
484
+ const width = Math.abs(event.touches[1].clientX - event.touches[0].clientX)
485
+ const height = Math.abs(event.touches[1].clientY - event.touches[0].clientY)
486
+ fingerDistance.value = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
487
+ }
488
+ }
489
+
490
+ /**
491
+ * {图片区} 拖动中
492
+ */
493
+ function handleImgTouchMove(event: any) {
494
+ if (IS_TOUCH_END.value || !MOVE_THROTTLE_FLAG) return
495
+ // 节流
496
+ throttle()
497
+ if (event.touches.length === 1) {
498
+ // 单指拖动
499
+ const { x, y } = movingPosRecord.value[0]
500
+ const left = event.touches[0].clientX - Number(x)
501
+ const top = event.touches[0].clientY - Number(y)
502
+ imgLeft.value = left
503
+ imgTop.value = top
504
+ detectImgPosIsEdge()
505
+ } else {
506
+ // 以两指为坐标点 做直角三角形 a2 + b2 = c2
507
+ const width = Math.abs(event.touches[1].clientX - event.touches[0].clientX)
508
+ const height = Math.abs(event.touches[1].clientY - event.touches[0].clientY)
509
+ const hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
510
+ const scale = imgScale.value * (hypotenuse / Number(fingerDistance.value))
511
+ imgScale.value = Math.min(scale, props.maxScale)
512
+ detectImgScaleIsEdge()
513
+ fingerDistance.value = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
514
+ }
515
+ }
516
+
517
+ /**
518
+ * {图片区} 拖动结束
519
+ */
520
+ function handleImgTouchEnd() {
521
+ IS_TOUCH_END.value = true
522
+ }
523
+
524
+ /**
525
+ * 图片已加载完成
526
+ */
527
+ function handleImgLoaded(res: any) {
528
+ emit('imgloaded', res)
529
+ }
530
+
531
+ /**
532
+ * 图片加载失败
533
+ */
534
+ function handleImgLoadError(err: any) {
535
+ emit('imgloaderror', err)
536
+ }
537
+
538
+ /**
539
+ * 旋转图片
540
+ */
541
+ function handleRotate() {
542
+ setRoate(imgAngle.value - 90)
543
+ }
544
+
545
+ /**
546
+ * 取消裁剪图片
547
+ */
548
+ function handleCancel() {
549
+ emit('cancel')
550
+ emit('update:modelValue', false)
551
+ }
552
+
553
+ /**
554
+ * 完成裁剪
555
+ */
556
+ function handleConfirm() {
557
+ draw()
558
+ }
559
+
560
+ /**
561
+ * canvas 绘制图片输出成文件类型
562
+ */
563
+ function canvasToImage() {
564
+ const { fileType, quality, exportScale } = props
565
+ try {
566
+ uni.canvasToTempFilePath(
567
+ {
568
+ width: cutWidth.value * exportScale,
569
+ height: Math.round(cutHeight.value * exportScale),
570
+ destWidth: cutWidth.value * exportScale,
571
+ destHeight: Math.round(cutHeight.value * exportScale),
572
+ fileType,
573
+ quality,
574
+ canvasId: 'wd-img-cropper-canvas',
575
+ success: (res: any) => {
576
+ const result = {
577
+ tempFilePath: res.tempFilePath,
578
+ width: cutWidth.value * exportScale,
579
+ height: cutHeight.value * exportScale,
580
+ }
581
+ // #ifdef MP-DINGTALK
582
+ result.tempFilePath = res.filePath
583
+ // #endif
584
+ emit('confirm', result)
585
+ },
586
+ complete: () => {
587
+ emit('update:modelValue', false)
588
+ },
589
+ },
590
+ proxy,
591
+ )
592
+ } catch (error) {
593
+ console.log(error)
594
+ }
595
+ }
596
+
597
+ /**
598
+ * canvas绘制,用canvas模拟裁剪框 对根据图片当前的裁剪信息进行模拟
599
+ */
600
+ function draw() {
601
+ if (!props.imgSrc) return
602
+ const draw = () => {
603
+ // 图片真实大小
604
+ const width = picWidth.value * imgScale.value * props.exportScale
605
+ const height = picHeight.value * imgScale.value * props.exportScale
606
+ // 取裁剪框和图片的交集
607
+ const x = imgLeft.value - cutLeft.value
608
+ const y = imgTop.value - cutTop.value
609
+ // 如果直接使用canvas绘制的图片会有锯齿,因此需要*设备像素比
610
+ // 设置(x, y)设置图片在canvas中的位置
611
+ ctx.value!.translate(x * props.exportScale, y * props.exportScale)
612
+ // 设置 旋转角度
613
+ if (!props.disabledRotate) {
614
+ ctx.value!.rotate((imgAngle.value * Math.PI) / 180)
615
+ }
616
+ // drawImage 的 旋转是根据以当前图片的图片水平垂直方向为x、y轴,并在x y轴上移动
617
+ ctx.value!.drawImage(props.imgSrc, -width / 2, -height / 2, width, height)
618
+
619
+ ctx.value!.restore()
620
+
621
+ // 绘制图片
622
+ ctx.value!.draw(false, () => {
623
+ canvasToImage()
624
+ })
625
+ }
626
+
627
+ canvasHeight.value = cutHeight.value
628
+ canvasWidth.value = cutWidth.value
629
+ draw()
630
+ }
631
+ function preventTouchMove() {}
632
+
633
+ defineExpose<ImgCropperExpose>({
634
+ revertIsAnimation,
635
+ setRoate,
636
+ resetImg,
637
+ })
638
+ </script>
639
+
640
+ <!-- #ifdef MP-WEIXIN || MP-QQ || H5 -->
641
+ <script module="animation" lang="wxs">
642
+ function setAnimation(newValue, oldValue, ownerInstance) {
643
+ if (newValue) {
644
+ var id = ownerInstance.setTimeout(function () {
645
+ ownerInstance.callMethod('revertIsAnimation', false)
646
+ ownerInstance.clearTimeout(id)
647
+ }, 300)
648
+ }
649
+ }
650
+
651
+ module.exports = {
652
+ setAnimation: setAnimation,
653
+ }
654
+ </script>
655
+ <!-- #endif -->
656
+
657
+ <style lang="scss" scoped>
658
+ @import './index';
659
+ </style>
@@ -0,0 +1,34 @@
1
+ @import './../common/abstracts/_mixin';
2
+ @import './../common/abstracts/variable';
3
+
4
+ .wot-theme-dark {
5
+ @include b(index-anchor) {
6
+ color: $-color-white;
7
+ background-color: $-color-gray-8;
8
+ }
9
+ }
10
+
11
+ // #ifdef MP-DINGTALK
12
+ @include b(index-anchor-ding) {
13
+ @include when(sticky) {
14
+ position: sticky;
15
+ top: 0;
16
+ left: 0;
17
+ z-index: 1;
18
+ }
19
+ }
20
+ // #endif
21
+
22
+ @include b(index-anchor) {
23
+ padding: 10px;
24
+ font-size: 14px;
25
+ color: $-color-title;
26
+ background-color: $-color-gray-2;
27
+
28
+ @include when(sticky) {
29
+ position: sticky;
30
+ top: 0;
31
+ left: 0;
32
+ z-index: 1;
33
+ }
34
+ }
@@ -0,0 +1,9 @@
1
+ import type { ExtractPropTypes } from 'vue'
2
+ import { baseProps, makeRequiredProp } from '../common/props'
3
+
4
+ export const indexAnchorProps = {
5
+ ...baseProps,
6
+ index: makeRequiredProp([String, Number]),
7
+ }
8
+
9
+ export type IndexAnchorProps = ExtractPropTypes<typeof indexAnchorProps>