index.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <template>
  2. <view>
  3. <image v-if="filePath" :src="filePath" :style="{ width: `${size}px`, height: `${size}px` }"></image>
  4. <canvas
  5. v-if="!filePath"
  6. :id="cid"
  7. :canvas-id="cid"
  8. :style="{ width: `${size}px`, height: `${size}px` }"
  9. />
  10. </view>
  11. </template>
  12. <script>
  13. import uQRCode from '@/utils/uqrcode.js';
  14. export default {
  15. props: {
  16. cid: {
  17. type: String,
  18. required: true
  19. },
  20. text: {
  21. type: String,
  22. required: true
  23. },
  24. size: {
  25. type: Number,
  26. default: 129
  27. },
  28. margin: {
  29. type: Number,
  30. default: 0
  31. },
  32. backgroundColor: {
  33. type: String,
  34. default: '#ffffff'
  35. },
  36. foregroundColor: {
  37. type: String,
  38. default: '#000000'
  39. },
  40. backgroundImage: {
  41. type: String
  42. },
  43. logo: {
  44. type: String
  45. },
  46. makeOnLoad: {
  47. type: Boolean,
  48. default: false
  49. }
  50. },
  51. data() {
  52. return {
  53. filePath: ''
  54. };
  55. },
  56. mounted() {
  57. if (this.makeOnLoad) {
  58. this.make();
  59. }
  60. },
  61. methods: {
  62. async make() {
  63. const options = {
  64. canvasId: this.cid,
  65. componentInstance: this,
  66. text: this.text,
  67. size: this.size,
  68. margin: this.margin,
  69. backgroundColor: this.backgroundImage
  70. ? 'rgba(255,255,255,0)'
  71. : this.backgroundColor,
  72. foregroundColor: this.foregroundColor
  73. };
  74. let filePath = await this.makeSync(options);
  75. if (this.backgroundImage) {
  76. filePath = await this.drawBackgroundImageSync(filePath);
  77. }
  78. if (this.logo) {
  79. filePath = await this.drawLogoSync(filePath);
  80. }
  81. this.filePath = filePath;
  82. this.makeComplete(filePath);
  83. },
  84. makeComplete(filePath) {
  85. this.$emit('makeComplete', filePath);
  86. },
  87. drawBackgroundImage(options) {
  88. const ctx = uni.createCanvasContext(this.cid, this);
  89. ctx.drawImage(this.backgroundImage, 0, 0, this.size, this.size);
  90. ctx.drawImage(options.filePath, 0, 0, this.size, this.size);
  91. ctx.draw(false, () => {
  92. uni.canvasToTempFilePath({
  93. canvasId: this.cid,
  94. success: res => {
  95. options.success && options.success(res.tempFilePath);
  96. },
  97. fail: error => {
  98. options.fail && options.fail(error);
  99. }
  100. });
  101. });
  102. },
  103. async drawBackgroundImageSync(filePath) {
  104. return new Promise((resolve, reject) => {
  105. this.drawBackgroundImage({
  106. filePath: filePath,
  107. success: res => {
  108. resolve(res);
  109. },
  110. fail: error => {
  111. reject(error);
  112. }
  113. });
  114. });
  115. },
  116. fillRoundRect(ctx, r, x, y, w, h) {
  117. ctx.save();
  118. ctx.translate(x, y);
  119. ctx.beginPath();
  120. ctx.arc(w - r, h - r, r, 0, Math.PI / 2);
  121. ctx.lineTo(r, h);
  122. ctx.arc(r, h - r, r, Math.PI / 2, Math.PI);
  123. ctx.lineTo(0, r);
  124. ctx.arc(r, r, r, Math.PI, (Math.PI * 3) / 2);
  125. ctx.lineTo(w - r, 0);
  126. ctx.arc(w - r, r, r, (Math.PI * 3) / 2, Math.PI * 2);
  127. ctx.lineTo(w, h - r);
  128. ctx.closePath();
  129. ctx.setFillStyle('#ffffff');
  130. ctx.fill();
  131. ctx.restore();
  132. },
  133. drawLogo(options) {
  134. const ctx = uni.createCanvasContext(this.cid, this);
  135. ctx.drawImage(options.filePath, 0, 0, this.size, this.size);
  136. const logoSize = this.size / 4;
  137. const logoX = this.size / 2 - logoSize / 2;
  138. const logoY = logoX;
  139. const borderSize = logoSize + 10;
  140. const borderX = this.size / 2 - borderSize / 2;
  141. const borderY = borderX;
  142. const borderRadius = 5;
  143. this.fillRoundRect(
  144. ctx,
  145. borderRadius,
  146. borderX,
  147. borderY,
  148. borderSize,
  149. borderSize
  150. );
  151. ctx.drawImage(this.logo, logoX, logoY, logoSize, logoSize);
  152. ctx.draw(false, () => {
  153. uni.canvasToTempFilePath({
  154. canvasId: this.cid,
  155. success: res => {
  156. options.success && options.success(res.tempFilePath);
  157. },
  158. fail: error => {
  159. options.fail && options.fail(error);
  160. }
  161. });
  162. });
  163. },
  164. async drawLogoSync(filePath) {
  165. return new Promise((resolve, reject) => {
  166. this.drawLogo({
  167. filePath: filePath,
  168. success: res => {
  169. resolve(res);
  170. },
  171. fail: error => {
  172. reject(error);
  173. }
  174. });
  175. });
  176. },
  177. async makeSync(options) {
  178. return new Promise((resolve, reject) => {
  179. uQRCode.make({
  180. canvasId: options.canvasId,
  181. componentInstance: options.componentInstance,
  182. text: options.text,
  183. size: options.size,
  184. margin: options.margin,
  185. backgroundColor: options.backgroundColor,
  186. foregroundColor: options.foregroundColor,
  187. success: res => {
  188. resolve(res);
  189. },
  190. fail: error => {
  191. reject(error);
  192. }
  193. });
  194. });
  195. }
  196. }
  197. };
  198. </script>