vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
46.75k stars 8.2k forks source link

Incorrect v-bind merged result due to casting #11880

Open a161803398 opened 1 week ago

a161803398 commented 1 week ago

Vue version

3.5.3

Link to minimal reproduction

https://play.vuejs.org/#eNqtU01v1DAQ/SsjCylF2iYqcIpCpRb1UA5QsRVcfAnJZNetYxt/bLeK8t/xRza7iDbiwC2eeZN5b+bNQK6UyncOSUkq02imLBi0Tl1SwXoltYUfulbvoNOyhywv4isUZFRURarwWP+w2CteW/QvgCpV9c/nTHTyIyVr2SN8r7lDSqCIFSeo2wS6dhbslhl4kvpxws2o3flPJlqPGqaCErL7AK65kbEiAxinqqo4oUNWxJpGio5t8gcjhdc6hB9T0sheMY76q7JMCkNJCTETcjXn8ulzjFntcHWIN1tsHl+IP5h9iFFyp9Gg3nmhc87WeoM2pW/WX3Dvv+dkL1vHPXoh+Q2N5C5wTLBrJ1pP+wQX2d7GjTGxuTc3e4vCHEQFogE5Rjwlfn+fFqQf6b7PP8Q6KkY/xVDzilla7JjAOy2VOYv/mXY0gH1WWMLaas9rBRp/OaaxTZwiofHtspVatrscDkuHcayKEPl7x8EmF8teDgJmKx/UeCcn9tMozgZgYoua2StrtSmh8w7zVP+BZhpgFdscvR+Jge9RO+6nenTymzo0OBp9QVi8ueUjvfjjSOMk/r+01OilW0xXOqnMVpDnedI3H+VrCsffJGyGHA==

Steps to reproduce

  1. Create a component (Comp) with a two words prop 'myInfo'.
  2. Create a wrapper component (Wrap1) and pass default value with kebab-case and v-bind $attrs <Comp my-info="'Wrap1 default'" v-bind="$attrs" /> to first component.
  3. Create another wrapper component (Wrap2) and pass default value with camelCase <Wrap1 v-bind="{ myInfo: 'Wrap2 default'', ...$attrs }" /> to the first wrapper component.
  4. When using Wrap2, pass the prop with kebab-case <Wrap2 my-info="'Some value" /> will not show correct text.

Since $attrs will keep the casting, the root cause seems be the incorrect merge behavior when mixing kebab-case and camelCase.

What is expected?

Should render 'Some value'

What is actually happening?

Render 'Wrap2 default'

System Info

No response

Any additional comments?

No response

zh-lx commented 1 week ago

The cause of this bug is that during the execution of mergeProps, my-info="default 1" first adds my-info to props, then v-bind="{ myInfo: 'default 2', 'my-info': 'Some value' }" adds myInfo to props and updates the value of my-info (but does not change the order of the keys). During rendering, the keys in props are rendered in the order they were added. Since myInfo was added after my-info, the final rendered value is that of myInfo. Therefore, during the execution of mergeProps, the order of keys corresponding to later updates should always remain at the end. #11883