Vue2父子組件傳值舉例詳解
前言
在日常開發(fā)中,我們經(jīng)常會在一個組件中嵌套另外一個組件,那么如果我們父組件要向子組件傳值該怎么辦?子組件向父組件通信又該怎么辦?本文將詳細舉例說明這些問題。
父向子通信
問題描述
現(xiàn)在我們有個需求,我們要分別顯示父和子的信息,我們當然可以在一個組件中直接顯示全部信息,但是萬一以后又來一個需求:我們要在母和子的信息,那其實這里就存在冗余了,所以我們把子組件單獨封裝成一個新的組件。那么這里就會出現(xiàn)一個問題,子組件的信息該如何從父組件傳過去呢?
解決方案
使用vue提供的prop屬性,下面邊看代碼邊分析:
父組件定義
<template>
<div class="father">
這里是父組件,我們會在這里展示父的信息
{{ fatherName }}
{{ fatherAge }}
<son/>
</div>
</template>
<script>
import son from "@/components/son";
export default {
name: "father",
components: {
son
},
data() {
return {
fatherName: "張三",
fatherAge: 12
}
}
}
</script>
<style lang="css">
.father{
border: 1px solid black;
}
</style>子組件定義
<template>
<div class="son">
這里是子組件,我們會在這里展示子的信息
</div>
</template>
<script>
export default {
name: "son"
}
</script>
<style scoped>
.son{
margin: 10px;
border: 1px solid red;
}
</style>使用:attribute屬性向子組件傳入值
<template>
<div class="father">
這里是父組件,我們會在這里展示父的信息
{{ fatherName }}
{{ fatherAge }}
<son :sonInfo="sonInfo"/>
</div>
</template>
<script>
import son from "@/components/son";
export default {
name: "father",
components: {
son
},
data() {
return {
fatherName: "張三",
fatherAge: 12,
sonInfo: {
sonName: "王小虎",
sonAge: 6
}
}
}
}
</script>
<style lang="css">
.father {
border: 1px solid black;
}
</style>
子組件通過props屬性接收父組件傳過來的值,這里的名字要和父組件傳的值對應
<template>
<div class="son">
這里是子組件,我們會在這里展示子的信息
{{ sonInfo.sonName }}
{{ sonInfo.sonAge }}
</div>
</template>
<script>
export default {
name: "son",
props: ["sonInfo"]
}
</script>
<style scoped>
.son {
margin: 10px;
border: 1px solid red;
}
</style>測試

擴展
上述的例子解決了父子組件傳值的基本問題,當然prop的用法還有很多,我們可以在vue2官網(wǎng)上看到
Prop的大小寫
camelCase (駝峰命名法) 的 prop 名需要使用其等價的 kebab-case (短橫線分隔命名) 命名
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})<!-- 在 HTML 中是 kebab-case 的 --> <blog-post post-title="hello!"></blog-post>
Prop 類型
我們之前使用以字符串數(shù)組形式列出的 prop
props: ["sonInfo"]
我們也可以給每一個prop指定對應的值
props: {
title: String,//字符串
likes: Number,//數(shù)字
isPublished: Boolean,//布爾
commentIds: Array,//數(shù)組
author: Object,//對象
callback: Function,//函數(shù)
contactsPromise: Promise //異步延遲對象
}傳遞靜態(tài)或動態(tài) Prop
之前我們傳遞的是動態(tài)的Prop,可以動態(tài)賦值
<son :sonInfo="sonInfo"/>
我們也可以傳遞靜態(tài)的
<son :sonInfo="sonInfo" sex="1"/>
props: ["sonInfo", "sex"]
單向數(shù)據(jù)流
所有的 prop 都使得其父子 prop 之間形成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,但是反過來則不行。這樣會防止從子組件意外變更父級組件的狀態(tài),從而導致你的應用的數(shù)據(jù)流向難以理解。
額外的,每次父級組件發(fā)生變更時,子組件中所有的 prop 都將會刷新為最新的值。這意味著你不應該在一個子組件內(nèi)部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制臺中發(fā)出警告。
官方這段話表明了,我們對于父組件傳過來的值最不要直接修改,官方例舉了兩個常用的變更案例
1.這個 prop 用來傳遞一個初始值;這個子組件接下來希望將其作為一個本地的 prop 數(shù)據(jù)來使用
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}2.這個 prop 以一種原始的值傳入且需要進行轉(zhuǎn)換
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}類型校驗
之前我們使用字符串數(shù)組形式列出的 prop,父組件不知道子組件prop值的類型,可能傳值的時候傳錯,所以我們可以給值指定類型。如果有一個需求沒有被滿足,則 Vue 會在瀏覽器控制臺中警告你
Vue.component('my-component', {
props: {
// 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
propA: Number,
// 多個可能的類型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 帶有默認值的數(shù)字
propD: {
type: Number,
default: 100
},
// 帶有默認值的對象
propE: {
type: Object,
// 對象或數(shù)組默認值必須從一個工廠函數(shù)獲取
default: function () {
return { message: 'hello' }
}
},
// 自定義驗證函數(shù)
propF: {
validator: function (value) {
// 這個值必須匹配下列字符串中的一個
return ['success', 'warning', 'danger'].includes(value)
}
}
}
})當 prop 驗證失敗的時候,(開發(fā)環(huán)境構建版本的) Vue 將會產(chǎn)生一個控制臺的警告
子向父通信
問題描述
既然父可以向子傳值,那么子是否可以通信父呢?當然可以,這時候我們要借助vue的 e m i t 和 emit和 emit和on,下面我們看代碼:
解決方案
子組件
<template>
<div class="son">
這里是子組件
<button @click="emit">使用emit向父組件通信</button>
</div>
</template>
<script>
export default {
name: "son",
methods:{
emit(){
this.$emit('sayHi',"tom")
}
}
}
</script>
<style scoped>
.son {
margin: 10px;
border: 1px solid red;
}
</style>父組件
<template>
<div class="father">
這里是父組件
<son sex="1" @sayHi="sayHi"/>
</div>
</template>
<script>
import son from "@/components/son";
export default {
name: "father",
components: {
son
},
data() {
return {}
}, methods: {
sayHi(name) {
console.log("sayHi:"+name)
}
}
}
</script>
<style lang="css">
.father {
border: 1px solid black;
}
</style>測試
點擊按鈕,控制臺輸出sayHi tom
分析
這里首先介紹一下vue提供的兩個重要函數(shù)emit和on
on
監(jiān)聽當前實例上的自定義事件。事件可以由 $emit 觸發(fā)。回調(diào)函數(shù)會接收所有傳入事件觸發(fā)函數(shù)的額外參數(shù)。
上述例子的 @sayHi="sayHi"就是在監(jiān)聽sayHi事件,這里采用了簡寫形式,完整形式是v-on:sayHi=“sayHi”,我們平時用的比較多的就是監(jiān)聽點擊事件,而這里我們就是監(jiān)聽了我們自定義的事件
emit
觸發(fā)當前實例上的事件。附加參數(shù)都會傳給監(jiān)聽器回調(diào)。
當我們監(jiān)聽了自定義事件,我們就可以在子組件中觸發(fā)事件,this.$emit(‘sayHi’,“tom”),這樣就會調(diào)用監(jiān)聽的回調(diào)函數(shù),并且將附加參數(shù)tom傳入回調(diào)函數(shù)
非父子通信
除了上述的父子組件通信,我們最后還可以在非父子組件之間傳值,某些場景下會用到。下面看代碼:
事件總線
import Vue from "vue"; export default new Vue;
組件B
<template>
<div>
組件B
{{ value }}
</div>
</template>
<script>
import bus from "@/components/bus";
export default {
name: "ComponentB",
data() {
return {
value: "oldVal"
}
}, created() {
bus.$on("changeVal", newVal => {
this.value = "newVal"
})
}
}
</script>
<style scoped>
</style>組件A
<template>
<div>
組件A
<button @click="communicate">組件A->組件B</button>
</div>
</template>
<script>
import bus from "@/components/bus";
export default {
name: "ComponentA",
methods:{
communicate(){
bus.$emit("changeVal","newVal")
}
}
}
</script>
<style scoped>
</style>測試
組件B的值由oldVal->newVal
分析
這里引入了事件總線(event bus)的概念,事件總線:事件發(fā)送者將事件消息發(fā)送到一個事件總線上,事件訂閱者向事件總線訂閱和接收事件,然后再處理接收到的事件
而我們這里的事件總線的載體就是一個Vue的實例對象,因為在emit和on都是Vue的一個實例方法。
當然我們還可以使用$attrs / listeners來實現(xiàn)類似效果,這里就不多做介紹了,有興趣的讀者可以自行了解
但是如果學過Vuex的話,利用Vuex來傳值會很方便,Vuex之后會慢慢講,不急。學習是個漫長的過程,慢慢來
總結
到此這篇關于Vue2父子組件傳值的文章就介紹到這了,更多相關Vue2父子組件傳值內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
vue3的watch用法以及和vue2中watch的區(qū)別
這篇文章主要介紹了vue3的watch用法以及和vue2中watch的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
vue項目報錯Uncaught runtime errors的解決方案
使用vue-cli的vue項目,出現(xiàn)編譯錯誤或警告時,在瀏覽器中顯示全屏覆蓋,提示報錯Uncaught runtime errors,本文給大家介紹了vue項目報錯Uncaught runtime errors的解決方案,需要的朋友可以參考下2024-01-01
利用webstrom調(diào)試Vue.js單頁面程序的方法教程
這篇文章主要給大家介紹了利用webstrom調(diào)試Vue.js單頁面程序的方法教程,文中介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面跟著小編一起來學習學習吧。2017-06-06

