Vuejs e Vue.set (), matriz de atualização

94

Eu sou novo em Vuejs. Fiz alguma coisa, mas não sei se é do jeito simples / certo.

o que eu quero

Quero algumas datas em uma matriz e atualizá-las em um evento. Primeiro tentei Vue.set, mas não deu certo. Agora, depois de mudar meu item de array:

this.items[index] = val;
this.items.push();

Eu empurro () nada para o array e ele atualiza .. Mas às vezes o último item fica escondido, de alguma forma ... Eu acho que esta solução é um pouco hackeada, como posso torná-la estável?

O código simples está aqui:

new Vue({
  el: '#app',
  data: {
  	f: 'DD-MM-YYYY',
    items: [
      "10-03-2017",
      "12-03-2017"
    ]
  },
  methods: {
    
    cha: function(index, item, what, count) {
    	console.log(item + " index > " + index);
      val = moment(this.items[index], this.f).add(count, what).format(this.f);
  		this.items[index] = val;
      this.items.push();
      console.log("arr length:  " + this.items.length);
    }
  }
})
ul {
  list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<div id="app">
  <ul>
    <li v-for="(index, item) in items">
    <br><br>
      <button v-on:click="cha(index, item, 'day', -1)">
      - day</button>
      {{ item }}
      <button v-on:click="cha(index, item, 'day', 1)">
      + day</button>
    <br><br>
    </li>
  </ul>
</div>

Johan Hoeksma
fonte

Respostas:

59

O VueJS não pode captar suas mudanças no estado se você manipular arrays como este.

Conforme explicado nas dicas comuns para iniciantes , você deve usar métodos de array como push, splice ou qualquer outro e nunca modificar os índices como este a[2] = 2nem a propriedade .length de um array.

new Vue({
  el: '#app',
  data: {
    f: 'DD-MM-YYYY',
    items: [
      "10-03-2017",
      "12-03-2017"
    ]
  },
  methods: {

    cha: function(index, item, what, count) {
      console.log(item + " index > " + index);
      val = moment(this.items[index], this.f).add(count, what).format(this.f);

      this.items.$set(index, val)
      console.log("arr length:  " + this.items.length);
    }
  }
})
ul {
  list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<div id="app">
  <ul>
    <li v-for="(index, item) in items">
      <br><br>
      <button v-on:click="cha(index, item, 'day', -1)">
      - day</button> {{ item }}
      <button v-on:click="cha(index, item, 'day', 1)">
      + day</button>
      <br><br>
    </li>
  </ul>
</div>

Borjante
fonte
1
Como dito na documentação, $ set é apenas um bonito .splice (). Isso faz sentido porque, como dizem nos documentos, você deve modificar a matriz usando seus métodos.
Borjante
1
Por favor, não combine recuos de guia com recuos de espaço, o tamanho de uma guia é aparentemente diferente no aplicativo SE, tornando difícil ler seu código
Ferrybig
No meu caso, o operador de propagação ES6 para a operação push não funciona provavelmente com vue
Mathias S
118

EDITAR 2

  • Para todas as mudanças de objetos que precisam de reatividade, useVue.set(object, prop, value)
  • Para mutações de array, você pode olhar a lista atualmente suportada aqui

EDITAR 1

Para vuex você vai querer fazer Vue.set(state.object, key, value)


Original

Então, apenas para outros que vêm a esta pergunta. Ele aparece em algum ponto no Vue 2. * eles removeram this.items.$set(index, val)em favor de this.$set(this.items, index, val).

A emenda ainda está disponível e aqui está um link para os métodos de mutação de array disponíveis no link vue .

Martin Calvert
fonte
Qual string devo fornecer como o 'índice'?
Kokodoko
@Kokodoko, você pode esclarecer o que está tentando fazer? Se for uma matriz, deve ser um número para o índice. Uma string seria se você estivesse definindo um campo em um objeto.
Martin Calvert
Ah ok, meu IDE insistiu que tinha que ser uma string, deve ser uma falha.
Kokodoko
Vue.set não é para vuex. E este. $ Set tornou-se obsoleto.
Atilkan
2
@MartinCalvert Diz "ao adicionar propriedade ao objeto". Esse é o objetivo principal do Vue.set, não relacionado apenas ao vuex. Suspensão de uso, li no link, mas agora estou lendo novamente, mas não entendi totalmente. stackoverflow.com/questions/36671106/…
atilkan
11

Como afirmado antes - o VueJS simplesmente não pode rastrear essas operações (atribuição de elementos de array). Todas as operações rastreadas pelo VueJS com array estão aqui . Mas vou copiá-los mais uma vez:

  • empurrar()
  • pop ()
  • mudança()
  • não mudar ()
  • splice ()
  • ordenar()
  • reverter()

Durante o desenvolvimento, você enfrenta um problema - como viver com isso :).

push (), pop (), shift (), unshift (), sort () e reverse () são bastante simples e ajudam em alguns casos, mas o foco principal está no splice () , que permite modificar efetivamente o array que seria rastreado por VueJs. Portanto, posso compartilhar algumas das abordagens mais usadas para trabalhar com arrays.

Você precisa substituir o item na matriz:

// note - findIndex might be replaced with some(), filter(), forEach() 
// or any other function/approach if you need 
// additional browser support, or you might use a polyfill
const index = this.values.findIndex(item => {
          return (replacementItem.id === item.id)
        })
this.values.splice(index, 1, replacementItem)

Nota: se você só precisa modificar um campo de item - você pode fazer isso:

this.values[index].itemField = newItemFieldValue

E isso seria rastreado pelo VueJS como os campos do item (Objeto) seriam rastreados.

Você precisa esvaziar a matriz:

this.values.splice(0, this.values.length)

Na verdade, você pode fazer muito mais com esta função splice () - link w3schools. Você pode adicionar vários registros, excluir vários registros, etc.

Vue.set () e Vue.delete ()

Vue.set () e Vue.delete () podem ser usados ​​para adicionar campos à versão de dados da interface do usuário. Por exemplo, você precisa de alguns dados calculados adicionais ou sinalizadores em seus objetos. Você pode fazer isso para seus objetos ou lista de objetos (no loop):

 Vue.set(plan, 'editEnabled', true) //(or this.$set)

E envie os dados editados de volta para o back-end no mesmo formato, fazendo isso antes da chamada do Axios:

 Vue.delete(plan, 'editEnabled') //(or this.$delete)
Mykola Korol
fonte
0

Uma alternativa - e uma abordagem mais leve para o seu problema - pode ser apenas editar o array temporariamente e, em seguida, atribuir o array inteiro de volta à sua variável. Porque, como o Vue não observa itens individuais, ele observará toda a variável sendo atualizada.

Então, isso também deve funcionar:

var tempArray[];

tempArray = this.items;

tempArray[targetPosition]  = value;

this.items = tempArray;

Isso também deve atualizar seu DOM.

Geole
fonte