Vue Component(元件) 互相溝通
29 Oct 2019 |Component 資料如何互相溝通
在父元件(Header.vue)中使用子元件(Card.vue)
如下圖紅色方框處,即為 Child Component
首先看父元件(Header.vue)的程式碼
<template>
<div>
<label for="name">Name</label>
<input type="text" v-model="name" />
<label for="jobTitle">Job Title</label>
<input type="text" v-model="jobTitle" />
<card :name="name" :jobTitle="jobTitle" />
<h1></h1>
</div>
</template>
<script>
import Card from "@/components/Card";
export default {
name: "HelloWorld",
components: {
Card
},
data() {
return {
name: "David Wu",
jobTitle: "Software Engineer",
msg: "Welcome to Your Vue.js App"
};
}
};
</script>
父元件中,透過 v-model 實現雙向綁定,輸入框的資料若有異動,則會異動到子元件相對的屬性
子元件(Card.vue)程式碼如下
<template>
<div>
<div>
<i class="fas fa-user-tie fa-10x"></i>
<h4><b>{{ name }}</b></h4>
<p>{{ jobTitle }}</p>
<h4><b>{{ name }}</b></h4>
</div>
</div>
</template>
<script>
export default {
name: "Card",
props: {
name: {
type: String,
default() {
return "";
}
},
jobTitle: {
type: String,
default() {
return "";
}
}
}
};
</script>
現在需要異動子元件的資料,所以在子元件新增兩個 Button 透過 methods 來異動props
<template>
<div>
<div>
<i class="fas fa-user-tie fa-10x"></i>
<h4><b>{{ name }}</b></h4>
<p>{{ jobTitle }}</p>
<button @click="changeName">Change Name</button>
<button @click="changeTitle">Change Title</button>
</div>
</div>
</template>
<script>
export default {
name: "Card",
...
methods: {
changeName: function() {
this.name = "Joe Doe";
},
changeTitle: function() {
this.jobTitle = "Sales";
}
}
};
</script>
看到上圖可以知道,父元件的資料沒有跟著改變,打開 F12 發現下面得錯誤訊息
[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: "name"
問題是在於prop是單向綁定,父組件屬性發生變化,會傳給子元件; 但相反的子元件屬性改變,並不會跟著改變父元件的屬性
,是為了防止子元件無意間修改了父組件的狀態,會讓數據流難以理解
首先要在子元件中將各個 props 用副本先儲存起來
舉例來說:再 data新增 myName 就將預設值設為name
這個 prop,再 changeName 的時候,新增一段this.$emit("nameChanged", this.myName);
<template>
<div>
<div>
<i class="fas fa-user-tie fa-10x"></i>
<h4><b>{{ name }}</b></h4>
<p>{{ jobTitle }}</p>
<button @click="changeName">Change Name</button>
<button @click="changeTitle">Change Title</button>
</div>
</div>
</template>
<script>
export default {
name: "Card",
props: {
name: {
type: String,
default() {
return "";
}
},
jobTitle: {
type: String,
default() {
return "";
}
}
},
data() {
return {
myName: this.name
};
},
methods: {
changeName: function() {
this.myName = "Joe Doe";
this.$emit("nameChanged", this.myName);
},
changeTitle: function() {
this.jobTitle = "Sales";
}
}
};
</script>
子元件會發射nameChanged這個 event
,所以在父元件需要新增這個 method
再 card 元件中 新增 @nameChanged="onNameChanged"
,@nameChanged 即對應到子元件發射的 eventName
<template>
<div>
...
<card :name="name" :jobTitle="jobTitle" @nameChanged="onNameChanged" />
...
</div>
</template>
<script>
import Card from "@/components/Card";
export default {
name: "HelloWorld",
components: {
Card
},
data() {
return {
name: "David Wu",
jobTitle: "Software Engineer",
msg: "Welcome to Your Vue.js App"
};
},
methods: {
onNameChanged: function(newVal) {
this.name = newVal;
}
}
};
</script>
如此一來子元件調整後的屬性值,也會更新到父元件對應的屬性
參考資料:
Comments