vue生成二维码、多张图片合成海报、并能下载海报插件

实现效果

Poster.vue

<template>
  <div class="content-item">
    <div class="player-bottom-panel">
      <!-- 要生成海报的 -->
      <div
        class="creat-give-poster"
        ref="creatGivePoster"
        :style="{ backgroundImage: 'url(' + posterList.currentBg + ')' }"
      >
        <div class="poster-info">
          <div class="poster-avatar">
            <van-image :src="posterList.imageUrl" />
          </div>

          <div class="qr-icon">
            <vue-qr
              :logo-src="config.logo"
              :text="config.value"
              :margin="0"
              :size="90"
              class="player-bottom-panel-qrcode"
              style="opacity: 0"
            />
            <p class="poster-more">{{ posterList.pintitle }}</p>
            <p class="poster-more">{{ posterList.name }}</p>
          </div>
        </div>
        <!-- <i class="van-icon van-icon-close" @click="hideImg"></i> -->
      </div>

      <!-- 海报图片 -->
      <div v-if="isMargin" class="share-give-poster">
        <img class="poster-img" :src="imgUrl" alt="poster" />

        <!-- 保存海报按钮 -->
        <div class="saveBtn-box-m">
          <van-button
            v-if="isShow"
            type="primary"
            size="mini"
            @click="saveImg"
            class="save-btn"
          >
            {{ $t("scan.the.qr.code.press") }}
          </van-button>
          <div
            @click="saveImgLauch"
            v-if="posterList.showLauch"
            class="imgLauch"
          >
            <img src="../../assets/images/baocun_icon@2x.png" alt="" />Save
          </div>
          <div
            class="link imgLauch"
            v-if="posterList.showLauch"
            @click="copyWebsite"
          >
            <img src="../../assets/images/daochu_icon@2x.png" alt="" />Link
          </div>
        </div>
        <i class="van-icon van-icon-close" @click="hideImg"></i>
      </div>

      <!-- 遮罩 -->
      <div class="shadow-box"></div>
    </div>
  </div>
</template>

<script>
import VueQr from "vue-qr";
import html2canvas from "html2canvas";
import {
  saveSponsorPersonInfo,
  getSysConfig,
  base64ToMultipartBody,
} from "@/api/member";

export default {
  name: "Poster",
  components: { VueQr },
  props: {
    posterList: {
      type: Object,
      default: () => ({
        avatarImgUrl: "",
        currentBg: "",
        pintitle: "",
        checked: null,
        imageUrl: "",
        name: "",
        radio: "",
        showLauch: "",
      }),
    },
  },
  data() {
    return {
      //二维码参数
      config: {
        value: window.location.href, //显示的值、跳转的地址
        logo: "", //中间logo的地址
      },
      imgUrl: "", //最后转化出来的图片base64地址
      isMargin: false,
      isShow: false, //阴影和下载按钮的控制
      isLoading: false,
      coverImgUrl: "",
      vcardDistributor: {},
      website: "",
      websitePrefix: "",
    };
  },
  watch: {},
  created() {},
  mounted() {
    this.getPoster();
    this.vcardDistributor = JSON.parse(
      localStorage.getItem("vcardDistributor")
    );
    this.website = this.vcardDistributor.website;
    this.getShareLink();
  },
  activated() {},
  methods: {
    hideImg() {
      this.isMargin = false;
      this.isShow = false;
      this.$emit("update:isPosterLoading", false);
      this.$emit("update:isPoster", false);
      window.location.reload();
    },

    getShareLink() {
      let cc = this.$store.state.user.distributorInfo.companyCode,
        key = "vip.share.website.url";

      getSysConfig(key, cc).then((res) => {
        if (res.code === 0) {
          this.websitePrefix = res.data[key];
        }
      });
    },

    getPoster() {
      if (!this.websitePrefix || !this.website) {
        this.getShareLink();

        if (!this.vcardDistributor) {
          this.vcardDistributor = JSON.parse(
            localStorage.getItem("vcardDistributor")
          );
        }
        this.website = this.vcardDistributor.website;
        // 使用 setTimeout 确保异步操作完成后再执行 getPoster
        setTimeout(this.getPoster, 100);
        return;
      }
      this.isLoading = true;

      if (this.posterList.showLauch) {
        if (this.posterList.radio === "1") {
          this.config.value = this.websitePrefix + this.website;
        } else if (this.posterList.radio === "2") {
          this.config.value =
            this.websitePrefix + this.website + "&redirectPage=mypage";
        }
      }

      setTimeout(() => {
        //插件只能解决当前可视区域的 因此截图生成前需要先滚动到顶部 解决浏览器出现滚动条时截图不全bug
        window.pageYoffset = 0;
        document.documentElement.scrollTop = 0;
        document.body.scrollTop = 0;

        let shareContent = this.$refs.creatGivePoster; // 需要截图的包裹的(原生的)DOM 对象
        let width = shareContent.offsetWidth; // 获取dom 宽度
        let height = shareContent.offsetHeight; // 获取dom 高度
        let canvas = document.createElement("canvas"); // 创建一个canvas节点
        let scale = 1; //定义任意放大倍数 支持小数

        canvas.width = width * scale; // 定义canvas 宽度 * 缩放
        canvas.height = height * scale; // 定义canvas高度 *缩放
        canvas.getContext("2d").scale(scale, scale); // 获取context,设置scale

        let opts = {
          scale: scale, // 添加的scale 参数
          canvas: canvas, // 自定义 canvas
          // logging: true,                         // 日志开关,便于查看html2canvas的内部执行流程
          width: width, // dom 原始宽度
          height: height,
          windowWidth: document.body.scrollWidth, // 解决浏览器出现滚动条时截图不全bug
          windowHeight: document.body.scrollHeight, // 解决浏览器出现滚动条时截图不全bug
          useCORS: false, // 【重要】开启跨域配置
          backgroundColor: null,
          removeContainer: false,
        };

        this.$emit("update:isPosterLoading", true);
        this.$nextTick(() => {
          html2canvas(shareContent, opts)
            .then((canvas) => {
              this.$emit("update:isPosterLoading", false);
              let context = canvas.getContext("2d");
              // 【重要】关闭抗锯齿
              context.mozImageSmoothingEnabled = false;
              context.webkitImageSmoothingEnabled = false;
              context.msImageSmoothingEnabled = false;
              context.imageSmoothingEnabled = false;
              // 【重要】默认转化的格式为png,也可设置为其他格式
              this.imgUrl = canvas.toDataURL("image/png");

              const formData = {
                base64: this.imgUrl,
              };

              // base64转图片
              base64ToMultipartBody(formData).then((res) => {
                if (res.code === 0) {
                  this.coverImgUrl = res.data;
                }
              });
            })
            .catch(() => {
              this.$emit("update:isPosterLoading", false);
            });
        });
        this.isMargin = true;
        this.isShow = true;
        this.isLoading = false;
      }, 0);
    },

    saveImg() {
      // 移动端不进行保存操作
      // 引入插件
      if (!this.is_mobile) {
        let FileSaver = require("file-saver");
        // 保存base64图片 也有保存canvas方法 详情看文档
        FileSaver.saveAs(this.imgUrl, "poster");
      }
      const infoList = {
        coverUrl: this.imgUrl,
        storeName: this.vcardDistributor.storeName,
        website: this.vcardDistributor.website,
      };
      saveSponsorPersonInfo(infoList)
        .then((res) => {
          console.log(res);
          if (res.code == 0) {
            this.$toast.success("保存成功");
            this.vcardDistributor.coverUrl = this.imgUrl;
            localStorage.setItem(
              "vcardDistributor",
              JSON.stringify(this.vcardDistributor)
            );
            this.$store.dispatch(
              "user/setVcardDistributorData",
              this.vcardDistributor
            );
          } else {
            this.$toast.fail("保存失败");
          }
        })
        .catch((err) => {
          this.$toast.fail("保存失败");
        });
    },

    saveImgLauch() {
      if (!this.is_mobile) {
        let FileSaver = require("file-saver");
        // 保存base64图片 也有保存canvas方法 详情看文档
        FileSaver.saveAs(this.imgUrl, "poster");
      }
    },

    copyWebsite() {
      console.log(this.coverImgUrl);
      window.location.href = this.coverImgUrl;
    },
  },
  updated() {},
};
</script>

<style lang="scss" scoped>
.content-item {
  .creat-give-poster {
    background: url("../../assets/images/bg_photo@2x.png") no-repeat;
    background-size: cover;
    width: 6.5rem;
    height: 10rem;
    color: #fff;
    text-align: center;
    position: absolute; /* 不能fixed 否则就挂了 */
    top: 1rem;
    left: 0;
    right: 0;
    margin: auto;
    z-index: -200;

    .poster-avatar {
      margin: 0 auto;
      text-align: center;
      .van-image {
        height: 6.5rem;
        margin-top: 0.5rem;
      }
    }

    .qr-icon {
      display: flex;
      align-items: center;
      padding: 0.3rem;
      box-sizing: border-box;
      justify-content: space-between;
      position: absolute;
      bottom: 0;

      .poster-more {
        font-size: 0.6rem;
        padding: 0.2rem;
        word-break: break-all;
        max-height: 2.5rem;
        overflow: hidden;
      }

      .player-bottom-panel-qrcode {
        border: 0.1rem solid #fff;
        box-sizing: border-box;
      }
    }
  }

  .share-give-poster {
    width: 100%;
    height: 100%;
    margin-top: 1rem;
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 500;

    img {
      display: block;
      width: 6.5rem;
      height: 10rem;
      margin: 0 auto;
      margin-top: 0.6rem;
    }

    .van-icon-close {
      position: absolute;
      top: 0rem;
      right: 0rem;
      text-align: center;
      font-size: 24px;
      color: #fff;
    }
  }

  .saveBtn-box {
    position: absolute;
    right: -3.85rem;
    bottom: 0;
  }

  .saveBtn-box-m {
    position: absolute;
    bottom: 1rem;
    left: 50%;
    transform: translate(-50%, 0);

    .imgLauch {
      display: flex;
      width: 3.21rem;
      height: 0.97rem;
      border-radius: 0.3rem;
      border: 1px solid #000;
      justify-content: center;
      align-items: center;
      font-size: 0.34rem;
      margin: 0.03rem;
      img {
        width: 0.41rem;
        height: 0.41rem;
        margin: 0.24rem;
      }
    }
    .link {
      background-color: #0554b8;
      color: #fff;
      border: none;
      padding: 0.01rem;
    }
  }

  .el-button--medium {
    margin: 0 auto;
    display: block;
    padding: 0.1rem 0.385rem;
    font-size: 0.25rem;
  }

  .shadow-box {
    background: rgba(0, 0, 0, 0.7);
    position: fixed;
    width: 100%;
    height: 100vh;
    left: 0;
    top: 0;
    z-index: 66;
  }
}
</style>

使用

<template>
        <Poster
            :isPosterLoading.sync="isPosterLoading"
            :is_mobile="is_mobile"
            :posterList="posterList"
            :isPoster.sync="isPoster"
            v-if="isPoster"
        />
</template>

<script>
import Poster from "@/components/Poster";
export default {
  data() {
    return {
      posterList: {
        avatarImgUrl: "",
        currentBg: "",
        pintitle: "",
        checked: "",
        imageUrl: "",
      },
    }
  }
  components: {
    Poster 
 }
}
</script>

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

async.1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值