vue双向绑定数据的问题

这个问题有点复杂,首先,VM对象内有个类数组对象list,里面有两个类数组对象,arr1,arr2,这两个对象的关系是:

arr1=[{
    size: [{
                            value: '',
                            check: false,
                        }],
}];
arr2=[{
   spec: arr1,
    orther:...
}]

其中,我有对对象arr2的操作方法add1,对对象arr2的操作方法add2,即动态向arr1,arr2添加元素,同时,在页面上,有节点分别依靠arr1,arr2内的子元素循环渲染出来。
当arr2中的节点渲染出来后,在页面上看就类似一个表格,假设为tab,arr1的子元素为表格tab的列,arr2就为表格tab的行,问题就出在这里了:
已知每个对应的arr2[i]arr1[z]元素下都有一个下拉框,每个下拉框上绑定有方法change(i,z);change方法去找到对应坐标i,z下的子元素size的check,并改变check=!check;(其实就是找到arr2下对应点击的这个元素,并修改它下面的状态check,以便后面根据check状态来获取数据编组)。逻辑上change(i,z);arr2[i].spec[z].size[n]是能够改变对应的check的值的,控制台输出看也确实是改变了的,但是麻烦的就是不止arr2[i].spec[z].size[n]的check呗改变了,arr2下所有的spec[z].size[n]的check都呗改变了(假设添加了三行三列,如果触发了第一行第一列的change方法,第一行第一列对应的check值呗改变了,同时所有行第一列的check值都呗改变了)。。。。
希望我的叙述诸位能理解,不知道有没有大神能明白到底是为什么会出现这种情况。卡了两天了这毛病

我吧主要代码提出来了:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            ul,li{
                margin: 0;
                padding: 0;
            }
            input{
                height: 30px;
            }
            p{
                display: inline-block;
            }
            .l_g_btn{
                display: inline-block;
                background-color: #b3b3b3;
                line-height: 25px;
                margin: 0 15px;
            }
            td{
                border: 1px solid #b3b3b3;
            }
        </style>
    </head>

    <body>
        <div id="test">
            <div>
                <ul v-for="(item,index) in spec_list[0]">
                    <p class="flex_box"><label>名称:</label><input type="text" v-model='item.name' /></p>
                    <li v-for="(vo,num) in item.size">
                        <span>
                            <p class="flex_box"><label>数据:</label><input type="text" v-model="vo.value" /></p>
                        </span>
                        <em v-if='num==item.size.length-1' @click="add_item(index)">添加</em>
                        <em v-else @click="del_item(index,num)">删除</em>
                    </li>
                </ul>
                <span class="l_g_btn" @click="add_spec">添加新名称</span>
                <span class="l_g_btn" @click="add_spec_img">编辑表</span>
            </div>
            <div class="size_tab">
                表格
                    <table>
                        <thead>
                            <tr>
                                <td v-for="(item,index) in spec_list[0]">{{item.name}}</td>
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(vt,vi) in spec_list[1]">
                                <td v-for="(item,index) in vt.spec">
                                    <!--<div>
                                        <span @click="tiggle_check(vi,index)">{{item.size[0].value}}</span>
                                        <ul v-if='item.show'>
                                            <li v-for="(vo,ind) in item.size" @click="set_check(ind,vi,index)">{{vo.value}}</li>
                                        </ul>
                                    </div>-->
                                    <select @change="set_check($event,vi,index)">
                                        <option v-for="(vo,ind) in item.size" v-bind:value="vo.value">{{vo.value}}</option>
                                    </select>
                                </td>
                                <td><em class="l_g_btn" v-if="vi==spec_list[1].length-1" @click="add_spec_tab()">添加</em><em class="l_g_btn" v-else @click="del_spec_tab(vi)">删除</em></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
                <div class="s_m_item">
                    <div class="l_g_btn" @click="be_set">保存</div>
                </div>
        </div>
    </body>
    <script type="text/javascript" src="script/vue.js"></script>
    <script>
        var vm = new Vue({
            el: '#test',
            data: {
                spec_list: [], //记录规格数,默认为1(必填一组规格)
            },
            methods: {
                init: function() {
                    //初始化数据
                    var tmp = [{
                        name: '',
                        size: [{
                            value: '',
                            check: false,
                        }],
                    }, ];
                    vm.spec_list.push(tmp);
                },
                add_item: function(e) {
                    //添加一条数据
                    var info = {
                        value: '',
                        check: false,
                    }
                    vm.spec_list[0][e].size.push(info);
                },
                del_item: function(i, n) {
                    //删除一条数据
                    vm.spec_list[0][i].size.splice(n, 1);
                },
                add_spec: function() {
                    //添加一条数据组
                    var tmp = {
                        name: '',
                        size: [{
                            value: '',
                            check: false,
                        }],
                    };
                    vm.spec_list[0].push(tmp);
                },
                del_spec: function(e) {
                    //删除一条数据组
                    vm.spec_list[0].splice(e, 1);
                },
                add_spec_img: function() {
                    //编辑表格
                    if(vm.spec_list[0][0].name != '') {
                        var tmp = [{
                            spec: vm.spec_list[0],
                        }];
                        for(var i in vm.spec_list[0]) {
                            (function(i) {
                                vm.spec_list[0][i].size[0].check = true;
                            })(i)
                        }
                        vm.spec_list.push(tmp);
                        vm.showMask = true;
                    } else {
                        alert("请填写规格信息")
                    }
                },
                add_spec_tab: function() {
                    //添加一行表格
                    var tmp = {
                        spec: vm.spec_list[0],
                    };

                    vm.spec_list[1].push(tmp);
                },
                del_spec_tab: function(e) {
                    //删除一行表格
                    vm.spec_list[1].splice(e, 1);
                },
                set_check: function(e, v, d) {
                    //修改对应check值
                    /*这里是现在方法,出现增加行数无法动态渲染*/
                    var val = e.target.value;
                    var tmp = JSON.stringify(vm.spec_list[1]);
                    tmp = JSON.parse(tmp);
                    for(var i in tmp[v].spec[d].size) {
                        if(tmp[v].spec[d].size[i].value == val) {
                            tmp[v].spec[d].size[i].check = true;
                        } else {
                            tmp[v].spec[d].size[i].check = false;
                        }
                    }
                    vm.spec_list[1] = tmp;
                    /*这里是原方法,出现相同列下所有行的check值被修改*/
//                    for(var i in vm.spec_list[1][v].spec[d].size) {
//                        if(vm.spec_list[1][v].spec[d].size[i].value == val) {
//                            vm.spec_list[1][v].spec[d].size[i].check = true;
//                        } else {
//                            vm.spec_list[1][v].spec[d].size[i].check = false;
//                        }
//                    }
                        
                },
                be_set: function() {
                    //提交表单
                    var arr = [];
                    var size_list = [];

                    for(var i in vm.spec_list[1]) {
                        var tmp1 = [];
                        for(var k in vm.spec_list[1][i].spec) {
                            var tmp2 = [];
                            for(var c in vm.spec_list[1][i].spec[k].size) {
                                if(vm.spec_list[1][i].spec[k].size[c].check == true) {
                                    var s_tmp = {
                                        size: vm.spec_list[1][i].spec[k].size[c].value,
                                    }
                                    tmp1.push(s_tmp);
                                }
                            }
                        }
                        size_list.push(tmp1);
                    }
                    for(var i in vm.spec_list[1]) {
                        var tmp = {
                            size_list: size_list[i],
                        };
                        arr.push(tmp);
                    }
                    console.log(JSON.stringify(arr))
                },
            }
        })
        vm.init();
    </script>

</html>

现在的问题是,当我深拷贝一次arr2后,却无法动态添加节点了,如上代码可以直接运行查看效果。
ps:我实在不明白有些看客到底是怎样一个心态————你踩我的提问,如果是因为我的问题太幼稚,那么麻烦你绕路。如果是我的问题中有些观点你不赞同,那劳烦你指出,我也很荣幸能于君交流。亦或者是我的问题违规了,sf后台会屏蔽————这是一个交流的平台,都不是没事找事闲的蛋疼来唠嗑。总之,lz我遇到了困难,是诚恳的来向大家请教的。如果你的回答对我有帮助或者启发,我不吝点赞和采纳。

阅读 3.2k
5 个回答

我尝试看了很多遍,但还是无法清晰的理解,你是在动态生成tab吗?
我建议你用最精简的方式重新构建一个功能,看是否还是有问题,如果还有你可以贴上完成的代码再问问题。
不过我最近也在做动态表单我的结构是这样的。

//动态列
taskList:[
        {

            id: 'name',
            name: '名称',
            isShow: true,
            isSearch: true,
            placeholder: '请输入名称',
            type: 'text',
        },
        {

            id: 'createName',
            name: '创建人',
            isShow: true,
            isSearch: true,
            placeholder: '请输入创建人名称',
            type: 'text',
        },
        {

            id: 'status',
            name: '状态',
            isShow: true,
            isSearch: true,
            placeholder: '请选择状态',
            select: [
                {
                    value: '1',
                    label: '完成'
                },
                {
                    value: '2',
                    label: '呼叫中'
                },
                {
                    value: '4',
                    label: '呼叫失败'
                }
            ],
            type: 'select',
            value: ''
            }

    ]
//行数据
taskList = {
    page: {
        total: 2,
        size: 5,
        current: 1
    },
    list: [
        {
            id: 1,
            name: '房产筛选',
            createName: '小飞',
            callNumberGroup: '尚郡ICON',
            callType: '群呼',
            status: '呼叫中'
        },
        {
            id: 2,
            name: '车型',
            createName: '小黑',
            callNumberGroup: '尚郡ICON',
            callType: '群呼',
            status: '呼叫中'
        }
    ]
}

传点源代码吧,看描述不是太理解你的意思

看你说这么多,我猜测你对 “对象的引用” 不够了解。

看了启发

一下子明白问题所在:vm.spec_list[1].push(tmp);添加一行表格后,虽然数组对象内是有数据了,但是却没有触发更新。其核心问题是:因为 JavaScript 的限制,Vue.js 不能检测到数组变化...,总之,将vm.spec_list[1].push(tmp);修改为:Vue.set(vm.spec_list, 1,tmp);之后,就可以正常运行了(好了,领盒饭去了)。感谢热心宝宝

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题