cl-qrcode.uvue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <template>
  2. <view :style="{ width: getPx(props.width) + 'px', height: getPx(props.height) + 'px' }">
  3. <canvas
  4. ref="canvasRef"
  5. :canvas-id="qrcodeId"
  6. type="2d"
  7. :id="qrcodeId"
  8. :style="{ width: getPx(props.width) + 'px', height: getPx(props.height) + 'px' }"
  9. ></canvas>
  10. </view>
  11. </template>
  12. <script lang="ts" setup>
  13. import {
  14. ref,
  15. watch,
  16. onMounted,
  17. getCurrentInstance,
  18. nextTick,
  19. computed,
  20. type PropType,
  21. onUnmounted,
  22. shallowRef
  23. } from "vue";
  24. import { drawQrcode, type QrcodeOptions } from "./draw";
  25. import { canvasToPng, getPx, isHarmony, uuid } from "@/cool";
  26. import type { ClQrcodeMode } from "../../types";
  27. defineOptions({
  28. name: "cl-qrcode"
  29. });
  30. const props = defineProps({
  31. // 二维码宽度,支持 px/rpx 单位
  32. width: {
  33. type: String,
  34. default: "200px"
  35. },
  36. // 二维码高度,支持 px/rpx 单位
  37. height: {
  38. type: String,
  39. default: "200px"
  40. },
  41. // 二维码前景色
  42. foreground: {
  43. type: String,
  44. default: "#131313"
  45. },
  46. // 二维码背景色
  47. background: {
  48. type: String,
  49. default: "#FFFFFF"
  50. },
  51. // 定位点颜色,不填写时与前景色一致
  52. pdColor: {
  53. type: String as PropType<string | null>,
  54. default: null
  55. },
  56. // 定位图案圆角半径,为0时绘制直角矩形
  57. pdRadius: {
  58. type: Number,
  59. default: 10
  60. },
  61. // 二维码内容
  62. text: {
  63. type: String,
  64. default: "https://cool-js.com/"
  65. },
  66. // logo 图片地址,支持网络、本地路径
  67. logo: {
  68. type: String,
  69. default: ""
  70. },
  71. // logo 大小,支持 px/rpx 单位
  72. logoSize: {
  73. type: String,
  74. default: "50px"
  75. },
  76. // 二维码边距,单位 px
  77. padding: {
  78. type: Number,
  79. default: 5
  80. },
  81. // 二维码样式:rect 普通矩形、circular 小圆点、line 线条、rectSmall 小方格
  82. mode: {
  83. type: String as PropType<ClQrcodeMode>,
  84. default: "circular"
  85. }
  86. });
  87. const { proxy } = getCurrentInstance()!;
  88. // 二维码组件id
  89. const qrcodeId = ref<string>("cl-qrcode-" + uuid());
  90. // 二维码组件画布
  91. const canvasRef = shallowRef<UniElement | null>(null);
  92. /**
  93. * 主绘制方法,根据当前 props 生成二维码并绘制到 canvas。
  94. * 支持多平台(APP、H5、微信小程序),自动适配高分屏。
  95. * 内部调用 drawQrcode 进行二维码点阵绘制。
  96. */
  97. function drawer() {
  98. const data = {
  99. text: props.text,
  100. size: getPx(props.width),
  101. foreground: props.foreground,
  102. background: props.background,
  103. padding: props.padding,
  104. logo: props.logo,
  105. logoSize: getPx(props.logoSize),
  106. ecc: "H", // 使用最高纠错级别
  107. mode: props.mode,
  108. pdColor: props.pdColor,
  109. pdRadius: props.pdRadius
  110. } as QrcodeOptions;
  111. nextTick(() => {
  112. // #ifdef APP || MP-WEIXIN
  113. uni.createCanvasContextAsync({
  114. id: qrcodeId.value,
  115. component: proxy,
  116. success(context) {
  117. drawQrcode(context, data);
  118. },
  119. fail(err) {
  120. console.error(err);
  121. }
  122. });
  123. // #endif
  124. // #ifdef H5
  125. // @ts-ignore
  126. drawQrcode(canvasRef.value, data);
  127. // #endif
  128. });
  129. }
  130. /**
  131. * 获取当前二维码图片的临时文件地址
  132. * @param call 回调函数,返回图片路径,失败返回空字符串
  133. */
  134. function toPng(): Promise<string> {
  135. return canvasToPng(canvasRef.value!);
  136. }
  137. // 自动重绘
  138. const stopWatch = watch(
  139. computed(() => [
  140. props.pdColor,
  141. props.pdRadius,
  142. props.foreground,
  143. props.background,
  144. props.text,
  145. props.logo,
  146. props.logoSize,
  147. props.mode,
  148. props.padding
  149. ]),
  150. () => {
  151. drawer();
  152. }
  153. );
  154. onMounted(() => {
  155. setTimeout(
  156. () => {
  157. drawer();
  158. },
  159. isHarmony() ? 50 : 0
  160. );
  161. });
  162. onUnmounted(() => {
  163. stopWatch();
  164. });
  165. defineExpose({
  166. toPng
  167. });
  168. </script>