u-qrcode.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <template>
  2. <view class="u-qrcode" :style="[{
  3. width: $u.addUnit(size),
  4. height: $u.addUnit(size)
  5. }]" @longpress="handleLongpress">
  6. <u-canvas
  7. ref="canvasRef"
  8. :width="size"
  9. :height="size"
  10. :customStyle="mode === 'image' ? 'position: absolute; left: -9999px; top: -9999px;' : ''"
  11. />
  12. <view class="u-qrcode__image-wrapper" v-if="mode === 'image'">
  13. <image :src="imageUrl" class="u-qrcode__image" mode="widthFix"/>
  14. </view>
  15. <view class="u-qrcode__mask" v-if="status === 'loading'">
  16. <slot name="loading">
  17. <u-loading-icon mode="semicircle"></u-loading-icon>
  18. </slot>
  19. </view>
  20. <view class="u-qrcode__mask" v-if="status === 'expired'">
  21. <slot name="expired">
  22. <text class="u-qrcode__expired-message">{{ expiredText }}</text>
  23. <view class="u-qrcode__expired-btn" @click="handleRefresh">
  24. <u-icon name="reload" size="20" color="primary" :label="refreshText" labelColor="primary"></u-icon>
  25. </view>
  26. </slot>
  27. </view>
  28. <view class="u-qrcode__mask" v-if="status === 'scanned'">
  29. <slot name="scanned">
  30. <u-icon name="checkmark-circle-fill" size="20" color="primary" :label="scannedText" labelColor="primary"></u-icon>
  31. </slot>
  32. </view>
  33. </view>
  34. </template>
  35. <script>
  36. import props from './props.js';
  37. import mixin from '../../libs/mixin/mixin'
  38. import mpMixin from '../../libs/mixin/mpMixin';
  39. import QRCode from '../../libs/util/qrcode.js';
  40. /**
  41. * qrcode 二维码
  42. * @description 二维码生成
  43. * @tutorial https://uview.d3u.cn/components/qrcode.html
  44. * @property {String} background 背景色
  45. * @property {String} foreground 前景色
  46. * @property {String} pdground 定位角点颜色
  47. * @property {String} level 容错级别
  48. * @property {String} value 二维码内容 (start为true时必填 )
  49. * @property {String} expiredText 过期文本
  50. * @property {String} scannedText 扫描文本
  51. * @property {String} refreshText 刷新文本
  52. * @property {String | Number} size 二维码尺寸
  53. * @property {String} icon 二维码图标
  54. * @property {Number} iconSize 二维码图标大小
  55. * @property {String} status 状态 expired,scanned,loading
  56. *
  57. * @example <u-qrcode ref="qrcode" size="200px" value="https://uview.d3u.cn"></u-qrcode>
  58. */
  59. export default {
  60. name: 'u-qrcode',
  61. mixins: [mpMixin, mixin, props],
  62. data() {
  63. return {
  64. imageUrl: '',
  65. };
  66. },
  67. watch: {
  68. value: {
  69. handler(newVal) {
  70. if(newVal){
  71. this.remake();
  72. }
  73. }
  74. },
  75. size: {
  76. handler(newVal) {
  77. if(newVal && newVal !== this.size){
  78. this.remake();
  79. }
  80. }
  81. }
  82. },
  83. mounted() {
  84. this.make();
  85. },
  86. // #ifdef VUE3
  87. emits: ["change", "refresh","onLongpress","error"],
  88. // #endif
  89. methods: {
  90. async make() {
  91. await this.$nextTick();
  92. const { canvas } = await this.$refs.canvasRef.getCanvasContext();
  93. new QRCode({
  94. canvas: canvas,
  95. text: this.value,
  96. size: this.size,
  97. background: this.background,
  98. foreground: this.foreground,
  99. pdground: this.pdground,
  100. correctLevel: this.level,
  101. icon: this.icon,
  102. iconSize: this.iconSize,
  103. callback: () => {
  104. if(this.mode === 'image') {
  105. this.getTempFile((tempFilePath)=>{
  106. this.imageUrl = tempFilePath;
  107. })
  108. }
  109. }
  110. });
  111. },
  112. getTempFile(callback) {
  113. this.$refs.canvasRef.canvasToTempFilePath({
  114. width: this.size,
  115. height: this.size,
  116. fileType: 'png',
  117. quality: 1,
  118. }).then((tempFilePath) => {
  119. callback(tempFilePath);
  120. }).catch((error) => {
  121. this.$emit('error', error);
  122. });
  123. },
  124. remake() {
  125. this.make();
  126. this.$emit('change');
  127. },
  128. handleRefresh() {
  129. this.$emit('refresh');
  130. },
  131. handleLongpress() {
  132. this.getTempFile((tempFilePath)=>{
  133. this.$emit('onLongpress', tempFilePath);
  134. })
  135. }
  136. }
  137. };
  138. </script>
  139. <style lang="scss" scoped>
  140. @import "../../libs/css/components.scss";
  141. .u-qrcode{
  142. position: relative;
  143. &__image {
  144. width: 100%;
  145. height: 100%;
  146. &-wrapper{
  147. width: 100%;
  148. height: 100%;
  149. }
  150. }
  151. &__mask{
  152. @include flex(row);
  153. flex-direction: column;
  154. position: absolute;
  155. top: 0;
  156. right: 0;
  157. bottom: 0;
  158. left: 0;
  159. z-index: 10;
  160. justify-content: center;
  161. align-items: center;
  162. background: rgba(255, 255, 255, 0.9);
  163. }
  164. &__expired-message {
  165. font-size: 15px;
  166. font-weight: 800;
  167. color: #333;
  168. }
  169. &__expired-btn {
  170. @include flex(row);
  171. align-items: center;
  172. justify-content: center;
  173. margin-top: 5px;
  174. }
  175. }
  176. </style>