Vuejs и Vue.set (), обновить массив

93

Я новичок в Vuejs. Что-то сделал, но не знаю, как это просто / правильно.

что я хочу

Я хочу несколько дат в массиве и обновляю их по событию. Сначала попробовал Vue.set, но ничего не вышло. Теперь после изменения элемента моего массива:

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

Я ничего не нажимаю () в массив, и он обновляется .. Но иногда последний элемент каким-то образом скрывается ... Я думаю, что это решение немного взломано, как я могу сделать его стабильным?

Вот простой код:

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>

Йохан Хуксма
источник

Ответы:

57

VueJS не может улавливать ваши изменения состояния, если вы манипулируете такими массивами.

Как объясняется в разделе Общие вопросы для начинающих , вам следует использовать методы массива, такие как push, splice или что-то еще, и никогда не изменять индексы, подобные этому, a[2] = 2или свойство .length массива.

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
источник
1
Как сказано в документации, $ set - это просто красивый .splice (). Это имеет смысл, потому что, как говорится в документации, вы должны изменять массив, используя его методы.
Borjante
1
Пожалуйста, не комбинируйте отступы табуляции с пробелами, размер табуляции явно отличается в приложении SE, что затрудняет чтение вашего кода
Ferrybig
В моем случае оператор распространения ES6 для операции push явно не работает с vue
Mathias S
117

РЕДАКТИРОВАТЬ 2

  • Для всех изменений объекта, требующих реактивности, используйтеVue.set(object, prop, value)
  • Для мутаций массива вы можете посмотреть список поддерживаемых в настоящее время здесь

ИЗМЕНИТЬ 1

Для vuex вы захотите сделать Vue.set(state.object, key, value)


Оригинал

Так что только для тех, кто задается этим вопросом. Он появляется в какой-то момент в Vue 2. * они удалили this.items.$set(index, val)в пользу this.$set(this.items, index, val).

Сплайс все еще доступен, и вот ссылка на методы мутации массива, доступные в ссылке vue .

Мартин Калверт
источник
Какую строку мне нужно указать в качестве индекса?
Kokodoko
@Kokodoko, можешь пояснить, что ты пытаешься сделать? Если это массив, это должно быть число для индекса. Строка будет, если вы устанавливаете поле для объекта.
Мартин Калверт,
А, ладно, моя IDE настаивала, что это должна быть строка, должно быть глюк.
Kokodoko
Vue.set не для vuex. И этот. $ Set устарел.
atilkan
2
@MartinCalvert Он говорит «при добавлении свойства к объекту». Это основная цель Vue.set, не связанная только с vuex. Устарело, я прочитал это по ссылке, но теперь читаю снова, я не совсем понимаю. stackoverflow.com/questions/36671106/…
atilkan
11

Как указывалось ранее - VueJS просто не может отслеживать эти операции (назначение элементов массива). Все операции, которые отслеживает VueJS с массивом, находятся здесь . Но скопирую еще раз:

  • От себя()
  • поп ()
  • сдвиг()
  • unshift ()
  • сращивание ()
  • Сортировать()
  • обеспечить регресс()

В процессе разработки возникает проблема - как с этим жить :).

push (), pop (), shift (), unshift (), sort () и reverse () довольно просты и помогают вам в некоторых случаях, но основное внимание уделяется splice () , который позволяет вам эффективно изменять массив это будет отслеживаться VueJs. Так что могу поделиться некоторыми подходами, которые наиболее часто используются при работе с массивами.

Вам нужно заменить элемент в массиве:

// 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)

Примечание: если вам просто нужно изменить поле элемента - вы можете сделать это просто:

this.values[index].itemField = newItemFieldValue

И это будет отслеживаться VueJS, поскольку отслеживаются поля элемента (объекта).

Вам нужно очистить массив:

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

На самом деле вы можете сделать гораздо больше с помощью этой функции splice () - ссылка w3schools. Вы можете добавлять несколько записей, удалять несколько записей и т. Д.

Vue.set () и Vue.delete ()

Vue.set () и Vue.delete () могут использоваться для добавления поля в вашу версию пользовательского интерфейса данных. Например, вам нужны дополнительные рассчитанные данные или флаги в ваших объектах. Вы можете сделать это для своих объектов или списка объектов (в цикле):

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

И отправьте отредактированные данные обратно в серверную часть в том же формате, сделав это до вызова Axios:

 Vue.delete(plan, 'editEnabled') //(or this.$delete)
Николай Король
источник
0

Одна альтернатива - и более легкий подход к вашей проблеме - может быть, просто временно отредактировать массив, а затем назначить весь массив обратно вашей переменной. Поскольку Vue не отслеживает отдельные элементы, он будет следить за обновлением всей переменной.

Так что это тоже должно работать:

var tempArray[];

tempArray = this.items;

tempArray[targetPosition]  = value;

this.items = tempArray;

Тогда это также должно обновить вашу DOM.

Geole
источник