Fabric.js 文本框调整大小和编辑可以在本地进行,但当 Canvas 存储在 Pinia 中时则不行

问题描述 投票:0回答:1

我正在使用 Fabric.js 和 Pinia 开发 Nuxt3 项目。我想使用 Pinia 商店全局管理 Fabric.js 画布实例。目标是使用商店中的操作将文本添加到画布。

但是,当直接在组件中添加 Fabric.Textbox 时,它可以完美运行(可调整大小和可拖动)。但是,当通过存储操作添加相同的文本框时,文本只能拖动但不能调整大小。

这是我到目前为止所拥有的:

Pinia Store (stores/canvasStore.js):

import { defineStore } from "pinia";
import * as fabric from "fabric";

export const useCanvasStore = defineStore("canvas", {
  state: () => ({
    canvas: null,
  }),

  actions: {
    setCanvas(canvasInstance) {
      this.canvas = canvasInstance;
    },

    addText(text = "New Text") {
      if (!this.canvas) return;

      const textbox = new fabric.Textbox(text, {
        left: 150,
        top: 200,
        fontSize: 24,
        fill: "black",
        width: 200,
        selectable: true,
        hasControls: true,
      });

      this.canvas.add(textbox);
      this.canvas.setActiveObject(textbox);
    },
  },
});

Canvas Initialization in Component (CanvasManager.vue):
<template>
  <canvas ref="canvasRef" class="border"></canvas>
<AddAddTextButton />
</template>

<script setup>
import { ref, onMounted } from "vue";
import * as fabric from "fabric";
import { useCanvasStore } from "@/stores/canvasStore";

const canvasRef = ref(null);
const canvasStore = useCanvasStore();

onMounted(() => {
  const canvas = new fabric.Canvas(canvasRef.value, {
    width: 800,
    height: 600,
    backgroundColor: "#fff",
  });

  canvasStore.setCanvas(canvas);
});
</script>

Add Text Button (AddTextButton.vue)
<template>
  <button @click="addTextToCanvas">Add Text</button>
</template>

<script setup>
import { useCanvasStore } from "@/stores/canvasStore";

const canvasStore = useCanvasStore();

const addTextToCanvas = () => {
  canvasStore.addText("Resizable Text");
};
</script>

当通过 store 调用 addText 方法时,文本框被添加但不能调整大小。如果我将相同的 Fabric.Textbox 逻辑直接移动到组件(商店外部),则调整大小效果完美。

工作示例:

<template>
  <div class="flex justify-center flex-col items-center">
    <canvas ref="canvasRef"></canvas>
    <button
      @click="addTextBlock"
      class="mt-4 px-4 py-2 bg-blue-500 text-white rounded"
    >
      Add Text Block
    </button>
    
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import * as fabric from "fabric";

const canvasRef = ref(null);
let canvas = null;

onMounted(() => {
  canvas = new fabric.Canvas(canvasRef.value, {
    width: 500,
    height: 500,
    backgroundColor: "lightgray",
  });
  canvas.renderAll();
});

const addTextBlock = () => {
  if (!canvas) return;

  const textbox = new fabric.Textbox("New Text Bzlocks", {
    left: 150,
    top: 200,
    fontSize: 30,
    fill: "black",
    width: 200,
  });

  canvas.add(textbox);
  
};
</script>

为什么通过 Pinia 商店添加文本框会破坏调整大小和编辑功能?我做错了什么

vue.js canvas nuxt.js fabricjs pinia
1个回答
0
投票

由于该商店仅在客户端使用(

onMounted
),因此 Nuxt SSR 部分不会产生任何影响。

这些片段并不等效,因为

let canvas
是非反应性对象,而 Pinia 存储是反应性的。让随机对象产生反应总是危险且无效的。反应式代理有开销,并且它们包装的对象不能保证正常工作。

要使

canvas
非反应性,可以将其设置为浅引用,这样可以避免在
state
中展开引用时它产生深度反应:

  state: () => ({
    canvas: shallowRef(null),
  }),

或者,可以将对象标记为非响应式,但这需要在每次属性分配时完成:

setCanvas(canvasInstance) {
  this.canvas = markRaw(canvasInstance);
},
© www.soinside.com 2019 - 2024. All rights reserved.