vue之v-model, sync浅析

311 阅读1分钟

最开始的vue是双向数据流的,后来改成了单向。 v-model, sync就是双向数据流的一个补充,且看到底是怎么回事吧。

v-model

特殊组件

<input v-model="dataValue" />

与下面等价

<input :value="dataValue" @input="handleInput" />
// 此处有省略,自己补全
methods: {
    /**
    * 事实上@input有一个默认方法,实现的功能如下
    * 除非你有一些自己的操作,需要重写默认方式
    * 下面这里是可以省略的
    */
    handleInput(val) {
        this.dataValue = val;
    }
}

自定义组件

<my-component v-model="dataValue" />
// 以下是<my-component ...>
props: ["value"]
template: "<div @click='handleClick(123)' />"
methods: {
    /**
    * 这是一个杜撰的方法,目的是告诉你@input需要手动emit
    * 这是跟input标签不一样的地方,因为input会自动emit
    */
    handleClick(val) {
        this.$emit("input", val);
    }
}

与下面等价

<my-component :value="dataValue" @input="handleInput" />
// 此处有省略,自己补全
methods: {
    /**
    * 事实上@input有一个默认方法,实现的功能如下
    * 除非你有一些自己的操作,需要重写默认方式
    * 下面这里是可以省略的
    */
    handleInput(val) {
        this.dataValue = val;
    }
}

对自定义组件的补充

// 引入自定义组件
<my-component v-model="dataValue" />

// 以下是<my-component ...>
// 注意:这里已经不是"value"了,照理讲应该是接收不到v-model的
props: ["myValue"] 
// 这里是关键,需要自己指定v-model的属性和事件名
model: {
    prop: "myValue",
    event: "myInput"
}
template: "<div @click='handleClick(123)' />"
methods: {
    /**
    * 因为v-model已经重置了事件名,这里也要修改到一致
    */
    handleClick(val) {
        this.$emit("myInput", val);
    }
}

与下面等价

<my-component :myValue="dataValue" @myInput="handleMyInput" />
// 此处有省略,自己补全
methods: {
    /**
    * 这里应该是v-model的自定义监听事件
    */
    handleMyInput(val) {
        this.dataValue = val;
    }
}

myValue.sync

自定义组件

// 引入自定义组件
<my-component :myValue.sync="dataValue" />

// 以下是自定义组件<my-component ...>
props: ["myValue"]
template: "<div @click='handleClick(123)' />"
methods: {
    /**
    * 这是一个杜撰的方法,目的是告诉你sync需要手动emit更新
    * 方法名:update:{valueFile} 此处是update:myValue
    */
    handleClick(val) {
        this.$emit("update:myValue", val);
    }
}

与下面等价

<my-component :myValue="dataValue" @update:myValue="handleUpdate" />
// 此处省略
methods: {
    handleUpdate(val) {
        this.dataValue = val;
    }
}

总结

v-model和sync修饰符都可以实现数据的双向同步,只是vue从代码层面断开了返回数据流,估计是考虑到了性能方面。如果需要实现也很简单,自己在需要的地方$emit一下就行了。