Vue.js 3: emit事件导致错误



我正在尝试从子组件向其父组件发出一个事件。我已经阅读了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]:渲染函数执行期间未处理的错误at

后跟一个'undefined'错误(见下文)。这在应用程序启动时就会发生,也就是说,没有触发click事件。

如果我从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似乎没有提供一个。

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

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组件没有接收任何道具,这将导致访问<script setup>内部道具时出现错误。

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

您可以定义一个默认属性,在没有传递属性时使用,或者在使用它之前检查prop是否未定义。

问题就在这里:

<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>

实际上有两个错误:首先,对Axislabel有两个调用,应该只有一个:

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

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

最新更新