V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
cstome
V2EX  ›  问与答

Vue 在 v-for 中通过 v-bind 绑定 class 在某些情况下无效的问题

  •  
  •   cstome · 2017-06-07 22:14:49 +08:00 · 7954 次点击
    这是一个创建于 2508 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大概 HTML:

    <div id="productSelect">
    	<li v-bind:class="{'active' : item.selected}" v-for="(item, index) in list" @click="selectItem(index)">{{item.name}}</li>
    </div>
    

    JS:

    var productChoice = new Vue({
    	el: "#productSelect",
    	data: {
    		list: []
    	},
    	created: function() {
    		this.loadDate();
    	},
    	methods: {
    		loadDate: function () {
    			//AJAX, 成功后传一个 Array 给 printProductList
    			this.printProductList(arr);
    		},
    		selectItem: function(i) {
    			this.list[i].selected = !(this.list[i].selected);
    		},
    		printProductList: function(arr) {
    			let list = [];
    			for(x in arr) {
    				//经过某从筛选,通过的 push 到 list
    				arr[x].selected = false; //每个条目中原先是没有 selected 这个属性的,这里加上去
    				list.push(arr[x]);
    			}
    			this.list = list;
    		}
    	})
            
    

    神奇的地方在于,如果直接写死 data.list 就能实现 class 的绑定,但是经过一系列处理之后赋值过去的 Array,虽然渲染得出来,但是通过点击来处理 class 的绑定就无效了。

    10 条回复    2017-06-10 12:06:06 +08:00
    ck65
        1
    ck65  
       2017-06-07 22:35:42 +08:00   ❤️ 1
    似乎没有发现描述中的情况,这种复现的对不? https://jsfiddle.net/589g0koo/5/
    SourceMan
        2
    SourceMan  
       2017-06-07 22:43:31 +08:00 via iPhone
    v-for in template block
    coo
        3
    coo  
       2017-06-08 09:18:22 +08:00   ❤️ 1
    你要使用 this.$set 来解决这个问题,直接更改变量是无法监听改变的。

    https://cn.vuejs.org/v2/guide/list.html#注意事项
    cstome
        4
    cstome  
    OP
       2017-06-09 16:41:41 +08:00
    @ck65 我仔细排查了一下,发现是这种情况就会: https://jsfiddle.net/589g0koo/6/
    这是为什么?
    cstome
        5
    cstome  
    OP
       2017-06-09 16:44:48 +08:00
    @ck65 上面链接不对,是 https://jsfiddle.net/589g0koo/7/
    ck65
        6
    ck65  
       2017-06-09 17:42:54 +08:00
    用 Vue.set() 方法,文档参考 #3 楼
    https://jsfiddle.net/589g0koo/8/
    cstome
        7
    cstome  
    OP
       2017-06-09 18:09:03 +08:00
    @ck65 我是在想将 arr 赋值给 list 跟 realList 是无关的,为什么会影响到?
    ck65
        8
    ck65  
       2017-06-09 18:59:51 +08:00
    「为什么会影响到」=> 什么影响到了什么?不太明白你的问题。
    19 行对 this.list 赋值之后没有任何地方使用 this.list,所以一直都在操作 this.realList,这两个 $data 属性扯不上关系。。

    问题的核心在于 arr 的元素属性是 Object,对它们直接追加 /删除属性是无法被 Vue 直接检测的,需要使用 Vue.set()、Vue.delete() 方法( 2.x )。参考 https://vuejs.org/v2/api/#Vue-set
    cstome
        9
    cstome  
    OP
       2017-06-10 02:03:12 +08:00
    @ck65 还是这个 jsfiddle.net/589g0koo/7/
    你把 19 行的赋值给删了,问题就不存在了。
    ```
    请不要在每一个回复中都包括外链,这看起来像是在 spamming
    ```
    V2EX 竟然说我是 spamming
    ck65
        10
    ck65  
       2017-06-10 12:06:06 +08:00
    哦,一定要存在这个 19 行的操作的话,改成这样即可 this.list = arr.map(item => Object.assign({}, item))

    你需要了解一下几个 JS 的关键特性(或许你已经了解,只当我提一下):变量赋值时的值传递和值引用的区别,Object 型引用赋值的坑,数组的深复制和浅复制。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   860 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 21:45 · PVG 05:45 · LAX 14:45 · JFK 17:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.