寫在前面: 我是「揚帆向海」,這個暱稱來源於我的名字以及女朋友的名字。我熱愛技術、熱愛開源、熱愛編程。
技術是開源的、知識是共享的
。
這博客是對自己學習的一點點總結及記錄,如果您對 Java、算法 感興趣,可以關注我的動態,我們一起學習。
用知識改變命運,讓我們的家人過上更好的生活
。
女朋友:“揚帆,你給我上一次講了 vue中的組件
,我現在自己學習父子組件的傳值,可是官方文檔看不懂啊!你能不能通過父子組件傳值的知識實現大頭兒子和小頭爸爸互相通信
呢?”
我: “可以呀!我先分別給你講父組件向子組件傳值和子組件向父組件傳值,最後在給你寫個案例,實現父子組件的相互通信。”
點擊【說話
】按鈕,大頭兒子給小頭爸爸傳遞消息。
小頭爸爸收到消息,點擊【回覆
】按鈕,給大頭兒子發送消息。
一、父組件向子組件傳值
1. 傳值步驟
① 子組件在props
中創建一個屬性,用以接收父組件傳過來的數據;
② 父組件中註冊子組件。通過屬性綁定(v-bind:
)的形式,把需要傳遞給子組件的數據傳遞到子組件的內部,供子組件使用;
③ 在子組件標籤中添加子組件props
中創建的屬性;
④ 把需要傳給子組件的值賦給該屬性
2. 代碼示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父組件向子組件傳值</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 父組件中註冊子組件 -->
<!-- 在子組件標籤中添加子組件props中創建的屬性, 把需要傳給子組件的值賦給該屬性 -->
<mycom :parent-msg='pmsg' :content='hello'></mycom>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
pmsg: '父組件中的內容',
hello: '我是父組件傳過來的'
},
components: {
mycom: {
data: function () {
return {
msg: '我是子組件本身的數據'
}
},
// 子組件在props中創建一個屬性,用以接收父組件傳過來的值
props: ['parentMsg', 'content'],
template: '<h3>{{msg + "---" + parentMsg + "----" + content}}</h3>'
}
}
});
</script>
</body>
</html>
【效果如下】
3. 注意事項
①
prop
是子組件用來接受父組件傳遞過來的數據的一個自定義屬性。
② 父組件的數據需要通過props
把數據傳給子組件,子組件需要顯式地用props
選項聲明 “prop”:
③prop
是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是不會反過來。
④props
中的數據都是隻讀的,無法進行重新賦值。
二、子組件向父組件傳值
1. 傳值步驟
① 子組件需要以某種方式例如點擊事件的方法來觸發一個自定義事件;
② 將需要傳遞的值作爲$emit
的第二個參數,該值將作爲實參傳遞給響應自定義事件的方法;
③ 在父組件中註冊子組件,在子組件標籤上監聽該自定義事件,並添加一個響應該事件的處理方法
2. 代碼示例
點擊子組件中的按鈕,給父組件發送子組件的信息
<body>
<div id="app">
<h3>父組件</h3>
<child @receive="handleEvent"></child>
</div>
<script>
Vue.component('child', {
template: `
<div>
<h3>子組件</h3>
<button @click="sendMessage()">發送</button>
</div>
`,
data() {
return {
}
},
methods: {
sendMessage() { // 按鈕的點擊事件
this.$emit("receive","父組件您好,我是子組件!") // 調用父組件傳遞過來的方法,並且把數據傳遞出去
}
}
})
var vm = new Vue({
el: '#app',
methods: {
// 定義在子組件中通過 this.$emit() 調用的方法
handleEvent(val) {
console.log("父組件收到的消息是:",val)
}
}
})
</script>
</body>
【效果如下】
3. 注意事項
① 父組件是使用
props
傳遞數據給子組件,但如果子組件要把數據傳遞回去,就需要使用自定義事件!
② 我們可以使用v-on
綁定自定義事件, 每個 Vue 實例都實現了事件接口(Events interface),即:使用
$on(eventName)
監聽事件
使用$emit(eventName)
觸發事件③ 父組件可以在使用子組件的地方直接用
v-on
來監聽子組件觸發的事件。
三、大頭兒子小頭爸爸案例
這個案例實現了文章開頭:大頭兒子和小頭爸爸之間的通信
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>父子組件通信</title>
<script src="js/vue.js"></script>
<style>
.father,
.son {
width: 150px;
height: 100px;
}
.info {
color: #446ee4;
font-size: 20px;
font-size: bold;
}
.desc {
font-size: 18px;
}
.btn {
width: 100px;
float: left;
height: 40px;
font-size: 18px;
color: #fff;
font-weight: bold;
background: #446ee4;
margin-top: 15px;
}
.parent,
.child {
display: inline-block;
width: 550px;
}
</style>
</head>
<body>
<div id="app">
<div class="parent">
<img class="father" src="images/father.jpg">
<div class="info">我是小頭爸爸</div>
<div v-if="msg !== ''" class="desc">小頭爸爸接收到的消息:【{{msg}}】</div>
<div v-if="replyMsg !== ''" class="desc">小頭爸爸回覆說:【{{replyMsg}}】</div>
<button class="btn" @click="reply()">回覆</button></button>
</div>
<div class="child">
<child :reply-msg="replyMsg" @listen="listenHandle($event)"></child>
</div>
</div>
<script>
Vue.component('child', {
props: {
replyMsg: {
type: String,
default: ''
}
},
template: `
<div>
<img class="son" src="images/son.jpg">
<div class="info">我是大頭兒子</div>
<div v-if="msg !== ''" class="desc">大頭兒子說:【{{msg}}】</div>
<div v-if="replyMsg !== ''" class="desc">大頭兒子接收到的消息:【{{replyMsg}}】</div>
<button class="btn" @click="say()">說話</button>
</div>
`,
data() {
return {
msg: ''
}
},
methods: {
say() {
this.msg = '小頭爸爸好!'
this.$emit("listen", this.msg)
}
}
})
var vm = new Vue({
el: '#app',
data() {
return {
msg: '',
replyMsg: ''
}
},
methods: {
listenHandle(val) {
this.msg = val
},
reply() {
this.replyMsg = '小頭兒子好,消息已收到'
}
},
})
</script>
</body>
</html>
【效果如下】
四、總結
在組件傳值過程中,無論是父傳子、還是子傳父,它們都有一個共同點就是有一箇中間介質。父傳子的介質是
props
中的屬性,子傳父的介質是自定義事件。
父子組件的關係可以總結爲
prop
向下傳遞,事件向上傳遞。父組件通過prop給子組件下發數據,子組件通過事件給父組件發送信息。
父組件通過
v-bind:
綁定參數傳給子組件,子組件通過props
接受這個參數。
在組件的最底層開始寫事件,由最底層組件逐步向上$emit
事件流,並攜帶相應參數,最後在父組件內完成總的數據處理。
由於水平有限,本博客難免有不足,懇請各位大佬不吝賜教!