u-barcode.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <template>
  2. <view class="u-barcode" :style="[{
  3. width: $u.addUnit(barcodeWidth),
  4. height: $u.addUnit(barcodeHeight)
  5. },$u.addStyle(customStyle)]">
  6. <u-canvas
  7. ref="canvasRef"
  8. :width="barcodeWidth"
  9. :height="barcodeHeight"
  10. :customStyle="mode === 'image' ? 'position: absolute; left: -9999px; top: -9999px;' : ''"
  11. />
  12. <view class="u-barcode__image-wrapper" v-if="mode === 'image'">
  13. <image :src="imageUrl" class="u-barcode__image" mode="widthFix"/>
  14. </view>
  15. </view>
  16. </template>
  17. <script>
  18. import props from './props.js';
  19. import JsBarcode from './JsBarcode/JsBarcode.js';
  20. import mixin from '../../libs/mixin/mixin'
  21. import mpMixin from '../../libs/mixin/mpMixin';
  22. /**
  23. * Barcode 条形码组件
  24. * @description 支持生成条形码和二维码的组件,基于JsBarcode.js库
  25. * @tutorial https://uviewui.com/components/barcode.html
  26. *
  27. * @property {String} value 条形码内容
  28. * @property {String} type 条形码类型,支持code128、code39、ean13、qr等
  29. * @property {String|Number} width 条形码宽度
  30. * @property {String|Number} height 条形码高度
  31. * @property {String} color 条形码颜色
  32. * @property {String} backgroundColor 背景颜色
  33. * @property {Boolean} displayValue 是否显示文本
  34. * @property {String} textPosition 文本位置,top/bottom
  35. * @property {Object|String} customStyle 自定义样式
  36. * @property {String} fontOptions 字体选项
  37. * @property {String} font 字体
  38. * @property {String} textAlign 文本对齐方式,left/center/right
  39. * @property {Number} textMargin 文本边距
  40. * @property {Number} fontSize 字体大小
  41. * @example <u-barcode value="123456789" type="code128"></u-barcode>
  42. */
  43. export default {
  44. name: "u-barcode",
  45. mixins: [mpMixin, mixin, props],
  46. data() {
  47. return {
  48. ctx: null,
  49. barcodeWidth: null,
  50. barcodeHeight: null,
  51. textHeight: 30,
  52. imageUrl: '',
  53. }
  54. },
  55. watch: {
  56. value: {
  57. handler(newVal) {
  58. if (newVal) {
  59. this.generateBarcode()
  60. }
  61. }
  62. }
  63. },
  64. mounted() {
  65. this.$nextTick(() => {
  66. this.generateBarcode()
  67. })
  68. },
  69. methods: {
  70. // 生成条形码
  71. async generateBarcode() {
  72. const data = {};
  73. JsBarcode(data, this.value, {
  74. format: this.format,
  75. width: this.width,
  76. height: this.height,
  77. displayValue: false,
  78. });
  79. // 获取编码数据
  80. const encodings = data.encodings[0];
  81. if (!encodings) {
  82. return;
  83. }
  84. const { data: binaryData } = encodings;
  85. this.barcodeWidth = binaryData.length * this.width;
  86. this.barcodeHeight = this.height + (this.displayValue ? this.textHeight : 0);
  87. await this.initCanvas(binaryData);
  88. },
  89. // 初始化canvas
  90. async initCanvas(binaryData) {
  91. const { canvas } = await this.$refs.canvasRef.getCanvasContext();
  92. this.ctx = canvas;
  93. this.ctx.clearRect(0, 0, this.barcodeWidth, this.barcodeHeight);
  94. this.ctx.fillStyle = this.backgroundColor;
  95. this.ctx.fillRect(0, 0, this.barcodeWidth, this.barcodeHeight);
  96. this.drawBarcode(binaryData);
  97. },
  98. // 绘制条形码
  99. drawBarcode(binaryData) {
  100. const startX = 0;
  101. let startY = this.textPosition === 'top' ? this.textHeight : 0;
  102. // 绘制条形码
  103. this.ctx.fillStyle = this.color;
  104. let drawnBars = 0;
  105. for (let i = 0; i < binaryData.length; i++) {
  106. if (binaryData[i] === '1') {
  107. const x = startX + i * this.width;
  108. this.ctx.fillRect(x, startY, this.width, this.height);
  109. drawnBars++;
  110. }
  111. }
  112. // 绘制文本
  113. if (this.displayValue) {
  114. this.drawText();
  115. }
  116. this.ctx.draw(true, ()=>{
  117. if(this.mode === 'image') {
  118. this.getTempFile((tempFilePath)=>{
  119. this.imageUrl = tempFilePath;
  120. })
  121. }
  122. });
  123. },
  124. // 绘制文本
  125. drawText() {
  126. const text = this.value;
  127. const textColor = this.color;
  128. // 构建字体字符串
  129. let fontString = `${this.fontSize}px ${this.font}`;
  130. if (this.fontOptions) {
  131. fontString = `${this.fontOptions} ${fontString}`;
  132. }
  133. // 设置文本样式
  134. this.ctx.font = fontString;
  135. this.ctx.fillStyle = textColor;
  136. this.ctx.textAlign = this.textAlign;
  137. this.ctx.textBaseline = 'middle';
  138. // 计算文本位置
  139. let textX;
  140. if (this.textAlign === 'left') {
  141. textX = this.textMargin;
  142. } else if (this.textAlign === 'right') {
  143. textX = this.barcodeWidth - this.textMargin;
  144. } else {
  145. // center
  146. textX = this.barcodeWidth / 2;
  147. }
  148. let textY;
  149. if (this.textPosition === 'top') {
  150. // 文本在上方
  151. textY = this.fontSize / 2 + this.textMargin;
  152. } else {
  153. // 文本在下方
  154. textY = this.barcodeHeight - this.fontSize / 2 - this.textMargin;
  155. }
  156. // 绘制文本
  157. this.ctx.fillText(text, textX, textY);
  158. },
  159. getTempFile(callback) {
  160. this.$refs.canvasRef.canvasToTempFilePath({
  161. width: this.barcodeWidth,
  162. height: this.barcodeHeight,
  163. fileType: 'png',
  164. quality: 1,
  165. }).then((tempFilePath) => {
  166. callback(tempFilePath);
  167. }).catch((error) => {
  168. this.$emit('error', error);
  169. });
  170. },
  171. }
  172. }
  173. </script>
  174. <style lang="scss" scoped>
  175. @import "../../libs/css/components.scss";
  176. .u-barcode {
  177. position: relative;
  178. display: flex;
  179. flex-direction: row;
  180. align-items: center;
  181. justify-content: center;
  182. &__image {
  183. width: 100%;
  184. height: 100%;
  185. &-wrapper{
  186. width: 100%;
  187. height: 100%;
  188. }
  189. }
  190. }
  191. </style>