canvas drawImage首次toDataURL值是data:,怎么解决?

场景是这样,一张整图切割成3x3的九宫格依次drawImage,实现一个拼图游戏。但是有这样一个问题,就是首次加载页面drawImage后toDataURL的值必定是data:,但是只要加载过一次有了缓存,就不出现这种情况了,这个要怎么解决。
这些事件我都是放在image.onload后的,确定已经加载好了图片

<template>
  <div class="jigsaw" @touchmove.prevent>
    <canvas
      v-show="false"
      ref="canvasRef"
      class="jigsaw-canvas"
      width="80"
      :height="canvasHeight"
    ></canvas>

    <div class="jigsaw-sudoku" ref="sudokuRef">
      <img :src="imgSrc" alt class="jigsaw-sudoku-reference" />
      <div class="jigsaw-sudoku-container">
        <div
          v-for="(item, index) in 9"
          :key="`sudoku_${index}`"
          class="jigsaw-sudoku-container-groove"
        >
          <img ref="sudokuItemRef" :id="`_${index}`" src="@/assets/cover.png" alt />
        </div>
      </div>
    </div>

    <ul class="jigsaw-selector" id="selector" ref="selectorRef">
      <li v-for="(item, index) in 9" :key="`selector_${index}`">
        <img ref="selectorItemRef" src alt draggable />
      </li>
    </ul>

    <button v-if="showStartButton" @click="actionToStart">开始</button>
    <div>用时:{{ differenceTime }}</div>
  </div>
</template>

<script>
import { polyfill } from 'mobile-drag-drop';
import { scrollBehaviourDragImageTranslateOverride } from 'mobile-drag-drop/scroll-behaviour';
export default {
  name: '',
  props: {},
  data() {
    return {
      imgSrc: require('@/assets/jigsaw.jpeg'),
      pieceWidth: 1, // 切片宽度
      pieceHeight: 1, // 切片高度
      ctx: undefined,
      selectorList: [],
      selectorArr: [],
      showStartButton: true,
      isCompleted: false,
      startDate: undefined,
      endDate: undefined,
      differenceTime: 0,
    };
  },
  computed: {
    canvasHeight () {
      return 80 * this.pieceHeight / this.pieceWidth
    }
 },
  created() {},
  mounted() {
    // 移动端适配
    polyfill({
      dragImageTranslateOverride: scrollBehaviourDragImageTranslateOverride,
    });
    this.onToInit();
  },
  watch: {},
  methods: {
    /* ----------------------行为触发函数------------------------ */
    // 开始拼图
    actionToStart() {
      this.showStartButton = false;
      this.startData = new Date().getTime();
    },

    // 结束拼图
    actionToComplete() {
      this.endDate = new Date().getTime();
      this.differenceTime = this.endDate - this.startData;
    },

    /* ----------------------内部处理函数------------------------ */
    // 初始化随机
    onToRandomImage() {
      this.selectorArr.sort(() => Math.random() - 0.5);
    },

    // 原图切片
    async onToRenderImage(image) {
      let index = 0;
      for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
          console.log(this.$refs.canvasRef.width, this.$refs.canvasRef.height)
          this.ctx.drawImage(
            image,
            this.pieceWidth * 2 * j,
            this.pieceHeight * 2 * i,
            this.pieceWidth * 2,
            this.pieceHeight * 2,
            0,
            0,
            this.pieceWidth,
            this.pieceHeight,
          );
          this.selectorArr[index].src = this.$refs.canvasRef.toDataURL('image/jpeg');
          this.selectorArr[index].id = index;
          index++;
        }
      }
    },

    // 拖动相关事件处理
    onToDrag() {
      const sudoku = this.$refs.sudokuRef;
      const selector = this.$refs.selectorRef;
      const _this = this;

      sudoku.addEventListener(
        'dragover',
        function(e) {
          e.preventDefault();
        },
        false,
      );

      sudoku.addEventListener(
        'dragenter',
        function(e) {
          e.preventDefault();
        },
        false,
      );

      selector.addEventListener(
        'dragstart',
        function(e) {
          const target = e.target;
          if (target.tagName.toLowerCase() == 'img') {
            e.dataTransfer.setData('id', target.id);
          }
        },
        false,
      );

      sudoku.addEventListener(
        'drop',
        function(e) {
          const target = e.target;
          if (target.tagName.toLowerCase() == 'img') {
            const originObj = document.getElementById(e.dataTransfer.getData('id'));
            const endObj = target;
            if (target.id === `_${e.dataTransfer.getData('id')}`) {
              [endObj.src, endObj.id, originObj.id] = [originObj.src, originObj.id, endObj.id];
              // 隐藏选项,不直接移除是为了保留内容撑开父高度
              originObj.parentNode.style.width = 0;
              originObj.parentNode.style.opacity = 0;
              originObj.parentNode.style.zIndex = -1;
              originObj.parentNode.style.margin = 0;
              // 判断进度
              const imageSequence = _this.$refs.sudokuItemRef;
              let arr = [];
              for (let i = 0; i < 9; i++) {
                arr.push(imageSequence[i].id);
              }
              if (arr.toString() === ['0', '1', '2', '3', '4', '5', '6', '7', '8'].toString()) {
                _this.isCompleted = true;
                _this.actionToComplete();
              }
            }
          }
        },
        false,
      );
    },

    // 加载原图
    onToLoadImage(imgSrc) {
      const image = new Image();
      image.src = imgSrc;
      this.pieceWidth = image.width / 6;
      this.pieceHeight = image.height / 6;
      image.onload = () => {
        this.onToRandomImage();
        this.onToRenderImage(image);
        this.onToDrag();
      };
    },

    // 初始化
    onToInit() {
      this.ctx = this.$refs.canvasRef.getContext('2d');
      this.selectorList = this.$refs.selectorItemRef;
      this.selectorArr = Array.from(this.selectorList);
      this.onToLoadImage(this.imgSrc);
    },

    /* ----------------------请求调用函数------------------------ */
    // 完成拼图,提交结果
    ajaxToSubmit() {},
  },
  components: {},
};
</script>

<style lang="less" scoped>
.jigsaw {
  &-sudoku {
    width: 246px;
    margin: 80px auto;
    overflow: hidden;
    position: relative;
    &-reference {
      width: 100%;
      object-fit: contain;
    }
    &-container {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: grid;
      grid-template-rows: 1fr 1fr 1fr;
      grid-template-columns: 1fr 1fr 1fr;
      &-groove {
        border: 1px solid #fff;
        > img {
          width: 100%;
          height: 100%;
        }
      }
    }
  }
  &-selector {
    display: flex;
    overflow-x: auto;
    > li {
      width: 80px;
      margin: 1px;
      position: relative;
      transition: all 0.3s ease-in;
      > img {
        width: 80px;
        object-fit: contain;
      }
    }
  }
}
</style>

其中cover.png只是一张半透明的黑块,用来做蒙层的

阅读 2.3k
1 个回答

https://www.w3school.com.cn/t... 这里,我写了一段代码来测试……
完全没有问题啊,所以我也不知道你到底遇到了啥问题。

<!DOCTYPE html>
<html>

<body>
    <p>要使用的图像:</p>
    <img id="tulip" src="/i/eg_tulip.jpg" alt="The Tulip" />

    <p>画布:</p>
    <canvas id="myCanvas" width="500" height="300" style="border:1px solid #d3d3d3;background:#ffffff;">
        Your browser does not support the HTML5 canvas tag.
    </canvas>

    <script>
        var img = document.getElementById("tulip");
        const source = new Image();
        source.src = img.src;
        source.onload = () => {
            const width = source.width / 3;
            const height = source.height / 2;
            console.log("xx", width, height);
            const c = document.getElementById("myCanvas");
            const ctx = c.getContext("2d");
            let i = 0;
            const timer = setInterval(() => {
                const y = Math.floor(i / 3);
                const x = i % 3;
                console.log("drawing", i, x, y);
                ctx.drawImage(
                    img,
                    x * width, y * height, width, height,
                    0, 0, width, height
                );
                console.log(c.toDataURL("image/png"));
                i++;
                if (i >= 6) {
                    clearInterval(timer);
                    console.log("done");
                }
            }, 1000);
        };

    </script>
</body>

</html>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题