vue.js不更新嵌套v-for循环中的属性

时间:2016-12-07 12:00:25

标签: javascript vue.js

我正在玩vue.js并做出反应,而我正在尝试从一本关于React的书中调整一个简单的可编辑HTML表格示例,以便学习Vue。

以下是代码中发生的事情:

  1. 用户点击了td元素
  2. td元素的坐标存储在rowSel,colSel变量
  3. 坐标更改导致Vue重新渲染视图
  4. 用户点击的td单元格添加了“contenteditable = true”属性,并添加了focusout事件监听器
  5. 用户可以更改td单元格中的数据,然后单击关闭单元格以停止编辑(焦点触发)
  6. 当用户点击单元格时,会重置rowSel和colSel变量,从而导致重新渲染
  7. vue重新渲染视图,并且因为重置坐标,Vue应该从有问题的td元素中删除contenteditable和focusout
  8. 包含表数据的数据数组将使用用户在单元格可编辑时输入的文本进行更新(尚未实现)
  9. 我遇到的问题是第7步。我可以点击表格中的多个单元格,所有单元格中仍然会设置contenteditable =“true”。如果您查看Chrome开发工具,您会看到该可信标签粘贴到所有单击的单元格上。

    我认为问题正在发生,因为我有嵌套的for循环,但我不确定如何正确地添加密钥以使其工作。我试图添加密钥,但我认为我没有正确地做到这一点。

    的jsfiddle: https://jsfiddle.net/o69yaq7L/

    以下是代码:

    "use strict";
    
    var headers = [
        "Book", "Author", "Language", "Published", "Sales"
    ];
    
    var data = [
        ["The Lord of the Rings", "J. R. R. Tolkien", "English", "1954-1955", "150 million"],
        ["Le Petit Prince (The Little Prince)", "Antoine de Saint-Exupéry", "French", "1943", "140 million"],
        ["Harry Potter and the Philosopher's Stone", "J. K. Rowling", "English", "1997", "107 million"],
        ["And Then There Were None", "Agatha Christie", "English", "1939", "100 million"],
        ["Dream of the Red Chamber", "Cao Xueqin", "Chinese", "1754-1791", "100 million"],
        ["The Hobbit", "J. R. R. Tolkien", "English", "1937", "100 million"],
        ["She: A History of Adventure", "H. Rider Haggard", "English", "1887", "100 million"],
    ];
    
    var Excel = new Vue({
    	el: '#app',
    
    	data: {
    		colData: data,
    		headers: headers,		
    		colSel: -1,
    		rowSel: -1
    	},
    	methods: {
    		dataClick: function(ev){	
    			this.colSel = ev.target.cellIndex;
    			this.rowSel = ev.target.parentElement.rowIndex - 1;
    			Vue.nextTick( function(){
    				ev.target.focus();
    			});
    		},
    
    		lostFocus: function(ev){						
    			console.log(ev.target.textContent);
    			//var changedRow = this.colData.slice(this.rowSel,this.rowSel+1);
    			this.colSel = -1;
    			this.rowSel = -1;
    			console.log(this.colSel + " " + this.rowSel);
    			
    		}
    	}
    });
    <html>
    <head>
        <title>
            VUEJS Testing
        </title>
    </head>
    <body>
        <div id="app">        
            <table>
                <thead>
                    <tr>
                        <th v-for="item in headers" :key="item.id">{{item}}</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(row,rowInd) in colData"  :key="row.id">
                    	<template v-for="(item,colInd) in row"  >
                    		<template v-if="rowInd == rowSel && colInd == colSel">
                        		<td contenteditable="true" v-on:focusout="lostFocus" :key="item.id">{{item}}</td>
                        	</template>
                        	<template v-else>
                        		<td v-on:dblclick="dataClick">{{item}}</td>
                        	</template>
                        </template>
                    </tr>
                </tbody>
            </table>
        </div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.4/vue.min.js"></script>   
    </body>
    </html>

    EDIT ***

    问题在于代码的这一部分:

    <tr v-for="(row,rowInd) in colData" :key="row.id">
      <template v-for="(item,colInd) in row">
        <template v-if="rowInd == rowSel && colInd == colSel">
          <td contenteditable="true" v-on:focusout="lostFocus" :key="item.id">{{item}}</td>
        </template>
        <template v-else>
          <td v-on:dblclick="dataClick">{{item}}</td>
        </template>
      </template>
    </tr>

    有两个v-for循环和一个if-else语句。问题是if语句使td元素具有contenteditable = true属性。一旦td元素获得该属性,该属性永远不会离开,即使在进一步重新呈现之后,td仍将具有contenteditable = true集,即使if语句的该部分不再对该元素产生影响。我认为我使用id标签的方式存在问题,但我不确定如何修复它。

1 个答案:

答案 0 :(得分:3)

你必须为if / else语句提供不同的键,如下所示:

<tr v-for="(row,rowInd) in colData"  :key="row.id">
    <template v-for="(item,colInd) in row"  >
        <template v-if="rowInd == rowSel && colInd == colSel">
            <td contenteditable="true" v-on:focusout="lostFocus" :key="item.id"  key="key1">{{item}}</td>
        </template>
        <template v-else>
            <td v-on:dblclick="dataClick" key="key2">{{item}}</td>
        </template>
    </template>
</tr>

查看更新的fiddle

这种情况正在发生,因为Vue尝试尽可能高效地渲染元素,通常重新使用它们而不是从头开始渲染。因为在你的情况下,if和else templace使用相同的元素,不会被替换,只是它的click事件。虽然这并不总是令人满意,因此Vue提供了一种方式,您可以通过添加key属性和唯一值来完成These two elements are completely separate - don’t re-use them