问题
在调用SearchForm组件时,使用v-on={}的方式绑定事件,在SearchForm发现$listeners为空对象
<SearchForm v-on="{ search: handleSearch, reset: handleReset }" />
核心原因
Vue2 中这种对象形式的 v-on 绑定,默认不会把事件挂载到$listeners上,而是会被当作组件的 props / 属性处理,这是 Vue2 和 Vue3 在 v-on 语法上的关键差异,Vue3 已统一该行为。
解决方法
-
方案1: 改用 Vue2 标准的多事件分开绑定(最推荐)
<SearchForm @search="handleSearch" @reset="handleReset" /> -
方案2:SearchForm子组件通过 props 接收对象形式的绑定(适配你原来的父组件写法)
如果想保留父组件v-on="{ ... }"的写法,子组件需要把这些「伪事件」当作props 属性接收,再手动调用
<template> <div> <button @click="handleClickSearch">搜索</button> <button @click="handleClickReset">重置</button> </div> </template> <script> export default { // 接收父组件v-on对象中的方法作为props props: { search: { type: Function, required: true }, reset: { type: Function, required: true } }, methods: { handleClickSearch() { // 调用父组件传递的search方法,可传参 this.search({ keyword: 'test' }); }, handleClickReset() { // 调用父组件传递的reset方法 this.reset(); } } }; </script>注意:这种方式本质是传方法 props,并非 Vue 的「事件通信」,Vue 官方不推荐频繁这么做(props 更适合传数据,事件适合子向父通信)。
-
方案3:手动把$attrs中的方法挂载到listeners(进阶技巧,不推荐新手)
因为对象形式的 v-on 绑定会被放到$attrs中(Vue2 中,未被 props 接收的属性都会存在$attrs),所以可在子组件的created钩子中,手动把$attrs中的方法合并到$listeners,实现兼容:
<!-- 子组件 SearchForm.vue --> <script> export default { created() { // 把$attrs中的方法(父组件v-on对象绑定的)合并到$listeners Object.assign(this.$listeners, this.$attrs); // 此时打印$listeners就能拿到search和reset了 console.log(this.$listeners); // { search: fn, reset: fn } } }; </script>缺点:这种方式是「hack 技巧」,破坏了 Vue2 的原生设计,可读性差,后期维护容易出问题,非特殊场景
补充: Vue2 中 $listeners 的核心特性
- $listeners仅收集通过@事件名直接绑定的原生 / 自定义事件,不包含对象形式 v-on、v-bind 绑定的方法 / 属性;
- $listeners是只读对象,Vue2 中不能直接修改(如this.$listeners.search = fn无效),需通过Object.assign合并(方案 3 的原理);
- 可通过v-on="$listeners"将父组件的所有事件监听透传给子组件的内部元素(比如子组件中的 input、button),实现事件透传;
- Vue2.4 + 新增inheritAttrs: false,可阻止父组件的非 props 属性被渲染到子组件的根元素上,但不影响$attrs和$listeners的收集。
总结
- 核心原因:Vue2 中对象形式的v-on="{ ... }"不会挂载到$listeners,而是被当作组件属性放到$attrs中(Vue3 已修复该差异,对象形式 v-on 也会被收集到 emits/listeners);
- 最优解决方案:改用 Vue2 标准的@search="handleSearch" @reset="handleReset"分开绑定事件,符合 Vue2 的事件设计,子组件$listeners能正常收集;
- 临时适配方案:若想保留父组件写法,可让子组件通过props 接收方法,但这并非官方推荐的事件通信方式。

