如何添加一个新的数字(字符串)键并将其余键移动 +1 而不会破坏 Vuejs 数据中的反应性
Posted
技术标签:
【中文标题】如何添加一个新的数字(字符串)键并将其余键移动 +1 而不会破坏 Vuejs 数据中的反应性【英文标题】:How to add a new numerical (string) key and shift the rest by +1 without breaking reactivity in Vuejs data 【发布时间】:2020-01-04 16:42:00 【问题描述】:我有一个 Vue 组件,它将以下内容构建到博客表单字段中。在构建博客文章时,作者可以创造性地在彼此之间添加/插入任何选择字段......(如:标题、段落、块引用、图像)在如下对象中:
"post":"1":"title":"name":"","intro":"","2":"paragraph":"text":"","fontweight":"default-weight","bottommargin":"default-bottom-margin","3":"image":"class":"default-image-class","creditto":"","4":"subheading":"text":"","size":"default";
我尝试使用 jQuery each 进行迭代并将其添加到 makedo "dataObj" 对象中并将其注入数据:
data: treeData: myUserData.post ,
injectFieldType: function(type, position)
var storeObj = ;
var dataObj = this.treeData;
var crntKey;
$.each( dataObj, function( key, value )
if(key < position)
//remain same as key is not to change
else if(key == position)
dataObj[''+(parseInt(key)+1)] = dataObj[key]; /*push key further right with +1*/
dataObj[key] = /*add injected field here*/;
else if(key > position)
dataObj[''+(parseInt(key)+1)] = dataObj[key]; /*push the rest*/
);
当它注入所需的键时,用(this.treeData = dataObj;)
将其注入回来,并在单击时通过在它们的键上加 1 来移动其余部分:
<button type="button" v-on:click="injectFieldType('image','2')">
我需要 "post":"1":"title":"name":"","intro":"","2":"image":"class":"default-image-class","creditto":"","3":"paragraph":"text":"","fontweight":"default-weight"....
当我尝试在现有的“名称”和“段落”字段之间注入图像字段并将段落键现在设为 3(而不是旧的 2)时。
我希望"1:foo, 2:bar"
变成 => "1:foo, 2:moo, 3:bar"
(注意 3 更改密钥)
注意:需要编号顺序才能在发布时可靠地对齐它们。并且data: treeData: myUserData.post
需要同意更改以允许创建字段并更新每个表单“名称”属性数组。
【问题讨论】:
Vue.set(dataObj, ''+(parseInt(key)+1), dataObj[key])
请注意,关键(如您上面使用的)不是属于整个对象集,而是属于每个字段
【参考方案1】:
这里有几个问题需要解决。
首先,尝试使用var dataObj = this.treeData;
然后this.treeData = dataObj
不会有帮助。 dataObj
和 this.treeData
都引用同一个对象,并且该对象已经被 Vue 的反应系统处理。您可以通过创建一个全新的对象来解决反应性问题,但仅仅为现有对象创建一个别名并没有帮助。
在我的示例中,我选择使用this.$set
,而不是创建一个新对象。对于大多数属性来说,这不是必需的,只有最后添加的新属性才真正需要它。但是,考虑到我选择使用的算法,单独挑出一个属性会不必要地复杂。
另一个潜在的问题是确保所有数字都作为数字而不是字符串进行比较。在您的示例中,您将position
作为字符串'2'
传递。诸如<
之类的运算符将为您提供高达9
的数字的预期答案,但是一旦treeData
中的项目数达到10
,您可能会开始遇到问题。对于字符串比较,'2' < '10'
是 false
。
下一个问题是您移动条目的顺序。在您当前的算法中,您将使用条目 key
覆盖条目 key + 1
。但这意味着您丢失了条目key + 1
的原始值。您最终只会将相同的条目一直复制到最后。有两种方法可以解决此问题。一种是使用一个新对象来保存输出(这也有助于解决反应性问题)。在下面的解决方案中,我选择通过键向后迭代。
new Vue(
el: '#app',
data ()
return
newEntry: 'Yellow',
newIndex: 4,
treeData:
1: 'Red',
2: 'Green',
3: 'Blue'
,
computed:
treeDataLength ()
return Math.max(...Object.keys(this.treeData))
,
methods:
onAddClick ()
const newIndex = Math.round(this.newIndex)
if (newIndex < 1 || newIndex > this.treeDataLength + 1)
return
this.injectFieldType(this.newEntry, newIndex)
,
injectFieldType (type, position)
const list = this.treeData
for (let index = this.treeDataLength + 1; index >= position; --index)
if (index === position)
this.$set(list, index, type)
else
this.$set(list, index, list[index - 1])
)
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
<ul>
<li v-for="index in treeDataLength">
index. treeData[index]
</li>
</ul>
<input v-model="newEntry">
<input v-model="newIndex">
<button @click="onAddClick">Add</button>
</div>
使用带有数字键的对象的决定似乎很奇怪。如果你只使用一个数组,这一切都会容易得多。
【讨论】:
您的回答向我揭示了我的代码中的缺陷。我已经尝试过了,它工作得很好。我希望重构我的以遵循您上面使用的模式。以上是关于如何添加一个新的数字(字符串)键并将其余键移动 +1 而不会破坏 Vuejs 数据中的反应性的主要内容,如果未能解决你的问题,请参考以下文章