在vue中数据的流向通常是单向的,但是实际开发中,存在子组件对父组件值进行更新的情况,例如对表单组件进行二次封装等,父组件需要响应子组件的变化。双向绑定呼之欲出,vue提供了两种方法进行双向绑定:
Vue父子组件间数据的双向绑定

1、使用v-model指令

在父组件上 v-model 会利用子组件名为 value 的 prop 和名为 input 的事件,父组件上的值的变化通过 value 传递到子组件,子组件的变化通过 emit 触发 input 事件传递回去。

<template>
    <div id="app">
        <the-input v-model="name"></the-input>
        <div>这是你的名字:{{ name }}</div>
    </div>
</template>
<script>
import TheInput from './components/TheInput'
export default {
    components: {
        TheInput
    },
    data() {
        return {
            name: ''
        }
    },
};
</script>

子组件代码如下:

<template>
    <input v-model="name" type="text">
</template>
<script>
export default {
    name: 'TheInput',
    props: {
        value: {
            require: true
        }
    },
    computed: {
        name: {
            get: function () {
                return this.value;
            },
            set: function (value) {
                this.$emit('input', value)
            }
        },
    }
}
</script>

v-model 初衷是服务于表单元素,非表单元素在使用时,可以修改子组件的 model 属性的 prop 及 event,实现自定义 v-model 绑定的属性名和触发事件名。

<template>
    <input v-model="name" type="text">
</template>
<script>
export default {
    name: 'TheInput',
    model: {
        prop: 'pName',		// 默认值为value
        event: 'change'		// 默认值为input
    },
    props: {
        pName: {
            require: true
        }
    },
    computed: {
        name: {
            get: function () {
                return this.pName;
            },
            set: function (value) {
                this.$emit('change', value)
            }
        },
    }
}
</script>

2、使用.sync修饰符

除了 v-model 之外,vue 在数据绑定时提供了 .sync 修饰符,可以对需要双向绑定的属性进行标记,在子组件中可以通过 update:propName 事件子组件的值同步至父组件。

<template>
    <div id="app">
        <the-input :pName.sync="name"></the-input>
        <div>这是你的名字:{{ name }}</div>
    </div>
</template>
<script>
import TheInput from './components/TheInput'
export default {
    components: {
        TheInput
    },
    data() {
        return {
            name: ''
        }
    }
};
</script>

子组件:

<template>
    <input v-model="name" type="text">
</template>
<script>
export default {
    name: 'TheInput',
    props: {
        pName: {
            require: true
        }
    },
    computed: {
        name: {
            get: function () {
                return this.pName;
            },
            set: function (value) {
                this.$emit('update:pName', value)
            }
        },
    }
}
</script>

注:v-model 可以理解为 .sync 的语法糖

3、单向数据绑定实现

由于双向绑定存在不确定性,所以在使用的时候要格外小心,切记不可滥用双向绑定。那么在不使用官方提供的双向绑定,是不是就其他方案实现这种效果了?答案是有的,在单向数据流的基础上,只要在子组件修改了父组件值,就能达到双向绑定的效果。

这里总结三种方法:

注:不要和前面双向绑定的 emit 混淆,这里 emit 所触发的自定义事件需要显示定义,这样看来 vue 中的双向绑定更像是语法糖

发表回复