在 vue 3 中,若未在子组件中显式声明 `emits: ['click']`,父组件绑定的 `@click` 会同时接收自定义事件和原生 dom 点击事件(含 `pointerevent` 对象),导致 `btnvalue[object pointerevent]` 的异常拼接。根本原因是事件未声明时,vue 无法区分自定义事件与原生事件冒泡。
这个问题的本质在于 Vue 3 的事件解析机制:当组件未通过 emits 选项声明自定义事件时,所有通过 this.$emit() 触发的同名事件(如 'click')不会被 Vue 视为“组件级事件”,而是与原生 DOM 事件混同处理。此时,父组件上写的 @click="handler" 实际会响应两件事:
由于两者事件名相同且未声明,Vue 默认将原生事件对象透传给父组件处理器,于是 value 实际变成了 event 对象,字符串拼接后就出现 btnValue[object PointerEvent] 这类错误输出。
✅ 正确做法是:在 Button.vue 中明确声明 emits: ['click'],让 Vue 知道这是一个受控的自定义事件,从而屏蔽原生 click 的冒泡干扰:
{{ btnValue }}
⚠️ 同时注意以下两点避免连锁问题:

{{ btnValue }}
对应地,ButtonPanel.vue 和 Calculator.vue 中的事件监听也需同步更新为 @append="addToExpression" 和 @append="updateExpression"。
? 总结:Vue 3 的 emits 选项不仅是文档提示,更是运行时事件过滤机制的核心。任何自定义事件都必须显式声明,否则将面临原生事件污染、类型不可控、调试困难等问题。养成 defineEmits([...]) + 语义化事件名的习惯,是构建健壮 Vue 组件的基础实践。