开发者问题收集

Vue.js 3:发出事件导致错误

2022-12-31
2076

我尝试从子组件向其父组件发出事件。我已阅读 vuejs.org 指南 并认为我的语法正确。我的子组件 (AxisLabel.vue) 有

<script setup>
  ....
  const emit = defineEmits(['removeLetter', 'submitLetter'])
  const props = defineProps({
    stat: Object,
    index: Number,
    segments: Number
  })
  const point = computed(() =>
  {
    try {
      return valueToPoint(props.stat.value - 10, props.index, props.segments, true)
    }
    catch {
      return valueToPoint(0, 0, 9, true)
    }
  })
  function click() {
    if (props.stat.chosen) {
        props.stat.chosen = false;
        emit('removeLetter',props.stat.label)
    }
    else {
        props.stat.chosen = true;
        emit('submitLetter',props.stat.label)
    }
  }
  ....
</script>

<template>
    <text @click="click" :class=changeColour() class="prevent-select"
        :x="point.x" :y="point.y">{{stat.label}}
    </text>
</template>

并且在父组件 (app.vue) 中我有:

<script setup>
import AxisLabel from './components/AxisLabel.vue'
const tryingWord = ref('word')

function addToWord(letter) {
  tryingWord.value = tryingWord.value + letter
}
function removeFromWord(letter) {
  // ....todo....
 
}
</script>

<template>

  <svg width="300" height="300">
    <PolyGraph :stats="stats"></PolyGraph>
  </svg>
  <text class="prevent-select" rows="1" cols="9">
        {{tryingWord}}
  </text>

  <AxisLabel @submit-letter = "addToWord"/>
  <AxisLabel @remove-letter = "removeFromWord"/>
 
</template>

当我运行此代码时,我得到

[Vue warn]: Unhandled error during execution of render function at <AxisLabel onSubmitLetter=fn > at

随后出现“未定义”错误(见下文)。应用程序启动后就会发生这种情况,即没有触发点击事件。

如果我从 app.vue 中删除事件侦听器定义,则不会发生错误。

[稍后] 我现在看到, 没有 定义事件侦听器,AxisLabel 的 <text> 元素被调用了 9 次(应该是这样的) - 它是从另一个组件调用的:

<axis-label
  v-for="(stat, index) in stats"
  :stat="stat"
  :index="index"
  :segments="stats.length-1">

并且“stats”有 9 个成员。但是当我重新添加事件监听器时,该元素会尝试创建 第十次 ,并使用无效参数,从而导致崩溃 - Chrome 调试器指示此处的“props”未定义:

<text @click="click" :class=changeColour() class="prevent-select"
    :x="point.x" :y="point.y">{{stat.label}}
</text>

“props”用于计算文本的位置,但在使用它的地方添加 try/catch 并没有帮助。

我需要查看在 vue 中发出事件的 有效 示例 - vuejs.org 似乎没有提供一个。

2个回答

您的事件处理程序函数内部有错误。我不确定这是否是问题所在,但可能是。

const tryingWord = ref('word')

function addToWord(letter) {
  // when working with refs, you need to use the .value property
  tryingWord.value = tryingWord.value + letter
}

此外,您永远不应像这里一样改变从 props 传递的数据:

function click() {
  if (props.stat.chosen) {
    // this mutates the props
    props.stat.chosen = false;
    emit('removeLetter',props.stat.label)
  }
  else {
    // this mutates the props
    props.stat.chosen = true;
    emit('submitLetter',props.stat.label)
  }
}

您将在 vue 文档 中找到有关单向数据流的解释。

更新

正如评论中提到的, AxisLabel 组件没有收到任何 props,这将导致在访问 <script setup> 内的 props 时出现错误。

// the following line will throw an error
// because props.stat === undefined
if (props.stat.chosen) {
  // ...
}

您可以定义一个在未传递任何属性时使用的默认属性,也可以检查 prop 是否在使用之前未定义。

Leif Marcus
2023-01-01

问题出在这里:

<template>
  <svg width="300" height="300">
    <PolyGraph :stats="stats"></PolyGraph>
  </svg>
  <text class="prevent-select" rows="1" cols="9">
        {{tryingWord}}
  </text>

  <AxisLabel @submit-letter = "addToWord"/>
  <AxisLabel @remove-letter = "removeFromWord"/>
</template>

实际上有 2 个错误:首先,对 Axislabel 的调用有 2 次,但应该只有一次:

<AxisLabel @submit-letter = "addToWord" @remove-letter = "removeFromWord"/>

其次,由于 Axislabel 是 PolyGraph 的子级,我需要将事件通过那里向上传播以到达 App.vue ,即这些事件处理程序应该在 PolyGraph.vue 中定义,而不是在 App.vue

quilkin
2023-01-02