vuejs vue props pass keep example data component alive javascript vue.js vuejs2

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 )

Más sobre esto here y here .


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>