Custom events should not be permeable
Vue version
latest
Link to minimal reproduction
Steps to reproduce
- Click on the checkbox box
What is expected?
The content of the h1 tag should not be changed
What is actually happening?
The text in the h1 tag should not be bound to the value of the checkbox
System Info
No response
Any additional comments?
No response
Additional scenario: When I use component components, I often register events that are not generic, but may listen for unintended actions
options 1
defineEmit
on the "immediate" component (Comp
). so vue does not attach a native event listener.
options 2
guard native event in the consumer level, (in case you don't have control over Comp)
function onChange(event) {
if(event instanceof Event ) return
title.value = e.target.checked
}
The first sense is that the custom event is only applied to the current component and not triggered by the grandchild component due to the failure to declare defineEmit
<Comp @change="onChange" />
The change event should only be triggered by Comp
emit('change')
This doesn't match the first intuition, you guys are talking about a user-side solution, what I'm thinking is why would vue do that?
I jumped to the workarounds to save you some time,
you can check the docs to better understand what is expected from vue when you bind events to a component with a defined emit and without, and what is the difference between native event, and vue emitted "events".
if you are trying to push a new feature or change of spec, I wish you good luck.
Thank you for your replies. @lidlanca @KaelWD
I'm here to talk about an application scenario
<component :is="hit" @change="onChange" />
const hit = Comp1 || Comp2 || Comp3
It may be that Comp2
does not need to respond to this event, but it happens that there are elements in Comp2
that do respond to the change event
.
The user will find an unexpected response when handling onChange
and will have to spend time to find the problem.
I agree that this specific scenario is an easy pitfall to introduce a bug.
However it's documented behavior that we could only change in a major release, as far as I can see right now. Though I'd be interested in suggestions
For now, what we can do is to better document this pitfall in the docs about <component>
, so people are aware that they need to i.e. use a computed property to dynamically create an object with the right props and event listeners depending on the current component used in :is=
.
We could also consider an eslint rule maybe?
Thank you for your answer. @LinusBorg
I think it could be described clearly in the <component>
documentation that props and events should be calculated dynamically based on :is
and not set in stone.
If you can add eslint rules that would be even better.
In Vue 2, custom vs. native event listeners are separated via the .native
modifier.
In Vue 3:
- Listeners will capture both custom and native listeners if no
emits
ordefineEmits
are explicitly declared - A listener will only capture custom events if it's declared as custom only via
emits
Given that this is documented behavior, we cannot change how it works. It also means that when you attach an event listener to a component, you should not make the assumption that the event is only triggered by component custom events.
For the case discussed here - I think it's quite rare to attach an event listener on a dynamic component where not all possible components actually emit that event. When it happens, however, it could indeed be a pitfall. I'm not quite sure how Vue can change its behavior to avoid this without causing breaking changes.
I'm not quite sure how Vue can change its behavior to avoid this without causing breaking changes.
we can introduce modifiers to vue 3 (prefix).
The modifier can configure the type of binding ( native / emit ). additionally we can also introduce case sensitive modifier, that can solve https://github.com/vuejs/core/issues/5401 to escape the normalization and use event name as-is
to demonstrate the idea, we can look for a prefix that minimize possibility of breaking existing code:
<!-- auto -->
<div @Click=handler>1</div>
<!-- auto + case sensitive -->
<div @\Click=handler>2</div>
<!-- emit only -->
<div @@Click=handler>3</div>
<!-- emit only + case sensitive -->
<div @@\Click=handler>4</div>
<!-- native only -->
<div @^Click=handler>5</div>
<!-- native + case sensitive -->
<div @^\Click=handler>6</div>
Thank you for your replies. @lidlanca @KaelWD
I'm here to talk about an application scenario
<component :is="hit" @change="onChange" /> const hit = Comp1 || Comp2 || Comp3
It may be that
Comp2
does not need to respond to this event, but it happens that there are elements inComp2
that do respond to thechange event
.The user will find an unexpected response when handling
onChange
and will have to spend time to find the problem.
add emits to Comp2 if does not need to respond to this event. will there be some problems?
@lidlanca Adding more modifiers to covers these cases would be thinkable in theory, though I'd be hesitant to add more shorthands as it will make the template more and more cryptic.
This should likely be discussed in an RFC: github.com/vuejs/rfcs
I actually started a discussion in RFC