Vue - Излучение объекта данных, но изменение одного, изменяет их все - PullRequest
2 голосов
/ 20 апреля 2020

У меня есть приложение TODO, и я хочу передать реквизиты из одного компонента в другой массив объектов. Объект добавляется каждый раз, когда вы нажимаете кнопку, но у меня возникают проблемы с ней. Проблема в том, что значение свойства становится одинаковым для каждого объекта, добавляемого в массив. Похоже, что он не сохраняет правильно все данные tareas.tarea.

Приложение. vue

<template>
  <div>
    <Header></Header>
    <AgregarTarea @tareaAgregada="agregarTarea"></AgregarTarea>
    <div class="container">
      <div class="columns">
        <div class="column">
          <Lista :tareas = 'tareas' @eliminarItem="eliminarTarea"></Lista>
          <!-- here i pass through props the array of objects -->
        </div>
        <div class="column">  
          <TareaFinalizada></TareaFinalizada>
          {}
        </div>
      </div>
    </div>
  </div>
</template>

<script>

import Header from './components/Header'
import AgregarTarea from './components/AgregarTarea'
import Lista from './components/Lista'
import TareaFinalizada from './components/TareaFinalizada'

export default {
  data(){
    return {
      tareas:[]
    }
  },
  components: {
    Header,
    AgregarTarea,
    Lista,
    TareaFinalizada
  },
  methods: {
    agregarTarea(data){
     //add new object to the array
      this.tareas.push(data)
    },
    eliminarTarea(data) {
      this.tareas.splice(data.id, 1);
    }
  }

};
</script>

AgregarTarea. vue || Вот где я могу добавить новый ToDo

<template>
    <div class="container">
        <input class="input" type="text" placeholder="Text input" v-model="tareas.tarea">
        <button class="button is-primary" @click="agregarTarea">Agregar Tarea</button>
    </div>
</template>

<script>

export default {
    data(){
        return {
            tareas: {
                tarea:'',
                id:null,
                editar:false
            }
        }
    },
    methods: {
        agregarTarea(){
            this.$emit('tareaAgregada', this.tareas)
            this.tareas.tarea = ' ';
        }
    }
}

</script>

Lista. vue || И вот где я показываю ToDo's

<template>
    <div>
        <div class="list is-hoverable">
            <ul>
                <li v-for="(tarea, index) in tareas" :key="index">
                    <a class="list-item has-text-centered" @click="editarTexto(index)">
                        {{ tarea }}
                        <div class="editar" v-if="editar">
                            <input class="input" type="text" placeholder="Text input" v-model="nuevaTarea">
                        </div>
                    </a>
                    <button class="button is-danger" @click="eliminarItem(index)">Eliminar</button>
                    <div><input type="checkbox"> Finalizada</div>
                </li>
            </ul>
        </div>
    </div>
</template>

<script>
export default {
    props:['tareas'],
    data(){
        return {
            nuevaTarea: ' ',
            editar:false,
        }
    },
    methods: {
        eliminarItem(index){
            this.$emit('eliminarItem', index)
        },
        editarTexto(){
            this.editar = true
        }
    }
}
</script>

<style scoped>

</style>

1 Ответ

2 голосов
/ 21 апреля 2020

JavaScript объекты передаются по ссылке (не клонируются по значению). Каждый раз, когда вы $emit объект tareas из AgregarTarea. vue, это та же ссылка на объект, что и раньше, даже если свойства изменились. Таким образом, все объекты в вашем массиве tareas в App. vue являются одним и тем же объектом.

Чтобы исправить это, измените AgregarTarea. vue $emit клон каждый раз:

methods: {
    agregarTarea(){
        this.$emit('tareaAgregada', Object.assign({}, this.tareas)) // clone
        this.tareas.tarea = ' ';
    }
}

(Это мелкий клон, и он не будет работать должным образом, если this.tareas имеет вложенные объекты, но это не так.)


Опция # 2

Вот другой способ, который легко работает для вложенных объектов:

new Vue({
  el: "#app",
  data(){
    return {
      tareas: null  // <-- It's not filled here
    }
  },
  methods: {
    resetTareas() { // <-- it's filled here instead
      this.tareas = {
        tarea:'',
        id:null,
        editar:false
      }
    },
    agregarTarea(){
      this.$emit('tareaAgregada', this.tareas);
      this.resetTareas(); // <-- Create a brand new object after emitting
    }
  },
  created() {
    this.resetTareas();  // <-- This is for the first one
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  Tarea: <input type="text" v-model="tareas.tarea" /><br /><br />
  <button @click="agregarTarea">Emit</button><br /><br />
  Object: {{ tareas }}
</div>

Поскольку resetTareas создает новый объект каждый раз, вам не нужно беспокоиться о клонировании чего-либо, и это работает, даже если tareas сложный вложенный объект.

...