vue修改子组件传来的prop值

974 阅读2分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

概述

props 的值是单向下行传递的,父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

image.png

重新赋值法

实现思路:

在子组件的data中定义一个变量,将props接收到的数据重新赋值给这个变量,在页面显示时直接与此变量进行双向数据绑定。

代码

父组件

<template>
    <div>
        <div class="fatherBox">
            <h2>父组件</h2>
            <childTemp :data="showLabel"></childTemp>
        </div>
    </div>
</template>
<script>
    import childTemp from '../compontent/childTemp.vue'
    export default {
        components:{childTemp}
        data() {
            return {
                showLabel:'我是父组件的数据'
            }
        },
    }
</script>
<style scoped>
.fatherBox{
    width: 500px;
    height: 200px;
    margin: 30px auto;
    background:rgb(135, 135, 196);
}
</style>


子组件

<template>
    <div>
        <div class="childBox">
            <h2>子组件</h2>
            <h3>父组件传来的值-----------{{this.data}}</h3>
            <h3>子组件修改后的值---------{{this.showLabel}}</h3>
         </div>
    </div>
    
</template>
<script>
    export default {
        props:['data'],
        data() {
            return {
                showLabel: this.data,
            }
        },
        mounted() {
            this.showLabel = '我是子组件的数据'
        },
    }
</script>
<style scoped>
.childBox{
    width: 350px;
    height: 120px;
    margin: 30px auto;
    background: thistle;

}
</style>

显示如下:

image.png

.sync修饰符法

实现思路

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。所以官方推荐以 update:myPropName 的模式触发事件取而代之

众所周知Props是单向下行传递数据,所以我们可以将.sync修饰符理解为单向上行传递数据。

代码

父组件


<template>
    <div>
        <div class="fatherBox">
        <h2>父组件</h2>
        <childTemp v-bind:content.sync="showLable"></childTemp>
		<!-- // 一个组件上的 v-model默认对应其子组件的props的value -->
    </div>
    </div>
</template>
<script>
    import childTemp from '../compontent/childTemp.vue'
    export default {
        data() {
            return {
                showLable:'我是父组件的数据'
            }
        },
        components:{childTemp}
    }
</script>
<style scoped>
.fatherBox{
    width: 500px;
    height: 200px;
    margin: 30px auto;
    background:rgb(135, 135, 196);
}
</style>

子组件

<template>
    <div>
        <div class="childBox">
        <button @click="btnTest">我是子组件,{{ showlable }}</button>
    </div>
    </div>
    
</template>
<script>
    export default {
        data() {
            return {
                showlable: this.data,
            }
        },
        props:['data'],
        watch: {
            data(val) {
                this.showlable = val;
            }
        },
         methods: {
            btnTest() {
                this.showlable = '哈哈,在子组件中改变了父组件传递过来的数据';
                // 更新content值
                this.$emit('update:data',this.showlable);
            }
        },
    }
</script>
<style scoped>
.childBox{
    width: 350px;
    height: 120px;
    margin: 30px auto;
    background: thistle;

}
</style>


显示效果如下

image.png 点击后 image.png

.sync使用注意

注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model

将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。