记一个Vue官方文档中关于修饰符.sync的坑

本文介绍了Vue 2.3中.sync修饰符的使用陷阱,指出官方文档的解释可能造成误解。通过示例代码展示了.sync与手动使用v-bind和v-on的差异,并强调了正确使用.sync的注意事项,包括事件命名和事件触发的条件。文章最后提出,.sync的实现可能涉及更复杂的内部机制,鼓励读者深入研究。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Vue官方文档“组件”一栏中提到,Vue在2.0移除了.sync,又在2.3重新添加了它,但是采用了全新的内部逻辑:

这次它只是作为一个编译时的语法糖存在。它会被扩展为一个自动更新父组件属性的 v-on 监听器。只有在子组件中显式传递一个名为update:变量名的自定义事件,父组件的相应变量才会被更新。

下面是坑:

Vue官方文档中对于最新版的.sync修饰符的原理解释如下:

如下代码
<comp :foo.sync="bar"></comp>
会被扩展为:
<comp :foo="bar" @update:foo="val => bar = val"></comp>

其实很好理解,就是简单的父组件的变量绑定给子组件的变量,子组件变量改变时通过事件提醒父组件更新。

为了进行实践,我写了以下demo,就是两个输入框,上面输入框的v-model绑定了父组件的变量parentMessage,下面的输入框的v-model绑定了子组件的变量myMessage,然后把父组件和子组件的两个变量通过.sync双向绑定:

<h1>写法1</h1>
    <div id="parent">
        <span>父组件</span>
        <input type="text" v-model="parentMessage">
        <br>
        <!---注意下面这行用的是.sync修饰符--->
        <child v-bind:my-message.sync="parentMessage"></child>
    </div>

以下是js部分:

Vue.component('child', {
            props: ['myMessage'],
            template: `<div>
            <span>子组件</span>
            <input type="text" v-model="myMessage">
            </div>`,
            watch: {
                myMessage: function() {
                    this.$emit('update:myMessage', this.myMessage);//请注意这一行的自定义事件名为update:myMessage
                }
            }
        })
var parent = new Vue({
            el: '#parent',
            data: {
                parentMessage: 'hello, child!'
            }
        })

以上代码运行一切正常,两个输入框任意改变一个的内容,另一个会相应改变。

但是,按照官方文档给出的说法,我把.sync改成v-bind和v-on两个属性后:

<h1>写法2</h1>
    <div id="parent1">
        <span>父组件</span>
        <input type="text" v-model="parentMessage">
        <br>
        <!---下面这行改成了v-bind和v-on的写法--->
        <child v-bind:my-message="parentMessage" v-on:update:my-message="myMessage => parentMessage = myMessage"></child>
    </div>

在父输入框中改变文本,子输入框中会相应改变,但是子输入框改变文本却不影响父输入框内容!也就是说父输入框并没有像我们想象的那样接收到update:myMessage事件。

此时,只有改变子组件向上传递的事件名才可以达到预期效果:

Vue.component('child', {
            //...
            watch: {
                myMessage: function() {
                    this.$emit('update:my-message', this.myMessage);//把这里的自定义事件名改为update:my-message后达到预期效果
                }
            }
        })
//...

由此可见,.sync的实现绝不仅仅是把它拆成那两个属性这么简单,官方文档这样解释应该只是为了通俗易懂地说明其原理。

以下为注意事项,具体内部原理日后慢慢发掘

  • 使用sync的时候,子组件传递的事件名必须为update:value,其中value必须与子组件中props中声明的名称完全一致(如上例中的myMessage,不能使用my-message)
  • .sync只是个语法糖,完全可以使用v-bind和v-on来实现相同的效果。这种情况下,就相当于父子组件的通信而已,v-on的事件可以随便取名字,没必要用update:value。因为html中大小写不敏感,如果在html中设置v-on:online-student,子组件中传递的事件名必须为online-student,不得采用驼峰命名法。
  • 官方文档写错了吧,上述二者不是单纯的换个写法这么简单。内部一定还有更深层次的不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值