通过按钮复制的模块,如何避免父子组件数据相互影响?

通过按钮复制的模块,如何避免父子组件数据相互影响,如图,普通平开门单门衣柜这个位置,是通过popup弹出的左右联动的动态数据,每点击一次添加按钮,都会动态复制一份forms组件内容,现在的问题是,无论修改第一组或者第二组的红色字体位置数据,另外一个就会跟着变成同样的数据,请教如何做到他们不相同可以独立操作数据?

img

<template>
    <view>
        <uni-forms v-for="(item,index) in sku" :key="index">
            <view class="items">
                <view>{{item.title}}</view>
                <view v-if="sku.length > 1" @click="deleteSku(index)">删除</view>
            </view>
            <view>
                <view>
                    <view class="box-body" @click="toggle('bottom')">
                        <view>{{it2}}->{{it3}}</view>
                    </view>
                    <view>
                        <uni-popup class="pop" ref="popup" @change="change">
                            <view class="popup-content"
                                :class="{ 'popup-height': type === 'left' || type === 'right' }">
                                <view class="content1">
                                    <view class="left">
                                        <scroll-view :scroll-y="true" :scroll-with-animation="true"
                                            :scroll-into-view="clickToId" :style="{'height':windowHeight}">
                                            <view v-for="(v,i) in sortarr" :key="i" v-if="v.grade1 === name">
                                                <view v-for="(item,i) in v.grade2" :key="i" @click="sg2(''+item.name)">
                                                    <view :class="['title',{active:i===currentNum}]" :id="'to'+i"
                                                        @click="setId(i)">
                                                        {{item.name}}
                                                    </view>
                                                </view>
                                            </view>
                                        </scroll-view>
                                    </view>
                                    <view class="right">
                                        <scroll-view :scroll-into-view="clickId" @scroll="scroll"
                                            :scroll-with-animation="true" :scroll-y="true"
                                            :style="{'height':windowHeight}">
                                            <view v-for="(v,i) in sortarr" :key="i" v-if="v.grade1 === name">
                                                <view v-for="(item,i) in v.grade2" :key="i">
                                                    <view class="title1,right_title" :id="'po'+i">---{{item.name}}---
                                                    </view>
                                                    <view v-for="(item,j) in item.grade3" :key="j">
                                                        <text class="item"
                                                            @click="sg3(''+item.name)">{{item.name}}</text>
                                                    </view>
                                                </view>
                                            </view>
                                        </scroll-view>
                                    </view>
                                </view>
                            </view>
                        </uni-popup>
                    </view>
                </view>
            </view>
            <view>
                <uni-file-picker limit="5"></uni-file-picker>
            </view>
        </uni-forms>
        <view>
            <button plain="true" @click="ad()">添加</button>
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                name: {},
                it3: "-",
                it2: "-",
                sku: [{
                    title: 1,
                    classify: {
                        it2: '-',
                        it3: '-'
                    },
                    image: []
                }],
            }
        },
        methods: {
            ad() {
                let number = this.sku[this.sku.length - 1].title;
                number++;
                const newsku = {
                    title: number,
                    classify: {},
                    image: []
                };
                this.sku.push(newsku);
            },
        },
    }
</script>

避免父子组件数据相互影响,需要保证所复制的模块是独立的。在你的情况下,复制的模块是一个包含表单和弹出框的popup组件,因此可能存在多个组件使用相同的popup模块的情况。

为了解决这个问题,你可以对复制的popup组件进行独立化处理,即弹出框中表单子组件所使用的属性数据需要通过props属性传递到popup组件中,popup组件再将这些数据传递到表单组件中,保证这些数据只在当前的popup组件和它的子组件之间存在。这种方法也称为props的单向数据流,即从父组件向子组件传递数据,而子组件无法直接修改父组件的数据。

具体来说,你可以按照如下步骤操作:

  1. 修改复制的popup组件属性,将弹出框中表单子组件所使用的属性数据定义为组件的props属性。

  2. 在表单组件中,接收popup组件传递的props数据,并根据自身的props属性进行渲染和操作。注意在表单组件中不要直接修改父组件中的数据,而是通过自己的props属性进行操作。

通过这种方式,你可以确保每个popup组件都有自己的一份props属性数据,保证数据的独立性。当需要修改数据时,只会影响当前组件,而不会影响其他组件,解决了你现在遇到的问题。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    回答:

    这个问题可以通过使用深拷贝来解决。深拷贝是一种将对象从源对象完全复制到新对象的方法,这将独立地创建一个新的对象,与原始对象没有联系。这样就可以在子组件中赋值给新对象,以避免父子组件数据相互影响。

    具体步骤如下:

    1. 在子组件中引入lodash库,并添加深拷贝方法
    import _ from 'lodash'
    
    ...
    
    let obj = { a: { b: 2 } };
    let copy = _.cloneDeep(obj);
    console.log(copy); // { a: { b: 2 } }
    console.log(copy === obj); // false
    
    1. 在点击按钮后,将要复制的对象进行深拷贝,并将其赋值给一个新的对象
    ...
    
    import _ from 'lodash'
    
    ...
    
    methods: {
        copyForm() {
            let newData = _.cloneDeep(this.form.data);
            // 这里使用Vue.set方法向对应的数组中添加元素,而不是直接使用push方法
            // 以保证新添加的元素也能够被Vue所监听
            this.$set(this.forms, this.forms.length, { data: newData });
        }
    }
    
    ...
    

    这样,每次复制的时候就会创建一个新的对象,与原始对象没有关系,即使修改其中一个对象的数据也不会影响到其他对象。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^