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 ไม่สามารถรับการเปลี่ยนแปลงสถานะของคุณได้หากคุณจัดการอาร์เรย์เช่นนี้

ตามที่อธิบายไว้ในGotchas สำหรับผู้เริ่มต้นทั่วไปคุณควรใช้วิธีอาร์เรย์เช่น 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>


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)

Splice ยังคงมีอยู่และที่นี่คือการเชื่อมโยงกับวิธีการอาร์เรย์การกลายพันธุ์ที่มีอยู่ใน vue การเชื่อมโยง


ฉันต้องระบุสตริงอะไรเป็น 'ดัชนี'
Kokodoko

@Kokodoko ช่วยชี้แจงสิ่งที่คุณพยายามทำ? ถ้าเป็นอาร์เรย์ควรเป็นตัวเลขสำหรับดัชนี สตริงจะเป็นถ้าคุณกำลังตั้งค่าฟิลด์บนวัตถุ
Martin Calvert

โอเค IDE ของฉันยืนยันว่ามันต้องเป็นสตริงต้องเป็นความผิดพลาด
Kokodoko

Vue.set ไม่ใช่สำหรับ vuex และสิ่งนี้ $ set เลิกใช้แล้ว
atilkan

2
@MartinCalvert มันขึ้นว่า "เมื่อเพิ่มคุณสมบัติให้กับวัตถุ" นั่นคือจุดประสงค์หลักของ Vue.set ไม่ได้เกี่ยวข้องกับ vuex เท่านั้น การเลิกใช้งานฉันอ่านในลิงค์ แต่ตอนนี้อ่านอีกครั้งฉันไม่เข้าใจทั้งหมด stackoverflow.com/questions/36671106/…
atilkan

11

ตามที่ระบุไว้ก่อนหน้านี้ VueJS ไม่สามารถติดตามการดำเนินการเหล่านั้นได้ (การกำหนดองค์ประกอบอาร์เรย์) การดำเนินงานทั้งหมดที่มีการติดตามโดย VueJS กับอาร์เรย์มีที่นี่ แต่ฉันจะคัดลอกอีกครั้ง:

  • ดัน ()
  • ป๊อป ()
  • กะ ()
  • คลาย ()
  • ประกบ ()
  • เรียงลำดับ ()
  • ย้อนกลับ ()

ในระหว่างการพัฒนาคุณประสบปัญหา - จะอยู่กับสิ่งนั้นได้อย่างไร :)

push (), pop (), shift (), unshift (), sort () และ reverse () นั้นค่อนข้างธรรมดาและช่วยคุณได้ในบางกรณี แต่โฟกัสหลักอยู่ภายในsplice ()ซึ่งช่วยให้คุณแก้ไขอาร์เรย์ได้อย่างมีประสิทธิภาพ ที่จะถูกติดตามโดย VueJs ดังนั้นฉันจึงสามารถแบ่งปันวิธีการบางอย่างที่ใช้มากที่สุดกับอาร์เรย์

คุณต้องเปลี่ยน Item ใน Array:

// 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 () เพื่อเพิ่มฟิลด์ให้กับข้อมูลเวอร์ชัน UI ของคุณ ตัวอย่างเช่นคุณต้องการข้อมูลหรือแฟล็กจากการคำนวณเพิ่มเติมภายในออบเจ็กต์ของคุณ คุณสามารถทำสิ่งนี้สำหรับวัตถุของคุณหรือรายการของวัตถุ (ในลูป):

 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 ของคุณด้วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.