深入理解vue单向数据流

2,969 阅读2分钟

官网解释

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

示例

我们通过一个示例来解释单向数据流与双向绑定,这个示例是对ant-design-vue表单组件的二次封装

a-input原始用法

<template>
    <a-input v-model='data'/>
</template>

<script>
export default {
    data() {
        return {
            data: ''
        }
    }
}
</script>

data中声明的属性会通过Object.definePropty方法为其添加getset方法,使其成为响应式数据。v-model是一个语法糖,在vue 2.2.0版本后新增了model属性

官方解释

允许一个自定义组件在使用 v-model 时定制 prop 和 event。默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

我们利用这个属性来对上述input组件做二次封装

组件代码

<template>
    <a-input :value='currentValue' @change='onInputChange'/>
</template>

<script>
export default {
    data() {
        return {
            currentValue: this.value
        }
    },
    
    model: {
        event: 'change',
        prop: 'value'
    },
    props:{
        value: {
            type: String
        }
    },
    watch: {
        value: {
            handler(newVal) {
                this.currentValue = newVal
            }
        }
    },
    
    onInputChange(e) {
        this.$emit('change', e.target.value)
    }
}
</script>

在父组件中使用

<template>
    <my-input v-model='data' />
</template>

<script>
export default {
    data() {
        return {
            data:''
        }
    }
}
</script>

上述子组件中的currentValue是实际input组件的值,他的值是根据父组件传入的值得出的,input标签组件的change事件来触发父组件的change事件,从而改变传入子组件propsvalue的值。这就解释了单项数据流,父組件通过props向子组件传递值,子组件通过emit事件来通知父组件修改值,子组件不在自身对父组件传递过来的props做任何修改,都是通过父组件来更新props,从而达到子组件更新自身状态。

使用场景

当我们在实现一个由数据渲染的复杂表单时,那么我们的设计就可以采用这种模式,通过props以及emit传递,保证子组件的事件触发根节点的数据更新,从而更新子孙组件的状态。