我有一个对象数组(数组1),可以将其切换到另一个数组(数组2)。添加后,用户可以选择为每个选项键入一个文本字段。切换工作正常,并且在初始创建时具有反应性。但是,如果我有数组2中已经存在的数据,则该项目不再是反应性的。
我做了一个快速的jsfiddle来演示:事件1和3是反应性的,但事件2不再存在,因为它已经存在于newEvents数组中。无论如何,可以将其与原始事件联系起来吗?
new Vue({
el: "#app",
data: {
events: [
{ id: 1, text: "Event 1"},
{ id: 2, text: "Event 2"},
{ id: 3, text: "Event 3"}
],
savedEvents: [
{ id: 2, text: "Event 2", notes: 'Event Notes'}
]
},
methods: {
toggleEvent: function(event){
let index = this.savedEvents.findIndex(e => e.id == event.id);
if (index != -1) {
this.savedEvents.splice(index, 1);
} else {
this.savedEvents.push(event);
}
},
inArray: function(id) {
return this.savedEvents.some(obj => obj.id == id);
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.btn {
display: inline-block;
padding: 5px;
border: 1px solid #666;
border-radius: 3px;
margin-bottom: 5px;
cursor: pointer;
}
input[type=text]{
padding: 5px;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Events:</h2>
<ol>
<li v-for="event in events">
<span class="btn" @click="toggleEvent(event)">
{{ event.text }}
</span>
<input type="text" placeholder="Type your note here..." v-model="event.notes" v-if="inArray(event.id)">
</li>
</ol>
<h2>
Saved Events:
</h2>
<ul>
<li v-for="event in savedEvents">
<strong>{{ event.text }}</strong> {{ event.notes }}
</li>
</ul>
</div>
答案 0 :(得分:0)
尝试使用<dependencies>
和$set
来避免失去反应性
答案 1 :(得分:0)
这里的问题与反应性无关。
通过单击按钮将事件添加到newEvents
时,它使用的是与events
中的对象相同的对象。由于每个事件只有一个对象,所以一切正常。
对于事件2 ,您从两个代表同一事件的单独对象开始,一个在events
中,另一个在newEvents
中。更改一个不会更改另一个。
在不知道选择这些数据结构的动机的情况下,很难说出合适的解决方案是什么,但是下面的示例确保了两个数组在事件2 中都包含相同的对象。
我对原始代码所做的唯一更改是data
函数。
new Vue({
el: "#app",
data () {
const data = {
events: [
{ id: 1, text: "Event 1"},
{ id: 2, text: "Event 2", notes: 'Event Notes'},
{ id: 3, text: "Event 3"}
],
newEvents: []
}
data.newEvents.push(data.events[1])
return data
},
methods: {
toggleEvent: function(event){
let index = this.newEvents.findIndex(e => e.id == event.id);
if (index != -1) {
this.newEvents.splice(index, 1);
} else {
this.newEvents.push(event);
}
},
inArray: function(id) {
return this.newEvents.some(obj => obj.id == id);
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.btn {
display: inline-block;
padding: 5px;
border: 1px solid #666;
border-radius: 3px;
margin-bottom: 5px;
cursor: pointer;
}
input[type=text]{
padding: 5px;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Events:</h2>
<ol>
<li v-for="event in events">
<span class="btn" @click="toggleEvent(event)">
{{ event.text }}
</span>
<input type="text" placeholder="Type your note here..." v-model="event.notes" v-if="inArray(event.id)">
</li>
</ol>
<h2>
New Events:
</h2>
<ul>
<li v-for="event in newEvents">
<strong>{{ event.text }}</strong> {{ event.notes }}
</li>
</ul>
</div>
除了使用两个相同对象的列表之外,还有多种方式可以表示此数据。您可以在对象内使用布尔标志。或者,您可以使用一个单独的对象来保存笔记,并以事件ID为键。很难知道哪种方案最适合您的情况。
更新:
基于注释,您可以执行以下操作,以在加载events
时将savedEvents
中的对象用作规范版本:
loadSavedEvents () {
// Grab events from the server
someServerCall().then(savedEvents => {
// Build a map so that the objects can be grabbed by id
const eventMap = {}
for (const event of this.events) {
eventMap[event.id] = event
}
// Build the list of server events using the objects in events
this.savedEvents = savedEvents.map(savedEvent => {
const event = eventMap[savedEvent.id]
this.$set(event, 'notes', savedEvent.notes)
return event
})
})
}
答案 2 :(得分:0)
如@skirtle所指出,列表数组中的对象需要被推入第二个数组以使其具有反应性。我已经解决了这个问题,方法是循环遍历并匹配id,然后将该对象推入第二个数组。不确定这是否是最好/最有效的方法,但现在可以使用。
new Vue({
el: "#app",
data: {
eventsList: [
{ id: 1, text: "Event 1"},
{ id: 2, text: "Event 2"},
{ id: 3, text: "Event 3"}
],
savedEvents: [
{ id: 2, text: "Event 2", notes: 'Event Notes'}
]
},
mounted() {
this.init();
},
methods: {
init: function() {
let _temp = this.savedEvents;
this.savedEvents = [];
_temp.forEach(event => {
this.eventsList.forEach(x => {
if (event.id == x.id) {
this.$set(x, "notes", event.notes);
this.savedEvents.push(x);
}
});
});
},
toggleEvent: function(event){
let index = this.savedEvents.findIndex(e => e.id == event.id);
if (index != -1) {
this.savedEvents.splice(index, 1);
} else {
this.savedEvents.push(event);
}
},
inArray: function(id) {
return this.savedEvents.some(obj => obj.id == id);
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.btn {
display: inline-block;
padding: 5px;
border: 1px solid #666;
border-radius: 3px;
margin-bottom: 5px;
cursor: pointer;
}
input[type=text] {
padding: 5px;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Events:</h2>
<ul>
<li v-for="event in eventsList">
<span class="btn" @click="toggleEvent(event)">
{{ event.text }}
</span>
<input type="text" placeholder="Type your note here..." v-model="event.notes" v-if="inArray(event.id)">
</li>
</ul>
<h2>
Saved Events:
</h2>
<ul>
<li v-for="event in savedEvents">
<strong>{{ event.text }}</strong> {{ event.notes }}
</li>
</ul>
</div>