Kỹ thuật Tạo Poster Sản phẩm Động kèm Mã QR trên UniApp

Trong phát triển ứng dụng thương mại điện tử, yêu cầu tạo ảnh poster chia sẻ sản phẩm kèm thông tin người giới thiệu và mã QR là rất phổ biến. Giải pháp này yêu cầu frontend kết hợp dữ liệu từ backend, tự động sinh mã QR từ link sản phẩm, sau đó ghép nối hình ảnh và tải về dưới dạng file ảnh.

Để thực hiện, chúng ta cần tích hợp ba thư viện chính: qrcodejs2 để tạo mã QR, html2canvas để chuyển đổi DOM thành canvas, và file-saver để xử lý việc tải file.

1. Thiết kế Giao diện Popup

Sử dụng một component popup để hiển thị preview. Cấu trúc bao gồm vùng hiển thị ảnh nền, thông tin user và vùng chứa QR code. Cần định nghĩa rõ các ref để thư viện có thể truy xuất phần tử DOM.

<template>
  <u-popup 
    v-model="dialogVisible" 
    mode="center" 
    :width="650" 
    :height="80%"
    @close="handleClose"
    :closeable="true" 
    border-radius="15">
    <div class="poster-wrapper" id="posterContainer" ref="posterNode">
      <view class="preview-section" v-if="isGenerated">
        <image :src="finalImage" class="result-img" />
        <view class="action-btn" @tap="downloadFile">
          <image src="/static/icons/save.png" />
          <text>Lưu ảnh</text>
        </view>
      </view>
      <view class="editing-section" v-else>
        <view class="bg-layer"><image :src="backgroundSrc" /></view>
        <view class="info-layer">
          <view class="user-profile">
            <view class="avatar"> <image :src="userAvatar" /></view>
            <view class="details">
              <view class="name-role">
                {{ userProfile.nickname }}
                <text> Tư vấn viên</text>
              </view>
              <view class="contact">{{ userProfile.phone }}</view>
            </view>
          </view>
          <view class="qr-container" id="qrTarget" ref="qrBox">
            <div id="qrCanvas" ref="qrElement"></div>
          </view>
        </view>
      </view>
    </div>
  </u-popup>
</template>

2. Xử lý Logic Sinh Poster

Quy trình xử lý bao gồm: lấy danh sách poster, khi chọn item sẽ kích hoạt popup, sinh mã QR dựa trên URL sản phẩm, đợi DOM render xong rồi dùng html2canvas chụp lại vùng chứa và chuyển thành base64.

<script>
export default {
  data() {
    return {
      dialogVisible: false,
      marketingData: [],
      backgroundSrc: '',
      productLink: '',
      isGenerated: false,
      finalImage: '',
      userProfile: { nickname: '', phone: '', avatar: '' },
      renderTimer: null
    };
  },
  methods: {
    async fetchMarketingMaterials() {
      const res = await getListByParentCodes({ parentCodes: ["poster"] });
      this.marketingData = res.data.data.poster;
    },
    onPosterSelected(item) {
      this.dialogVisible = true;
      this.backgroundSrc = this.localHostImg;
      this.productLink = this.baseUrl + '#' + item.url;
      setStorageSync('poster_share_url', this.productLink);
      
      this.initQRCode(this.productLink);
      
      setTimeout(() => {
        this.captureCanvas();
        uni.showLoading({ title: 'Đang xử lý ảnh' });
      }, 300);
    },
    initQRCode(link) {
      const target = this.$refs.qrElement;
      if (!target) {
        this.renderTimer = setTimeout(() => {
          this.initQRCode(link);
        }, 300);
        return;
      }
      this.$nextTick(() => {
        new QRCode(this.$refs.qrElement, {
          width: 70,
          height: 70,
          text: link,
          correctLevel: QRCode.CorrectLevel.L,
          render: "canvas",
        });
      });
    },
    captureCanvas() {
      html2canvas(this.$refs.posterNode, {
        scrollY: 0,
        scrollX: 0,
        useCORS: true
      }).then(canvas => {
        uni.hideLoading();
        const base64Data = canvas.toDataURL("image/png").split(",")[1];
        this.finalImage = "data:image/png;base64," + base64Data;
        this.isGenerated = true;
      });
    },
    downloadFile() {
      if (!this.finalImage) {
        uni.$showMsg('Vui lòng đợi ảnh hoàn thành');
        return;
      }
      saveAs(this.finalImage, 'Poster_Chia_Se');
    },
    handleClose() {
      this.isGenerated = false;
      this.clearTimers();
    },
    clearTimers() {
      if (this.renderTimer) {
        clearTimeout(this.renderTimer);
      }
    }
  },
  beforeDestroy() {
    this.clearTimers();
  }
};
</script>

Thẻ: UniApp qrcodejs2 html2canvas file-saver vue-component

Đăng vào ngày 26 tháng 7 lúc 05:51