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

kho*_*ayr 3 javascript vue.js

我正在使用 vue.js 和 React,目前我正在尝试改编一本关于 React 的书中的一个简单的可编辑 HTML 表格示例,以便学习 Vue。

\n\n

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

\n\n
    \n
  1. 用户点击 td 元素
  2. \n
  3. td 元素的坐标存储在 rowSel、colSel 变量中
  4. \n
  5. 坐标变化导致Vue重新渲染视图
  6. \n
  7. 用户单击的 td 单元格添加了“contenteditable=true”属性,并添加了 focusout 事件监听器
  8. \n
  9. 然后,用户可以更改 td 单元格中的数据,然后单击单元格以停止编辑(触发焦点)
  10. \n
  11. 当用户单击单元格时, rowSel 和 colSel 变量将被重置,这会导致重新渲染
  12. \n
  13. vue 重新渲染视图,并且由于坐标被重置,Vue 应该从相关 td 元素中删除 contenteditable 和 focusout
  14. \n
  15. 然后,包含表格数据的数据数组将使用用户在单元格可编辑时输入的文本进行更新(尚未实现)
  16. \n
\n\n

我遇到的问题是第 7 步。我可以单击表格中的多个单元格,所有单元格中仍将设置 contenteditable="true"。如果您查看 Chrome 开发工具,您会发现 contenteditable 标签粘贴到所有被单击的单元格上。

\n\n

我相信问题的发生是因为我有嵌套的 for 循环,但我不确定如何正确地向它们添加键以使其正常工作。我尝试添加键,但我认为我做得不正确。

\n\n

JSFiddle:\n https://jsfiddle.net/o69yaq7L/

\n\n

这是代码:

\n\n

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

\n\n

编辑***

\n\n

问题出在这部分代码上:

\n\n

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

\n\n

有两个 v-for 循环和一个 if-else 语句。问题在于 if 语句使 td 元素具有 contenteditable=true 属性。一旦 td 元素获得该属性,该属性就永远不会离开,即使在进一步重新渲染之后,td 仍将设置 contenteditable=true,即使 if 语句的该部分不会再次影响该元素。我认为我使用 id 标签的方式有问题,但我不知道如何修复它。

\n

Sau*_*abh 5

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

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

请参阅更新的小提琴

\n

发生这种情况是因为 Vue 尝试尽可能高效地渲染元素,通常会重复使用它们而不是从头开始渲染。因为在您的情况下, if 和 else tempplace 使用相同的元素,因此不会被替换,只是它的单击事件。由于这并不是\xe2\x80\x99t 总是可取的,所以 Vue 提供了一种方式让你说,这两个元素是完全独立的 - 不要\xe2\x80\x99t 重复使用它们key,这可以通过添加属性来完成独特的价值观。

\n