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 не може отримати ваші зміни до стану, якщо ви маніпулюєте такими масивами.

Як пояснюється в Common Beginner Gotchas , вам слід використовувати методи масиву, такі як push, сплайсинг або будь-який інший, і ніколи не змінювати подібні індекси, 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>


1
Як сказано в документах, $ set - це просто симпатичний .splice (). Це має сенс, оскільки, як кажуть у документах, ви повинні модифікувати масив, використовуючи його методи.
Borjante

1
Будь ласка, не поєднуйте відступи табуляції з відступами, розмір вкладки, очевидно, різниться в додатку SE, що ускладнює читання коду
Ferrybig,

У моєму випадку оператор розповсюдження ES6 для операції штовхання не працює належним чином з 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 link .


Який рядок мені потрібно вказати як "індекс"?
Кокодоко

@Kokodoko, ти можеш пояснити, що ти намагаєшся зробити? Якщо це масив, це має бути число для індексу. Рядок буде, якщо ви встановлюєте поле для об'єкта.
Мартін Калверт,

О гаразд, моя IDE наполягала, що це має бути рядок, це має бути глюк.
Кокодоко

Vue.set не для vuex. І це. $ Set застаріло.
atilkan

2
@MartinCalvert У ньому сказано "при додаванні властивості до об'єкта". Це головна мета Vue.set, не пов’язана лише з vuex. Знищення, я прочитав це за посиланням, але зараз, читаючи ще раз, я його не повністю розумію. stackoverflow.com/questions/36671106 / ...
atilkan

11

Як вже було сказано - VueJS просто не може відстежувати ці операції (призначення елементів масиву). Всі операції, які відстежуються VueJS з масивом, знаходяться тут . Але я ще раз скопіюю їх:

  • push ()
  • поп ()
  • shift ()
  • зрушення ()
  • зрощення ()
  • сортувати ()
  • зворотний()

Під час розвитку ви стикаєтесь із проблемою - як з цим жити :).

push (), pop (), shift (), unshift (), sort () і reverse () досить прості і допомагають вам в деяких випадках, але основний фокус лежить на сплайсингу () , що дозволяє ефективно змінювати масив що буде відстежено 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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.