Vue 2 - เปลี่ยนอุปกรณ์ประกอบฉาก vue-warn


181

ฉันเริ่มต้นhttps://laracasts.com/series/learning-vue-step-by-stepซีรี่ส์ ฉันหยุดบทเรียนVue, Laravel และ AJAXด้วยข้อผิดพลาดนี้:

vue.js: 2574 [เตือนของ Vue]: หลีกเลี่ยงการกลายพันธุ์ prop โดยตรงเนื่องจากค่าจะถูกเขียนทับเมื่อใดก็ตามที่องค์ประกอบหลักแสดงผลอีกครั้ง ให้ใช้ข้อมูลหรือคุณสมบัติที่คำนวณได้แทนตามค่าของ prop Prop กำลังกลายพันธุ์: "รายการ" (พบในส่วนประกอบ)

ฉันมีรหัสนี้ในmain.js

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    created() {
        this.list = JSON.parse(this.list);
    }
});
new Vue({
    el: '.container'
})

ฉันรู้ว่าปัญหานั้นสร้างขึ้น ()เมื่อฉันเขียนทับเสารายการ แต่ฉันเป็นมือใหม่ใน Vue ดังนั้นฉันจึงไม่รู้วิธีแก้ไขโดยสิ้นเชิง ใครมีความคิดวิธี (และโปรดอธิบายว่าทำไม) เพื่อแก้ไขหรือไม่


2
คิดว่ามันเป็นเพียงข้อความเตือนและไม่ใช่ข้อผิดพลาด
David R

คำตอบ:


264

สิ่งนี้เกี่ยวข้องกับความจริงที่ว่าการกลายพันธุ์เสาในท้องถิ่นนั้นถือเป็นรูปแบบการต่อต้านใน Vue 2

สิ่งที่คุณควรทำตอนนี้ในกรณีที่คุณต้องการที่จะกลายพันธุ์เสาในท้องถิ่นคือการประกาศเขตข้อมูลในของคุณdataที่ใช้propsค่าเป็นค่าเริ่มต้นแล้วกลายพันธุ์คัดลอก:

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    data: function () {
        return {
            mutableList: JSON.parse(this.list);
        }
    }
});

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับสิ่งนี้ได้ในคู่มืออย่างเป็นทางการของ Vue.js


หมายเหตุ 1:โปรดทราบว่าคุณไม่ควรใช้ชื่อเดียวกันสำหรับคุณpropและdataเช่น:

data: function () { return { list: JSON.parse(this.list) } // WRONG!!

หมายเหตุ 2:เนื่องจากฉันรู้สึกว่ามีความสับสนเกี่ยวกับpropsและปฏิกิริยาบางอย่างฉันขอแนะนำให้คุณดูที่หัวข้อนี้


3
นี่เป็นคำตอบที่ดี แต่ฉันคิดว่าควรได้รับการอัปเดตเพื่อรวมการรวมเหตุการณ์ไว้ด้วย เหตุการณ์ที่ถูกทริกเกอร์จากเด็กสามารถอัปเดตพาเรนต์ซึ่งจะส่งอุปกรณ์ประกอบฉากที่อัปเดตไปยังเด็ก ด้วยวิธีนี้แหล่งที่มาของความจริงยังคงอยู่ในองค์ประกอบทั้งหมด มันอาจคุ้มค่าที่จะกล่าวถึง Vuex สำหรับการจัดการสถานะที่แชร์ข้ามหลายองค์ประกอบ
Wes Harper

@WesHarper สามารถใช้ตัวปรับเปลี่ยน. syncเป็นชวเลขเพื่อรับกิจกรรมการอัพเดทของผู้ปกครองโดยอัตโนมัติ
danb4r

48

รูปแบบ Vue propsลดลงและeventsเพิ่มขึ้น ฟังดูง่าย แต่ลืมง่ายเมื่อเขียนส่วนประกอบที่กำหนดเอง

ตั้งแต่ Vue 2.2.0 คุณสามารถใช้v-model (พร้อมคุณสมบัติที่คำนวณได้ ) ฉันพบว่าชุดค่าผสมนี้สร้างอินเทอร์เฟซที่เรียบง่ายสะอาดและสอดคล้องกันระหว่างส่วนประกอบ:

  • propsองค์ประกอบใด ๆ ที่ส่งผ่านไปยังองค์ประกอบของคุณจะยังคงมีปฏิกิริยา (เช่นมันไม่ได้ถูกโคลนหรือไม่จำเป็นต้องมีwatchฟังก์ชั่นในการอัพเดทสำเนาในเครื่องเมื่อตรวจพบการเปลี่ยนแปลง)
  • การเปลี่ยนแปลงจะถูกปล่อยออกโดยอัตโนมัติไปยังผู้ปกครอง
  • สามารถใช้กับส่วนประกอบหลายระดับ

คุณสมบัติที่คำนวณได้อนุญาตให้ setter และ getter แยกกันได้ สิ่งนี้อนุญาตให้Taskคอมโพเนนต์ถูกเขียนใหม่ดังนี้:

Vue.component('Task', {
    template: '#task-template',
    props: ['list'],
    model: {
        prop: 'list',
        event: 'listchange'
    },
    computed: {
        listLocal: {
            get: function() {
                return this.list
            },
            set: function(value) {
                this.$emit('listchange', value)
            }
        }
    }
})  

รูปแบบกำหนดสถานที่ให้บริการที่propมีความเกี่ยวข้องกับv-modelและกรณีที่จะถูกปล่อยออกมาเกี่ยวกับการเปลี่ยนแปลง จากนั้นคุณสามารถเรียกใช้คอมโพเนนต์นี้จากพาเรนต์ดังนี้:

<Task v-model="parentList"></Task>

listLocalคุณสมบัติคำนวณให้ทะเยอทะยานและตั้งค่าอินเตอร์เฟซที่เรียบง่ายภายในส่วนประกอบ (คิดว่ามันเหมือนเป็นตัวแปรเอกชน) ภายใน#task-templateคุณสามารถแสดงผลlistLocalและมันจะยังคงมีปฏิกิริยา (เช่นหากparentListการเปลี่ยนแปลงจะอัปเดตTaskองค์ประกอบ) นอกจากนี้คุณยังสามารถกลายพันธุ์listLocalโดยการเรียกตัวตั้งค่า (เช่นthis.listLocal = newList) และมันจะปล่อยการเปลี่ยนแปลงไปยังผู้ปกครอง

สิ่งที่ยอดเยี่ยมเกี่ยวกับรูปแบบนี้คือคุณสามารถส่งlistLocalต่อไปยังองค์ประกอบย่อยของTask(โดยใช้v-model) และการเปลี่ยนแปลงจากองค์ประกอบย่อยจะเผยแพร่ไปยังองค์ประกอบระดับบนสุด

ตัวอย่างเช่นสมมติว่าเรามีEditTaskส่วนประกอบแยกต่างหากสำหรับทำการแก้ไขบางชนิดกับข้อมูลงาน โดยใช้v-modelรูปแบบคุณสมบัติที่เหมือนกันและคำนวณเราสามารถส่งผ่านlistLocalไปยังองค์ประกอบ (โดยใช้v-model):

<script type="text/x-template" id="task-template">
    <div>
        <EditTask v-model="listLocal"></EditTask>
    </div>
</script>

ถ้าEditTaskปล่อยออกมามีการเปลี่ยนแปลงได้อย่างเหมาะสมจะเรียกset()ในlistLocalและจึงเผยแพร่เหตุการณ์ให้อยู่ในระดับด้านบน ในทำนองเดียวกันEditTaskองค์ประกอบยังสามารถเรียกส่วนประกอบเด็กอื่น ๆ (เช่นองค์ประกอบของแบบฟอร์ม) v-modelโดยใช้


1
ฉันทำสิ่งที่คล้ายกันยกเว้นซิงค์ ปัญหาคือฉันต้องเรียกใช้วิธีอื่นหลังจากส่งเหตุการณ์การเปลี่ยนแปลงของฉันอย่างไรก็ตามเมื่อวิธีการทำงานและเข้าสู่ getter ฉันจะได้รับค่าเก่าเพราะผู้ฟัง / เผยแพร่กลับไปยังเหตุการณ์ที่เกิดการเปลี่ยนแปลง นี่เป็นกรณีที่ฉันต้องการเปลี่ยนรูปแบบเพื่อให้ข้อมูลในเครื่องของฉันถูกต้องจนกว่าการอัปเดตหลักจะแพร่กระจายกลับลงมา ความคิดใด ๆ ในเรื่องนี้?
koga73

ฉันสงสัยว่าการโทรทะเยอทะยานจากสุนัขเซทเทอร์ไม่ใช่วิธีปฏิบัติที่ดี สิ่งที่คุณอาจพิจารณาคือวางนาฬิกาบนทรัพย์สินที่คำนวณของคุณและเพิ่มตรรกะของคุณที่นั่น
chris

อุปกรณ์ประกอบฉากและกิจกรรมที่เกิดขึ้นเป็นสิ่งที่ฉันคลิก คำอธิบายนี้อยู่ที่ไหนในเอกสารของ VueJs
nebulousGirl

@nebulousGirl ดูที่นี่: vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow
chris

ฉันคิดว่านี่เป็นวิธีที่เจ็บปวดยิ่งกว่าในการเปล่งการเปลี่ยนแปลงในองค์ประกอบหลัก
มูฮัมหมัด

36

Vue เพิ่งเตือนคุณ: คุณเปลี่ยน prop ในองค์ประกอบ แต่เมื่อองค์ประกอบหลัก re-renders "รายการ" จะถูกเขียนทับและคุณสูญเสียการเปลี่ยนแปลงทั้งหมด ดังนั้นจึงเป็นอันตรายที่จะทำเช่นนั้น

ใช้คุณสมบัติที่คำนวณได้แทนเช่นนี้:

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    computed: {
        listJson: function(){
            return JSON.parse(this.list);
        }
    }
});

25
สิ่งที่เกี่ยวกับเสาผูก 2 ทาง?
Josh R.

7
หากคุณต้องการผูกข้อมูล 2 ทางคุณควรใช้เหตุการณ์ที่กำหนดเองสำหรับข้อมูลเพิ่มเติมอ่าน: vuejs.org/v2/guide/components.html#sync-Modifierคุณยังไม่สามารถปรับเปลี่ยน prop ได้โดยตรงคุณต้องมีกิจกรรมและฟังก์ชันที่ จัดการกับการเปลี่ยนแปลงเสาสำหรับคุณ
Marco

22

หากคุณใช้ Lodash คุณสามารถโคลนเสาก่อนที่จะส่งคืน รูปแบบนี้มีประโยชน์ถ้าคุณแก้ไข prop นั้นทั้งบน parent และ child

สมมติว่าเรามีรายการ prop ในกริดส่วนประกอบตาราง

ในองค์ประกอบหลัก

<grid :list.sync="list"></grid>

ในองค์ประกอบลูก

props: ['list'],
methods:{
    doSomethingOnClick(entry){
        let modifiedList = _.clone(this.list)
        modifiedList = _.uniq(modifiedList) // Removes duplicates
        this.$emit('update:list', modifiedList)
    }
}

19

อุปกรณ์ประกอบฉากลงเหตุการณ์เพิ่มขึ้น นั่นคือรูปแบบของ Vue ประเด็นก็คือว่าถ้าคุณพยายามที่จะกลายพันธุ์อุปกรณ์ประกอบฉากที่ผ่านจากผู้ปกครอง มันไม่ทำงานและมันเพิ่งถูกเขียนทับซ้ำโดยองค์ประกอบหลัก องค์ประกอบลูกสามารถส่งเหตุการณ์เพื่อแจ้งให้ผู้ปกครององค์ประกอบที่จะทำ sth หากคุณไม่ชอบข้อ จำกัด เหล่านี้คุณสามารถใช้ VUEX (อันที่จริงรูปแบบนี้จะดูดในโครงสร้างส่วนประกอบที่ซับซ้อนคุณควรใช้ VUEX!)


2
นอกจากนี้ยังมีตัวเลือกในการใช้งานอีเวนต์บัส
Steven Pribilinskiy

Event Bus ไม่ได้รับการรองรับใน vue 3. github.com/vuejs/rfcs/pull/118
AlexMA

15

คุณไม่ควรเปลี่ยนค่าของอุปกรณ์ประกอบฉากในองค์ประกอบย่อย .syncถ้าคุณต้องการจริงๆที่จะเปลี่ยนคุณสามารถใช้ แบบนี้

<your-component :list.sync="list"></your-component>

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    created() {
        this.$emit('update:list', JSON.parse(this.list))
    }
});
new Vue({
    el: '.container'
})

7

ตาม VueJs 2.0 คุณไม่ควรกลายพันธุ์เป็นเสาภายในองค์ประกอบ พวกเขากลายพันธุ์โดยผู้ปกครองเท่านั้น ดังนั้นคุณควรกำหนดตัวแปรในข้อมูลที่มีชื่อแตกต่างกันและให้พวกเขาปรับปรุงโดยดูอุปกรณ์ประกอบฉากจริง ในกรณีที่รายการเปลี่ยนแปลงโดยผู้ปกครองคุณสามารถแยกมันและกำหนดให้ mutableList นี่คือทางออกที่สมบูรณ์

Vue.component('task', {
    template: ´<ul>
                  <li v-for="item in mutableList">
                      {{item.name}}
                  </li>
              </ul>´,
    props: ['list'],
    data: function () {
        return {
            mutableList = JSON.parse(this.list);
        }
    },
    watch:{
        list: function(){
            this.mutableList = JSON.parse(this.list);
        }
    }
});

มันใช้ mutableList เพื่อแสดงเทมเพลตของคุณดังนั้นคุณเก็บรักษาเสาไว้ในรายการอย่างปลอดภัย


ดูไม่แพงที่จะใช้?
Kick Buttowski

6

อย่าเปลี่ยนอุปกรณ์ประกอบฉากโดยตรงใน components.if คุณต้องเปลี่ยนมันตั้งค่าคุณสมบัติใหม่เช่นนี้:

data () {
    return () {
        listClone: this.list
    }
}

และเปลี่ยนค่าของ listClone


6

คำตอบนั้นง่ายคุณควรทำลายการกลายพันธุ์โดยตรงของเสาโดยการกำหนดค่าให้กับตัวแปรองค์ประกอบในตัวเครื่องบางตัว (อาจเป็นคุณสมบัติของข้อมูล

นี่เป็นวิธีง่ายๆในการใช้ watcher

<template>
  <input
    v-model="input"
    @input="updateInput" 
    @change="updateInput"
  />

</template>

<script>
  export default {
  props: {
    value: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      input: '',
    };
  },
  watch: {
    value: {
      handler(after) {
        this.input = after;
      },
      immediate: true,
    },
  },
  methods: {
    updateInput() {
      this.$emit('input', this.input);
    },
  },
};
</script>

มันเป็นสิ่งที่ฉันใช้ในการสร้างองค์ประกอบการป้อนข้อมูลใด ๆ และใช้งานได้ดี ข้อมูลใหม่ใด ๆ ที่ส่ง (v-model (ed)) จาก parent จะถูกเฝ้าดูโดยตัวตรวจสอบค่าและถูกกำหนดให้กับตัวแปรอินพุตและเมื่อได้รับอินพุตแล้วเราสามารถจับการกระทำนั้นและปล่อยอินพุตไปยัง parent แนะนำว่าข้อมูลนั้นเป็นอินพุต จากองค์ประกอบแบบฟอร์ม


5

ฉันประสบปัญหานี้เช่นกัน คำเตือนหายไปหลังจากที่ผมใช้และ$on $emitมันเหมือนกับการใช้งาน$onและ$emitแนะนำให้ส่งข้อมูลจากองค์ประกอบลูกไปยังองค์ประกอบหลัก


4

หากคุณต้องการที่จะกลายพันธุ์อุปกรณ์ประกอบฉาก - ใช้วัตถุ

<component :model="global.price"></component>

ส่วนประกอบ:

props: ['model'],
methods: {
  changeValue: function() {
    this.model.value = "new value";
  }
}

เช่นเดียวกับบันทึกย่อคุณต้องระวังเมื่อทำการผ่าเหล่าวัตถุ วัตถุ Javascript ถูกส่งผ่านโดยการอ้างอิง แต่มีข้อแม้: การอ้างอิงจะใช้งานไม่ได้เมื่อคุณตั้งค่าตัวแปรให้เท่ากับค่า
ira

3

คุณต้องเพิ่มวิธีการคำนวณเช่นนี้

component.vue

props: ['list'],
computed: {
    listJson: function(){
        return JSON.parse(this.list);
    }
}

3

การไหลของข้อมูลทางเดียวตาม https://vuejs.org/v2/guide/components.htmlองค์ประกอบจะเป็นไปตามการไหลของข้อมูลทางเดียวอุปกรณ์ทั้งหมดสร้างการเชื่อมโยงทางเดียวระหว่างคุณสมบัติลูกและผู้ปกครอง หนึ่งเมื่อคุณสมบัติของผู้ปกครองอัปเดตมันจะไหลลงไปที่เด็ก แต่ไม่ใช่วิธีอื่น ๆ สิ่งนี้จะป้องกันไม่ให้คอมโพเนนต์ลูกไม่ได้ทำการปิดบังของผู้ปกครองโดยไม่ตั้งใจซึ่งจะทำให้การไหลของข้อมูลของแอปเข้าใจยากขึ้น

นอกจากนี้ทุกครั้งที่องค์ประกอบพาเรนต์อัปเดตอุปกรณ์ประกอบฉากทั้งหมดในองค์ประกอบย่อยจะรีเฟรชด้วยค่าล่าสุด ซึ่งหมายความว่าคุณไม่ควรพยายามที่จะกลายเป็นเสาในองค์ประกอบเด็ก หากคุณทำ. vue จะเตือนคุณในคอนโซล

โดยปกติจะมีสองกรณีที่มีการพยายามที่จะกลายพันธุ์ไม้ค้ำยัน: ไม้ค้ำยันจะใช้ในการส่งผ่านค่าเริ่มต้น; องค์ประกอบลูกต้องการใช้มันเป็นคุณสมบัติข้อมูลท้องถิ่นหลังจากนั้น เสาถูกส่งผ่านเป็นค่าดิบที่ต้องเปลี่ยน คำตอบที่เหมาะสมสำหรับกรณีการใช้งานเหล่านี้คือ: กำหนดคุณสมบัติข้อมูลท้องถิ่นที่ใช้ค่าเริ่มต้นของ prop เป็นค่าเริ่มต้น:

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}

กำหนดคุณสมบัติที่คำนวณซึ่งคำนวณจากมูลค่าของ prop:

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

2

อุปกรณ์ประกอบฉากของ Vue.js จะต้องไม่ถูกทำให้กลายพันธุ์เนื่องจากเป็น Anti-Pattern ใน Vue

วิธีการที่คุณจะต้องใช้คือการสร้างสถานที่ให้บริการข้อมูลในส่วนของคุณที่อ้างอิงเดิมเสาทรัพย์สินของรายการ

props: ['list'],
data: () {
  return {
    parsedList: JSON.parse(this.list)
  }
}

ตอนนี้โครงสร้างรายการของคุณที่ส่งผ่านไปยังองค์ประกอบนั้นจะถูกอ้างอิงและกลายพันธุ์ผ่านdataคุณสมบัติของส่วนประกอบของคุณ :-)

หากคุณต้องการที่จะทำมากกว่าเพียงแค่การแยกทรัพย์สินรายการของคุณแล้วทำให้การใช้งานขององค์ประกอบวู' computedคุณสมบัติ วิธีนี้ช่วยให้คุณสามารถสร้างการกลายพันธุ์เชิงลึกให้กับอุปกรณ์ประกอบฉากของคุณได้มากขึ้น

props: ['list'],
computed: {
  filteredJSONList: () => {
    let parsedList = JSON.parse(this.list)
    let filteredList = parsedList.filter(listItem => listItem.active)
    console.log(filteredList)
    return filteredList
  }
}

ตัวอย่างข้างต้นจะแยกวิเคราะห์เสารายการของคุณและกรองลงในรายการที่ใช้งานอยู่เท่านั้นออกจากระบบสำหรับ schnitts และ gigglesและส่งกลับ

หมายเหตุ : ทั้งdata& computedคุณสมบัติถูกอ้างอิงในเทมเพลตเช่นเดียวกัน

<pre>{{parsedList}}</pre>

<pre>{{filteredJSONList}}</pre>

มันอาจเป็นเรื่องง่ายที่จะคิดว่าต้องเรียกcomputedคุณสมบัติ (เป็นวิธีการ) ... มันไม่ได้


2
Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    computed: {
      middleData() {
        return this.list
      }
    },
    watch: {
      list(newVal, oldVal) {
        console.log(newVal)
        this.newList = newVal
      }
    },
    data() {
      return {
        newList: {}
      }
    }
});
new Vue({
    el: '.container'
})

อาจจะตอบสนองความต้องการของคุณ


2

การเพิ่มคำตอบที่ดีที่สุด

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    data: function () {
        return {
            mutableList: JSON.parse(this.list);
        }
    }
});

การตั้งค่าอุปกรณ์ประกอบฉากโดยอาเรย์นั้นมีไว้สำหรับ dev / prototyping ในการผลิตตรวจสอบให้แน่ใจว่าตั้งประเภท prop ( https://vuejs.org/v2/guide/components-props.html) ) และตั้งค่าเริ่มต้นในกรณีที่ prop ไม่ได้ ได้รับการบรรจุโดยผู้ปกครองดังนั้น

Vue.component('task', {
    template: '#task-template',
    props: {
      list: {
        type: String,
        default() {
          return '{}'
        }
      }
    },
    data: function () {
        return {
            mutableList: JSON.parse(this.list);
        }
    }
});

วิธีนี้คุณจะได้รับวัตถุว่างเปล่าmutableListแทนที่จะเป็นข้อผิดพลาด JSON.parse หากยังไม่ได้กำหนด


0

Vue.js พิจารณาว่านี่เป็นรูปแบบการต่อต้าน ตัวอย่างเช่นการประกาศและการตั้งค่าอุปกรณ์ประกอบฉากเช่น

this.propsVal = 'new Props Value'

ดังนั้นเพื่อแก้ปัญหานี้คุณต้องรับค่าจากอุปกรณ์ประกอบฉากไปยังข้อมูลหรือคุณสมบัติที่คำนวณได้ของอินสแตนซ์ Vue เช่นนี้:

props: ['propsVal'],
data: function() {
   return {
       propVal: this.propsVal
   };
},
methods: {
...
}

นี้จะทำงานได้อย่างแน่นอน


0

นอกเหนือจากข้างต้นสำหรับผู้อื่นที่มีปัญหาต่อไปนี้:

"ถ้าไม่จำเป็นต้องใช้ค่าประกอบฉากและไม่ได้ส่งคืนเสมอข้อมูลที่ส่งผ่านจะส่งคืนundefined(แทนค่าว่าง)" ซึ่งอาจเป็น<select>ค่าเริ่มต้นยุ่งฉันแก้ไขได้โดยการตรวจสอบว่าค่าตั้งอยู่ในbeforeMount()(และตั้งค่าถ้าไม่) ดังนี้

JS:

export default {
        name: 'user_register',
        data: () => ({
            oldDobMonthMutated: this.oldDobMonth,
        }),
        props: [
            'oldDobMonth',
            'dobMonths', //Used for the select loop
        ],
        beforeMount() {
           if (!this.oldDobMonth) {
              this.oldDobMonthMutated = '';
           } else {
              this.oldDobMonthMutated = this.oldDobMonth
           }
        }
}

Html:

<select v-model="oldDobMonthMutated" id="dob_months" name="dob_month">

 <option selected="selected" disabled="disabled" hidden="hidden" value="">
 Select Month
 </option>

 <option v-for="dobMonth in dobMonths"
  :key="dobMonth.dob_month_slug"
  :value="dobMonth.dob_month_slug">
  {{ dobMonth.dob_month_name }}
 </option>

</select>

0

ฉันต้องการให้คำตอบนี้ซึ่งช่วยหลีกเลี่ยงการใช้รหัสนักดูและคุณสมบัติที่คำนวณได้มากมาย ในบางกรณีนี่อาจเป็นทางออกที่ดี:

อุปกรณ์ประกอบฉากได้รับการออกแบบเพื่อให้การสื่อสารทางเดียว

เมื่อคุณมีshow/hideปุ่มโมดัลที่มีเสาทางออกที่ดีที่สุดสำหรับฉันคือการปล่อยเหตุการณ์:

<button @click="$emit('close')">Close Modal</button>

จากนั้นเพิ่มผู้ฟังไปยังองค์ประกอบ modal:

<modal :show="show" @close="show = false"></modal>

(ในกรณีนี้เสาshowอาจไม่จำเป็นเพราะคุณสามารถใช้ง่ายv-if="show"บนฐานโมดอล)


0

ฉันมักแนะนำว่าถ้าคุณต้องการที่จะกลายเป็นอุปกรณ์ประกอบฉากก่อนส่งพวกเขาไปยังสถานที่คำนวณและกลับมาจากที่นั่นหลังจากนั้นหนึ่งสามารถกลายพันธุ์อุปกรณ์ได้อย่างง่ายดายแม้ที่คุณสามารถติดตามการกลายพันธุ์เสาถ้าพวกเขาจะกลายพันธุ์จากที่อื่น องค์ประกอบเช่นกันหรือเราสามารถรับชมได้


0

เนื่องจากอุปกรณ์ประกอบฉาก Vue เป็นการไหลของข้อมูลทางเดียวสิ่งนี้จะป้องกันไม่ให้คอมโพเนนต์ลูกจากการเปลี่ยนแปลงสถานะของผู้ปกครองโดยไม่ได้ตั้งใจ

จากเอกสาร Vue อย่างเป็นทางการเราจะค้นหา 2 วิธีในการแก้ปัญหานี้

  1. หากองค์ประกอบย่อยต้องการใช้อุปกรณ์ประกอบฉากเป็นข้อมูลในเครื่องจะเป็นการดีที่สุดที่จะกำหนดคุณสมบัติของข้อมูลในเครื่อง

      props: ['list'],
      data: function() {
        return {
          localList: JSON.parse(this.list);
        }
      }
    
  2. เสาถูกส่งผ่านเป็นค่าดิบที่ต้องเปลี่ยน ในกรณีนี้เป็นการดีที่สุดที่จะกำหนดคุณสมบัติที่คำนวณได้โดยใช้ค่าของ prop:

      props: ['list'],
      computed: {
        localList: function() {
           return JSON.parse(this.list);
        },
        //eg: if you want to filter this list
        validList: function() {
           return this.list.filter(product => product.isValid === true)
        }
        //...whatever to transform the list
      }
    
    

0

ใช่! การกลายพันธุ์ของแอททริบิวใน vue2 เป็นการต่อต้านรูปแบบ แต่ ... เพียงแค่ทำลายกฎโดยใช้กฎอื่นและไปข้างหน้า! สิ่งที่คุณต้องการคือการเพิ่ม. sync โมดิฟายเออร์ในแอตทริบิวต์ component ของคุณในขอบเขต paret <your-awesome-components :custom-attribute-as-prob.sync="value" />

🤡มันง่ายที่เราฆ่าแบทแมน😁


0

สำหรับเมื่อ TypeScript เป็น lang ที่คุณต้องการ ของการพัฒนา

<template>
<span class="someClassName">
      {{feesInLocale}}
</span>
</template>  



@Prop({default: 0}) fees: any;

// computed are declared with get before a function
get feesInLocale() {
    return this.fees;
}

และไม่

<template>
<span class="someClassName">
      {{feesInLocale}}
</span>
</template>  



@Prop() fees: any = 0;
get feesInLocale() {
    return this.fees;
}

0

ด้านล่างนี้เป็นส่วนประกอบที่สแน็คบาร์เมื่อฉันให้Snackbarตัวแปรเข้า V-รูปแบบเช่นนี้โดยตรงหากจะทำงาน แต่ในคอนโซลก็จะให้เป็นข้อผิดพลาด

หลีกเลี่ยงการกลายพันธุ์ prop โดยตรงเนื่องจากค่าจะถูกเขียนทับเมื่อใดก็ตามที่องค์ประกอบหลักแสดงผลอีกครั้ง ให้ใช้ข้อมูลหรือคุณสมบัติที่คำนวณได้แทนตามค่าของ prop

<template>
        <v-snackbar v-model="snackbar">
        {{ text }}
      </v-snackbar>
</template>

<script>
    export default {
        name: "loader",

        props: {
            snackbar: {type: Boolean, required: true},
            text: {type: String, required: false, default: ""},
        },

    }
</script>

วิธีที่ถูกต้องในการกำจัดข้อผิดพลาดการกลายพันธุ์นี้คือใช้ตัวเฝ้าดู

<template>
        <v-snackbar v-model="snackbarData">
        {{ text }}
      </v-snackbar>
</template>

<script>
/* eslint-disable */ 
    export default {
        name: "loader",
         data: () => ({
          snackbarData:false,
        }),
        props: {
            snackbar: {type: Boolean, required: true},
            text: {type: String, required: false, default: ""},
        },
        watch: { 
        snackbar: function(newVal, oldVal) { 
          this.snackbarData=!this.snackbarDatanewVal;
        }
      }
    }
</script>

ดังนั้นในองค์ประกอบหลักที่คุณจะโหลดสแน็คบาร์นี้คุณสามารถทำรหัสนี้ได้

 <loader :snackbar="snackbarFlag" :text="snackText"></loader>

สิ่งนี้ได้ผลสำหรับฉัน

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