people
다음과 같이 개체를 포함 하는 배열 이 있습니다.
전에
[
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
]
변경 될 수 있습니다.
후
[
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 33},
{id: 2, name: 'Joe', age: 38}
]
Frank가 방금 33 살이 된 것을보세요.
사람들 배열을 보려고하고 값이 변경되면 변경 사항을 기록하는 앱이 있습니다.
<style>
input {
display: block;
}
</style>
<div id="app">
<input type="text" v-for="(person, index) in people" v-model="people[index].age" />
</div>
<script>
new Vue({
el: '#app',
data: {
people: [
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
]
},
watch: {
people: {
handler: function (val, oldVal) {
// Return the object that changed
var changed = val.filter( function( p, idx ) {
return Object.keys(p).some( function( prop ) {
return p[prop] !== oldVal[idx][prop];
})
})
// Log it
console.log(changed)
},
deep: true
}
}
})
</script>
어제 어레이 비교에 대해 물어 본 질문을 기반으로 가장 빠른 응답을 선택했습니다.
따라서이 시점에서 다음과 같은 결과를 기대합니다. { id: 1, name: 'Frank', age: 33 }
그러나 내가 콘솔로 돌아가는 것은 (구성 요소에 있음을 염두에두고) 다음과 같습니다.
[Vue warn]: Error in watcher "people"
(found in anonymous component - use the "name" option for better debugging messages.)
그리고 내가 만든 코드 펜 에서 결과는 내가 예상했던대로 변경된 변경된 객체가 아니라 빈 배열입니다.
왜 이런 일이 발생했는지 또는 내가 여기서 잘못되었는지 제안 할 수 있다면 크게 감사하겠습니다. 많은 감사합니다!
답변
이전 값과 새 값 간의 비교 기능에 문제가 있습니다. 나중에 디버깅 노력을 증가 시키므로 일을 너무 복잡하게하지 않는 것이 좋습니다. 간단하게 유지해야합니다.
가장 좋은 방법은 person-component
아래와 같이 자체 구성 요소 내에서 모든 사람을 개별적 으로 만들고 관찰하는 것입니다.
<person-component :person="person" v-for="person in people"></person-component>
내부 사람 구성 요소를 관찰하는 작업 예제를 아래에서 찾으십시오. 부모 측에서 처리하려면 $emit
을 사용 하여 id
수정 된 사람을 포함하는 이벤트를 위쪽으로 보낼 수 있습니다 .
Vue.component('person-component', {
props: ["person"],
template: `
<div class="person">
{{person.name}}
<input type='text' v-model='person.age'/>
</div>`,
watch: {
person: {
handler: function(newValue) {
console.log("Person with ID:" + newValue.id + " modified")
console.log("New age: " + newValue.age)
},
deep: true
}
}
});
new Vue({
el: '#app',
data: {
people: [
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
]
}
});
<script src="https://unpkg.com/vue@2.1.5/dist/vue.js"></script>
<body>
<div id="app">
<p>List of people:</p>
<person-component :person="person" v-for="person in people"></person-component>
</div>
</body>
답변
문제를 해결하기 위해 구현을 변경했으며 이전 변경 사항을 추적하고이를 비교하는 개체를 만들었습니다. 문제를 해결하는 데 사용할 수 있습니다.
여기에서 이전 값이 별도의 변수에 저장되고 시계에서 사용되는 메서드를 만들었습니다.
new Vue({
methods: {
setValue: function() {
this.$data.oldPeople = _.cloneDeep(this.$data.people);
},
},
mounted() {
this.setValue();
},
el: '#app',
data: {
people: [
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
],
oldPeople: []
},
watch: {
people: {
handler: function (after, before) {
// Return the object that changed
var vm = this;
let changed = after.filter( function( p, idx ) {
return Object.keys(p).some( function( prop ) {
return p[prop] !== vm.$data.oldPeople[idx][prop];
})
})
// Log it
vm.setValue();
console.log(changed)
},
deep: true,
}
}
})
업데이트 된 코드 펜보기
답변
잘 정의 된 행동입니다. 변경된 개체에 대한 이전 값을 가져올 수 없습니다 . newVal
와 둘 다 oldVal
동일한 객체를 참조하기 때문 입니다. Vue는 변경 한 개체의 이전 복사본을 유지 하지 않습니다 .
개체를 다른 개체 로 교체 했다면 Vue가 올바른 참조를 제공했을 것입니다.
문서 의 Note
섹션을 읽으십시오 . ( vm.$watch
)
답변
이것은 내가 물체를 깊이 관찰하는 데 사용하는 것입니다. 내 요구 사항은 개체의 자식 필드를 관찰하는 것이 었습니다.
new Vue({
el: "#myElement",
data:{
entity: {
properties: []
}
},
watch:{
'entity.properties': {
handler: function (after, before) {
// Changes detected.
},
deep: true
}
}
});
답변
구성 요소 솔루션과 딥 클론 솔루션에는 장점이 있지만 다음과 같은 문제도 있습니다.
-
추상 데이터의 변경 사항을 추적하고 싶을 때가 있습니다. 해당 데이터를 중심으로 구성 요소를 구축하는 것이 항상 의미가있는 것은 아닙니다.
-
변경할 때마다 전체 데이터 구조를 딥 클로닝하는 것은 비용이 많이들 수 있습니다 .
더 나은 방법이 있다고 생각합니다. 당신이 목록에있는 모든 항목을보고 알고 싶은 경우에 있는 목록의 항목이 변경, 당신은 별도로 모든 항목에서 사용자 정의 전문가를 설정과 같이 할 수 있습니다 :
var vm = new Vue({
data: {
list: [
{name: 'obj1 to watch'},
{name: 'obj2 to watch'},
],
},
methods: {
handleChange (newVal) {
// Handle changes here!
console.log(newVal);
},
},
created () {
this.list.forEach((val) => {
this.$watch(() => val, this.handleChange, {deep: true});
});
},
});
이 구조를 사용하면 handleChange()
변경된 특정 목록 항목을 받게됩니다. 여기서 원하는대로 처리 할 수 있습니다.
또한 목록에 항목을 추가 / 제거하는 경우 (이미있는 항목 만 조작하는 것이 아니라) 더 복잡한 시나리오를 여기에 문서화했습니다 .