我正在尝试从子组件向其父组件发出一个事件。我已经阅读了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