Search code examples
vue.jsvuejs2vuejs3migrationvue-component

Vue3: pass all $attrs to child but exclude listeners


Since $attrs and $listeners are now merged in Vue3, how to pass all $attrs to child except listeners?

In Vue2:

<child v-bind="$attrs"/>

But in Vue3 that also leaks listeners into the child which creates side effects like triggering events multiple times.

I still need to pass attributes, but not listeners. How do I do this?

So far I can add inheritAttrs: false, but then I need to parse $attrs manually and exclude everything that starts with "on + capital letter".

Any better way?


Solution

  • Now it starts to comes together.

    In addition to the merged listers and $attrs, Vue 3 also introduced a new emits property which solves exactly this issue - declare the events in your component that you don't want to fall through to the the root element.

    While the docs stated that there is the new "emits" option, it was never clear to me why would one need to use that option. But after running into this issue it all makes more sense now.

    And I've found a buried line in the docs that also confirms that:

    Note that the emits option affects which event listeners are considered component event listeners, rather than native DOM event listeners. The listeners for declared events will be removed from the component's $attrs object, so they will not be passed through to the component's root element. See Fallthrough Attributes for more details.

    Though if one passes events to grand children this approach assumes that all the chain of components should know and declare all the events that might be propagated back. Can't see a general solution to that with the current implementation yet.