You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue组合式API中props目标只读报错:组件传值异常

解决Vue组件props修改报错:Set operation on key "texteEnvoye" failed: target is readonly

这个错误的根源很明确:你在Visionneuse组件的watch回调里尝试直接修改从props转换来的ref,而props在Vue里是只读的,子组件不能直接修改父组件传递过来的props值。

看你代码里的这段watch逻辑:

watch(texte, (_, y) => {
  texte.value = y;
  initCarte();
});

这里的texte是通过toRefs(props)生成的,本质上还是绑定了父组件的texteEnvoye props。你在这里执行texte.value = y(把旧值重新赋值回去)完全没有必要,还触发了Vue的只读限制报错。

修复方案

只需要移除这个多余的赋值操作即可解决报错。如果后续子组件需要维护文本的本地修改状态,可以额外创建本地ref来承接props值,具体调整如下:

调整后的Visionneuse组件setup部分:

setup(props) {
  const myCanvas = ref(null);
  const carte = ref(null);
  // 创建本地ref承接props值,后续如需修改文本操作这个本地变量
  const localTexte = ref(props.texteEnvoye);
  const { taille } = toRefs(props);
  const rapport = ref(0);
  const petit = ref((window.innerWidth < 750));
  const size = reactive({
    w: window.innerWidth * taille.value,
    h: window.innerWidth * taille.value,
  });

  // 保留你的drawText、initCarte、handleResize函数,注意drawText里的文本要改用localTexte
  function drawText() {
    const fontSize = 0.05 * size.w - 10;
    myCanvas.value.font = `${fontSize}px Adrip`;
    myCanvas.value.textAlign = 'center';
    myCanvas.value.fillStyle = 'lightgrey';
    myCanvas.value.strokeStyle = 'black';
    myCanvas.value.lineWidth = 0.006 * size.w - 10;
    const x = size.w / 2;
    const lineHeight = fontSize;
    // 改用本地的localTexte
    const lines = localTexte.value.split('\n');
    for (let i = 0; i < lines.length; i += 1) {
      myCanvas.value.fillText(
        lines[lines.length - i - 1],
        x,
        (size.h * 0.98) - (i * lineHeight),
      );
      myCanvas.value.strokeText(
        lines[lines.length - i - 1],
        x,
        (size.h * 0.98) - (i * lineHeight),
      );
    }
  }

  function initCarte() {
    const background = new Image();
    background.src = '/img/fond.jpeg';
    background.onload = function () {
      rapport.value = background.naturalWidth / background.naturalHeight;
      size.h = size.w / rapport.value;
      nextTick(() => {
        try {
          myCanvas.value.drawImage(background, 0, 0, size.w, size.h);
        } catch (e) {
          console.log(`ERREUR DE CHARGEMENT D'IMAGE: ${e}`);
        }
        if (!petit.value) {
          drawText();
        }
      });
    };
  }

  function handleResize() {
    size.w = window.innerWidth * taille.value;
    size.h = size.w / rapport.value;
    petit.value = window.innerWidth < 750;
    initCarte();
  }

  window.addEventListener('resize', handleResize);
  
  // 监听props的文本变化,同步更新本地ref并重新绘制
  watch(() => props.texteEnvoye, (newVal) => {
    localTexte.value = newVal;
    initCarte();
  });

  onMounted(() => {
    const c = carte.value;
    const ctx = c.getContext('2d');
    myCanvas.value = ctx;
    initCarte();
  });

  return {
    myCanvas,
    size,
    localTexte,
    petit,
    carte,
  };
}

关键注意点:

  1. 永远不要直接修改props:props是单向数据流,父组件传递给子组件,子组件只能读取,不能修改。如果需要修改,要么通过emit通知父组件更新,要么在子组件内创建本地副本维护状态。
  2. 原watch里的赋值操作完全冗余,移除后即可解决当前报错;如果后续有子组件修改文本的需求,一定要用本地ref来承接props值。

内容的提问来源于stack exchange,提问作者djcaesar9114

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:40:21