javascript - props - vue router
Vue: ¿Profundamente observando una serie de objetos y calculando el cambio? (4)
Tengo una matriz llamada
people
que contiene objetos de la siguiente manera:
antes de
[
{id: 0, name: ''Bob'', age: 27},
{id: 1, name: ''Frank'', age: 32},
{id: 2, name: ''Joe'', age: 38}
]
Puede cambiar:
Después
[
{id: 0, name: ''Bob'', age: 27},
{id: 1, name: ''Frank'', age: 33},
{id: 2, name: ''Joe'', age: 38}
]
Observe que Frank acaba de cumplir 33 años.
Tengo una aplicación en la que intento ver la matriz de personas y cuando alguno de los valores cambia, entonces registro el cambio:
<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>
Basé esto en la pregunta que hice ayer sobre las comparaciones de matrices y seleccioné la respuesta de trabajo más rápida.
Entonces, en este punto espero ver un resultado de:
{ id: 1, name: ''Frank'', age: 33 }
Pero todo lo que vuelvo a la consola es (teniendo en cuenta que lo tenía en un componente):
[Vue warn]: Error in watcher "people"
(found in anonymous component - use the "name" option for better debugging messages.)
Y en el codepen que hice , el resultado es una matriz vacía y no el objeto cambiado que cambió, que sería lo que esperaba.
Si alguien pudiera sugerir por qué está sucediendo esto o dónde me he equivocado aquí, sería muy apreciado, ¡muchas gracias!
Es un comportamiento bien definido.
No puede obtener el valor anterior para un objeto
mutado
.
Esto se debe a que tanto
newVal
como
oldVal
refieren al mismo objeto.
Vue
no
conservará una copia antigua de un objeto que haya mutado.
Si hubiera reemplazado el objeto por otro, Vue le habría proporcionado las referencias correctas.
Lea la sección de
Note
en los
documentos.
(
vm.$watch
)
Esto es lo que uso para mirar en profundidad un objeto. Mi requisito era mirar los campos secundarios del objeto.
new Vue({
el: "#myElement",
data:{
entity: {
properties: []
}
},
watch:{
''entity.properties'': {
handler: function (after, before) {
// Changes detected.
},
deep: true
}
}
});
He cambiado la implementación para resolver su problema, hice un objeto para rastrear los viejos cambios y compararlo con eso. Puede usarlo para resolver su problema.
Aquí creé un método, en el que el valor anterior se almacenará en una variable separada y, que luego se utilizará en un reloj.
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,
}
}
})
Ver el codepen actualizado
Su función de comparación entre el valor antiguo y el nuevo valor tiene algún problema. Es mejor no complicar tanto las cosas, ya que aumentará su esfuerzo de depuración más adelante. Deberías hacerlo simple.
La mejor manera es crear un
person-component
y observar a cada persona por separado dentro de su propio componente, como se muestra a continuación:
<person-component :person="person" v-for="person in people"></person-component>
A continuación encontrará un ejemplo de trabajo para ver el componente interno de la persona.
Si desea manejarlo en el lado primario, puede usar
$emit
para enviar un evento hacia arriba, que contenga la
id
de la persona modificada.
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/[email protected]/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>