1. 程式人生 > >Vue2.0 之props是資料綁定出錯

Vue2.0 之props是資料綁定出錯

背景

在使用Vue進行元件開發時,對於父元件傳遞過來的props屬性,在子元件內部對這個值進行了更改,就會出現如下的錯誤資訊:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "xxx"

錯誤原因

在Vue2.X中,傳入的props屬性是不允許改變的,因為在新的渲染機制中,每當父元件重新渲染時,子元件都會被重新覆蓋,所以props屬性,在子元件內部應該被看做是不可變物件。所以我們必須藉助中間變數來做緩衝,通過中間變數的改變傳送事件給父元件,父元件接收到後,再對props進行更改。

案例

在實現公司內部元件時,我引用了element-ui的Dialog元件,為了方便元件的複用,我將一些基礎屬性封裝在了一個自定義元件中,大致的結構如下: 在這裡插入圖片描述

  • 外部Index是用於組裝自定義的元件
  • 自定義元件是一些可以複用的基本功能元件
  • 最裡面的是引用的elementUI

為了控制彈出框的顯示情況,所以我定義了一個Visible屬性, Visible的流向是: 在這裡插入圖片描述

在element-ui元件中 ,控制顯示的一般會加上這個屬性:visible.sync="visible" 這個意思是說elementui元件在內部改變visible之後會通知父元件visible屬性更新了。它的變化會回傳給父元件,所以當時在自定義元件中拿到這個值就對其進行操作,發現報錯了。此時的資料流向如下: 在這裡插入圖片描述

這個屬性是Index傳進來的,所以我們沒有經過Index,在自定義元件就對其進行了修改,所以不符合Vue對於屬性資料單向傳遞的規則,正確的做法是像這樣: 在這裡插入圖片描述

但是由於elementUI直接就將變化給回傳了,所以我們不能直接傳給Index元件,需要藉助一箇中間變數來接受這個值,然後把這個變化回傳給Index元件,告訴Index自定義元件需要更新。

解決方式

首先我們頂一下Index元件需要傳的值:

<user-dialog :showDialog.sync="dialogTableVisible" :ruleForm="ruleForm" v-if="dialogTableVisible"
@closeDialog="closeUserDialog"></user-dialog>

dialogTableVisible屬性傳入到user-dialog自定義的元件中

自定義的元件

  props: {
      showDialog: {
             type: Boolean,
             default: false
         }       
 },
 data(){
 	return {
 		//show控制elementui的變化
 		show: false,
	}
 }
 //建立時,賦值
 created() {
  	this.show = this.showDialog;
 },

我們藉助show作為中轉變數,當show發生變化時,我們傳送事件給Index元件 所以,在關閉elementui時,觸發一個回撥函式:

closeDialog() {
     this.show = false;
     this.$emit('closeDialog');
},

父元件可以通過監聽這個事件來關閉自定義元件:

<user-dialog :showDialog.sync="dialogTableVisible" :ruleForm="ruleForm" v-if="dialogTableVisible"
@closeDialog="closeUserDialog"></user-dialog>

事件方法:

closeUserDialog() {
 	this.dialogTableVisible = false;
},

解決方式二

通過事件Bus來傳遞事件

import Vue from 'vue'
const Bus = new Vue()
var app= new Vue({
    el:'#app',
   data:{
    Bus
    }  

})

直接建立一個空Vue例項,作為訊息匯流排承載體,然後在子元件中通過 this.$root.Bus.$on(),this.$root.Bus.$emit()來呼叫. 不需要走props,子元件改變就呼叫$emit('xxx')傳送事件 父元件只需要監聽$on('xxx')然後操作傳入的屬性值即可。