Vue3, Composition API & HTML Canvas 绘图刷新问题

Vue3, Composition API & HTML Canvas drawing refresh problem

我有一个 typescript 代码库,我在其中创建了一个工作的数独板,只是直接处理 DOM 并专门在 HTML Canvas 元素上使用它的 API.

我现在想将我的项目扩展到一个完整的站点,并且我正在尝试将我已有的内容合并到一个 Vue3 项目中。我正在使用 Composition API 和打字稿。我已经开始取得进展,但因面板刷新问题而停止。

这是我的 Board 组件的启动代码:

<template>
    <button @click="grow">Grow</button>
    <br><br>
    <div class="board">
        <canvas ref='myCanvas' :width="size.w" :height="size.h" tabindex='0' 
style="border:1px solid #000000;"
        ></canvas>
    </div>
</template>

<script lang="ts">

    import { defineComponent, onMounted, ref, reactive } from 'vue'
    import { CanvasManager } from '@/managers/canvasmanager'

    export default defineComponent({
        
        setup() {
                 
            let myCanvas = ref(null)
            let myContext = ref(null)
            let manager = ref(null)

            let size = reactive({
                w: 200,
                h: 200
            })

            function grow() {
                size.w += 10
                size.h += 10
                manager.drawGrid(4, 4, 1, 'black')
            }
            
            onMounted(() => {
                myContext = myCanvas.value.getContext('2d')
                manager = new CanvasManager(myContext, size.w, size.h)
                manager.drawGrid(4, 4, 1, 'black')
            })

            return {
                myCanvas,
                size,
                grow
            }
        }
    })
</script>

这里导入的 CanvasManager 是我写的一个实用程序 class,它包含各种 Canvas API 绘图助手。

此代码在首次加载时有效。 onMounted 中的 manager.drawGrid(4, 4, 1, 'black') 调用起作用并在 canvas.

上绘制一个 4 x 4 的网格

grow 方法也增加了canvas 的大小,并且可以看到边框在增长,但是在grow 方法内部调用manager.drawGrid(4, 4, 1, 'black') 没有效果。边框内的网格消失,不再重新绘制。

我只使用 Vue(任何版本)几个星期,我现在不确定如何进行调试。

我在控制台中没有收到任何错误。我已将控制台日志记录添加到 CanvasManager 中的 drawGrid 方法,可以看到它确实被调用了。

如有任何帮助,我们将不胜感激。

干杯

Vue 会在数据发生变化时重新渲染组件,但这并不意味着重新挂载,您的 canvas 只准备绘制 onMounted。所以当组件重新渲染节点时,之前的绘制就丢失了。解决此问题的一种快速方法是同时绘制 onUpdated

function draw() {
  myContext = myCanvas.value.getContext('2d')
  manager = new CanvasManager(myContext, size.w, size.h)
  manager.drawGrid(4, 4, 1, 'black')
}

onMounted(draw);
onUpdated(draw);

但我会通过不在每次渲染时都创建一个新的 CanvasManager 对象来进一步改进代码,这只能完成一次。

function draw() {
  manager.drawGrid(4, 4, 1, 'black')
}

onMounted(() => {
  myContext = myCanvas.value.getContext('2d')
  manager = new CanvasManager(myContext, size.w, size.h)
  draw();
});
onUpdated(() => {
  draw();
});

这是 demo 以及其他一些小的结构改进