Vue3, Composition API и проблема с обновлением рисунка HTML Canvas

У меня есть кодовая база машинописного текста, в которой я создал рабочую доску судоку, просто работая с DOM напрямую и специально рисуя элемент HTML Canvas, используя его API.

Сейчас я хочу расширить свой проект до полноценного сайта и пытаюсь объединить то, что у меня уже есть, с проектом Vue3. Я использую Composition API с машинописным текстом. Я начал добиваться прогресса, но остановился на проблеме с обновлением доски.

Вот код для запуска моего компонента платы:

<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 — это написанный мной служебный класс, который содержит различные помощники рисования Canvas API.

Этот код работает при первой загрузке. Вызов manager.drawGrid(4, 4, 1, 'black') внутри onMounted работает и рисует сетку 4 на 4 на холсте.

Метод роста также увеличивает размер холста, и можно увидеть, как растет граница, однако вызов manager.drawGrid(4, 4, 1, 'black') внутри метода роста не имеет никакого эффекта. Сетка внутри границы исчезает и не перерисовывается.

Я использую Vue (любую версию) всего пару недель и сейчас не знаю, как заниматься отладкой.

Я не получаю никаких ошибок в консоли. Я добавил ведение журнала консоли к методу drawGrid в CanvasManager и вижу, что он определенно вызывается.

Любая помощь будет принята с благодарностью.

Ваше здоровье

я предполагаю, что vue перерисовывает, и, поскольку нет ссылки на то, что на самом деле происходит внутри vue, сетка не перерисовывается

Derek Pollard 22.12.2020 17:51

Большинство руководств с Vue, которые я видел для холста, похоже, перерисовывают весь холст всякий раз, когда что-то меняется и т. д.

Derek Pollard 22.12.2020 17:54

@DerekPollard Я слышу, что вы говорите, но удивляюсь, почему это работает в первый раз, поскольку это также внешний класс, выполняющий работу. Я мог бы попробовать переместить методы рисования внутри самого компонента платы.

ChromaticRanger 23.12.2020 12:38
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
3
5 700
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Vue снова отображает компонент всякий раз, когда происходит изменение данных, но это не означает повторного монтирования, и ваш холст готов только к рисованию 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();
});

Вот демо с некоторыми другими незначительными структурными улучшениями.

Другие вопросы по теме