简述html2canvas遇见的坑点及解决方案


theme: smartblue

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

前言

大家好,最近公司在做公众号的海报图生成功能,功能不难,但是其中也遇到了一些坑还有一些细节的问题,这里给大家复盘一下,相互借鉴及学习

制作海报选用工具

这里我看了几款生成图片的工具:

这里我选用的是html2canvas,因为大部分人使用这个比较多,而且我也只听过这个🤣,另一个大家可以去自行摸索,毕竟我看github上也有9k的star

image.png

开始使用插件生成

引入插件

// npm 下载插件
npm install html2canvas
// 项目引入插件
import html2canvas from 'html2canvas';

html2canvas的option配置

属性名 默认值 描述
allowTaint false 是否允许跨域图像。会污染画布,导致无法使用canvas.toDataURL 方法
backgroundColor #ffffff 画布背景色(如果未在DOM中指定),设置null为透明
canvas null 现有canvas元素用作绘图的基础
foreignObjectRendering false 如果浏览器支持,是否使用ForeignObject渲染
imageTimeout 15000 加载图像的超时时间(以毫秒为单位),设置0为禁用超时
ignoreElements (element) => false 谓词功能,可从渲染中删除匹配的元素
logging true 启用日志以进行调试
onclone null 克隆文档以进行渲染时调用的回调函数可用于修改将要渲染的内容,而不会影响原始源文档
proxy null 代理将用于加载跨域图像的网址。如果保留为空,则不会加载跨域图像
removeContainer true 是否清除html2canvas临时创建的克隆DOM元素
scale window.devicePixelRatio 用于渲染的比例。默认为浏览器设备像素比率
useCORS false 是否尝试使用CORS从服务器加载图像
width Element width canvas的宽度
height Element height canvas的高度
x Element x-offset 裁剪画布X坐标
y Element y-offset 裁剪画布X坐标
scrollX Element scrollX 渲染元素时要使用的x滚动位置(例如,如果Element使用position: fixed)
scrollX Element scrollY 呈现元素时要使用的y-scroll位置(例如,如果Element使用position: fixed)
windowWidth Window.innerWidth 渲染时使用的窗口宽度Element,这可能会影响媒体查询之类的内容
windowHeight Window.innerHeight 渲染时要使用的窗口高度Element,这可能会影响媒体查询之类的内容

调用html2canvas时传入两个参数,第一个参数是dom节点,第二个参数是options配置项(配置项可根据上方表格进行对应配置)

html2canvas(document.body).then(function(canvas) {
    document.body.appendChild(canvas);
});

调用方法生成海报

1.获取节点:let img = document.querySelector("#myImg");

2.配置需要参数:

let options = {
        useCORS: true,// 开启跨域
        backgroundColor: "#caddff",// 背景色
        ignoreElements: (ele) => {},// dom节点
        scale: 4,// 渲染出来的比例
      };

3.调用方法

html2canvas(img, options).then((canvas) => {
        let url = canvas.toDataURL("image/png"); // canvas转png(base64)
        this.url = url;
        this.isShow = false;
      });

到这里html2canvas的相关使用及配置就介绍完了,接下来就是遇见的问题

使用时遇见的坑点及解决方案

图片跨域问题

第一次用我就遇见了这个问题,第一个就是百度的方法,配置useCORS: true,// 开启跨域,然后图片标签上加crossorigin="anonymous",但是结果没用,图片依旧跨域,这时候咱们前端就要硬气一点,直接让后端处理,让后端把图片地址改成base64的形式传给你,或者服务器配置跨域

生成海报时图片模糊问题

生成海报如果模糊,建议把配置项的scale配置高一点,生成的canvas图片把盒子固定大小,显示的图片就更清晰

dom之间有一道横杠

本人是在公众号上做生成海报功能,dom元素顶部是两张图片,图片顶部有一道白线,而且两张图片之间还有一道杠(不好形容),后面发现是因为生成这个海报我在公众号上用的是image标签,改成img标签就没用影响了,具体原因应该是uniapp内部处理image标签时的一些样式问题吧,这是我的猜测

注意:app上不支持html2canvas生成海报(我也是调试的时候发现的)

全部代码

这里代码仅供大家参考

<template>
  <view class="poster-content">
    <view class="poster-img" id="myImg" v-if="isShow">
      <img class="flow" src="../../static/QC-code.png" />
      <view class="card-item">
        <view class="title-card">爽卡优势</view>
        <view class="tip-content">
          <view class="left">
            <p>零月租,随充随用,不用不扣费</p>
            <p>全程4G、不限APP、不限速</p>
            <p>支持多场景使用</p>
            <p>官方正品、品质保证</p>
          </view>
          <view class="right">
            <view class="right-item">
              <view class="qr-code">
                <img
                  id="codeImg"
                  :src="imgUrl"
                  style="width: 100%; height: 100%"
                  class="flow"
                  crossorigin="anonymous"
                />
              </view>
              <view style="color: #0032d0">扫码免费领取</view>
            </view>
          </view>
        </view>
      </view>
    </view>
    <view v-else class="canvas-img">
      <img style="width: 100vw" :src="url"  />
    </view>
    <view v-if="isShow" style="padding-bottom: 10px">
      <view @click="getImage" class="createPoster">点击生成海报</view>
    </view>
    <view style="padding-bottom: 50px">
      <view
        @click="close"
        class="createPoster"
        style="background-color: #fff; color: #4f80e6"
        >关闭</view
      >
    </view>
  </view>
</template>

<script>
import html2canvas from "html2canvas";
export default {
  props: {
    imgUrl: {
      type: String,
      default: "",
    },
    hasQrCode: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      url: "",
      isShow: true,
    };
  },
  onShow() {},
  methods: {
    close() {
      this.$emit("closePop");
    },
    getImage() {
      // this.saveImg()
      this.saveImg();
    },
    saveImg() {
      let img = document.querySelector("#myImg");
      let options = {
        useCORS: true,
        backgroundColor: "#caddff",
        ignoreElements: (ele) => {},
        scale: 4,
      };
      html2canvas(img, options).then((canvas) => {
        let url = canvas.toDataURL("image/png"); // canvas转png(base64)
        this.url = url;
        this.isShow = false;
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.poster-content {
  width: 100vw;
  background-color: #caddff;
  height: calc(100vh - 50px);
  overflow: scroll;
  margin-top: -50px;
}
.poster-img {
  width: 80vw;
  margin: 0 auto;
  background-color: #caddff;
  // display: flex;
  // flex-direction: column;
  padding: 40upx 20upx;
  text-align: center;
  .title {
    width: 203px;
    height: 96px;
  }
  .flow {
    width: 100%;
    height: 300px;
  }
  .card-item {
    background-color: #fff;
    font-size: 14px;
    margin-top: -12upx;
    padding: 20upx 0 40upx;
    text-align-last: left;
    border-radius: 20upx;
    .title-card {
      color: #0032d0;
      font-size: 36upx;
      font-weight: 700;
      padding-left: 10upx;
    }
    .tip-content {
      display: flex;
      justify-content: space-between;
      font-size: 26upx;
      .left {
        flex: 1;
        margin-top: 10upx;
        & > p {
          line-height: 1.5em;
          margin-top: 20upx;
          padding-left: 40upx;
          position: relative;
          &::after {
            content: "";
            position: absolute;
            top: calc(50% - 10upx);
            left: 8upx;
            width: 20upx;
            height: 20upx;
            border-radius: 20upx;
            background-color: #0256ff;
          }
        }
      }
      .right {
        width: 90px;
        font-size: 20upx;
        display: flex;
        align-items: center;
        padding-right: 16upx;
        .right-item {
          display: flex;
          flex-direction: column;
          justify-content: space-around;
          align-items: center;
          // height: 143px;
          .qr-code {
            width: 160upx;
            height: 160upx;
            background-color: #fff;
            border-radius: 10upx;
            display: flex;
            justify-content: center;
            align-items: center;
          }
        }
      }
    }
  }
  .canvas-img {
    width: 100vw;
    height: calc(100vh - 50px);
    overflow: scroll;
  }
}
.createPoster {
  line-height: 2.8em;
  width: 90%;
  background-color: #5479f7;
  margin: auto;
  border-radius: 40upx;
  color: #fff;
  text-align: center;
}
</style>

结尾

这些就是本人在做海报功能所遇见的一些问题及解决方案,希望掘友们相互学习共同进步,如果有什么描述错误的地方希望给我指正,欢迎大家跟我一起交流

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容