Vue子組件與父組件詳細(xì)解析
一、父組件和子組件
我們經(jīng)常分不清什么是父組件,什么是子組件?,F(xiàn)在來(lái)簡(jiǎn)單總結(jié)下:我們將某段代碼封裝成一個(gè)組件,而這個(gè)組件又在另一個(gè)組件中引入,而引入該封裝的組件的文件叫做父組件,被引入的組件叫做子組件。
具體代碼如下:
<div id="app"> <component2></component2> </div> <script> // 全局注冊(cè) Vue.component("component1", { template: ` <div> <h2>hello</h2> </div> ` }) const app = new Vue({ el: "#app", data: { message: "hello" }, components: { // 局部注冊(cè) "component2": { template: ` <div> <component1></component1> <h2>world</h2> </div> `, } } }) </script>
- 1.全局注冊(cè)組件
component1
- 2.局部注冊(cè)組件
component2
,component2
中又引用了組件component1
最后我們?cè)趆tml中使用組件component-2
,
模板代碼就是:
<div> <component-1></component-1> <h2>world</h2> </div>
又因?yàn)榻M件component1
中也有模板,所以程序會(huì)自動(dòng)進(jìn)行解析,最后component-2
的html
代碼為
<div> <div> <h2>hello</h2> </div> <h2>world</h2> </div>
所以我們?cè)跒g覽器上看到的效果應(yīng)該是:
hello
world
結(jié)果:
component1
是子組件,component2
是父組件
二、模板分離寫法
上面我們創(chuàng)建組件的時(shí)候,都在組件中寫了模板template
,但是在編譯器里這樣寫,不僅沒(méi)有代碼提示,而且換行也不對(duì)齊,寫起來(lái)很麻煩,所以這里介紹模板分離寫法
1、template標(biāo)簽
我們將原來(lái)在組件里寫的template
模板抽離出來(lái),放在html
中,使用template
標(biāo)簽,并且給他附上id屬性如下:
<template id="component2"> <div> <component1></component1> <h2>world</h2> </div> </template>
然后在組件中,將原來(lái)template
標(biāo)簽的內(nèi)容換成id,這樣程序就會(huì)自動(dòng)去尋找對(duì)應(yīng)的id模板:
components: { // 局部注冊(cè) "component2": { template: `#component2`, } }
推薦這種寫法
2、text/x-template
我們還有另一中寫法,跟上面差不多,上面我們用的template
標(biāo)簽,此寫法只需將template
中的內(nèi)容放到script
標(biāo)簽中,并給與類型type=text/x-template
,再給上一個(gè)id屬性即可,
如下:
<script type="text/x-template" id="component2"> <div> <component1></component1> <h2>world</h2> </div> </script>
三、父子組件通信-父?jìng)髯?/h2>
當(dāng)我們創(chuàng)建了父組件和子組件,如果子組件也想獲取父組件上相同的數(shù)據(jù),一種方法是像后臺(tái)發(fā)送接口獲取數(shù)據(jù),但是這樣會(huì)給服務(wù)器造成壓力,所以我們有了第二種方法,通過(guò)props
屬性來(lái)獲取父組件的數(shù)據(jù)
<div id="app"> <test1 :cmovies="movies"></test1> </div> <template id="test1"> <div> <ul> <li v-for="item in cmovies">{{item}}</li> </ul> </div> </template> <script> const app = new Vue({ el: "#app", data: { movies: ["海賊王", "海爾兄弟", "海王"] }, components: { "test1": { template: `#test1`, props: ['cmovies'], data(){ return{} }, } } }) </script>
這里我們將app
實(shí)例定義為父組件,又定義了子組件test1
,此時(shí)子組件test1
想獲取父組件data
中的數(shù)據(jù)來(lái)展示在頁(yè)面上,就需要寫入props屬性,這里綁定了變量cmovies,最后我們?cè)趆tml中使用子組件test1
時(shí),想傳入父組件data
中的數(shù)據(jù),就需要綁定屬性,:cmovies="movies",cmovies
是props中定義的變量,綁定的值是movies列表,所以上面的代碼<li v-for="item in cmovies">{{item}}</li>中的cmoviess
的值其實(shí)是列表movies
的數(shù)據(jù),因?yàn)楦附M件已經(jīng)向子組件傳遞了值
最后網(wǎng)頁(yè)上就能顯示movies中的電影了
以上頁(yè)面上顯示的無(wú)序列表,我們是使用了子組件,數(shù)據(jù)是從父組件data
中傳入到了子組件,子組件通過(guò)props
與父組件綁定
1、Prop 類型
上面的例子我們把props
定義成為了一個(gè)數(shù)組,用于接收來(lái)自父組件的數(shù)據(jù)。我們也可以使用對(duì)象作為替代,對(duì)象允許配置高級(jí)選項(xiàng),如類型檢測(cè)、自定義驗(yàn)證和設(shè)置默認(rèn)值。
- type:可以是下列原生構(gòu)造函數(shù)中的一種:
String、Number、Boolean、Array、Object、Date、Function、Symbol
、任何自定義構(gòu)造函數(shù)、或上述內(nèi)容組成的數(shù)組。會(huì)檢查一個(gè)prop
是否是給定的類型,否則拋出警告。Prop
類型的更多信息在此。 - default:
any
為該prop
指定一個(gè)默認(rèn)值。如果該prop
沒(méi)有被傳入,則換做用這個(gè)值。對(duì)象或數(shù)組的默認(rèn)值必須從一個(gè)工廠函數(shù)返回。 - required:
Boolean
定義該prop
是否是必填項(xiàng)。在非生產(chǎn)環(huán)境中,如果這個(gè)值為truthy
且該prop
沒(méi)有被傳入的,則一個(gè)控制臺(tái)警告將會(huì)被拋出。 - validator:
Function
自定義驗(yàn)證函數(shù)會(huì)將該prop
的值作為唯一的參數(shù)代入。在非生產(chǎn)環(huán)境下,如果該函數(shù)返回一個(gè) falsy 的值 (也就是驗(yàn)證失敗),一個(gè)控制臺(tái)警告將會(huì)被拋出。你可以在這里查閱更多prop
驗(yàn)證的相關(guān)信息。
示例:
// 簡(jiǎn)單語(yǔ)法 Vue.component('props-demo-simple', { props: ['size', 'myMessage'] }) // 對(duì)象語(yǔ)法,提供驗(yàn)證 Vue.component('props-demo-advanced', { props: { // 檢測(cè)類型 height: Number, // 檢測(cè)類型 + 其他驗(yàn)證 age: { type: Number, default: 0, required: true, validator: function (value) { return value >= 0 } } } })
注意:當(dāng)我們?cè)谑褂?code>props時(shí),如果我們使用駝峰命名法,比如cMovies
,然后我們?cè)?code>HTML中綁定時(shí)如果也這么寫,程序是不識(shí)別的,我們需要轉(zhuǎn)成c-movies
這種短橫線形式
四、父子組件通信子傳父
子傳父的場(chǎng)景,通常是子組件傳遞事件給父組件監(jiān)聽(tīng),告訴父組件用戶點(diǎn)擊了哪個(gè)按鈕,使用的函數(shù)是$emit
1、vm.$emit( eventName, […args] )
參數(shù):
- eventName:事件名字
- args:不定長(zhǎng)的數(shù)組
觸發(fā)當(dāng)前實(shí)例上的事件。附加參數(shù)都會(huì)傳給監(jiān)聽(tīng)器回調(diào)。
示例:
<div id="app"> <test1 @item-click="cpnClick"></test1> </div> <template id="test1"> <div> <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button> </div> </template> <script> const app = new Vue({ el: "#app", data: { message: "hello" }, methods: { cpnClick(item){ console.log("success", item) } }, components: { // 局部注冊(cè)組件test1 "test1": { data(){ return{ categories: [ {id: "aaa", name: "熱門推薦"}, {id: "bbb", name: "手機(jī)數(shù)碼"}, {id: "ccc", name: "家用電器"}, {id: "ddd", name: "食品飲料"}, ] } }, methods: { btnClick(item){ this.$emit("item-click", item) } }, template: `#test1` } } }) </script>
以上代碼定義了test1
子組件,并在methods
中通過(guò)$emit
傳遞了事件和額外的參數(shù)item
,然后父組件通過(guò)@item-click="cpnClick"
事件綁定,這樣父組件就能收到子組件的點(diǎn)擊事件,并且觸發(fā)自己的點(diǎn)擊事件,效果如下
我們可以看到控制臺(tái)打印的日志中含有子組件的categories
的分類
五、父子組件通信-結(jié)合雙向綁定案例
下面這個(gè)案例結(jié)合了父?jìng)髯雍妥觽鞲福€有v-model
,是個(gè)非常全面的案例
1、基本模板代碼
<div id="app"> <cpn :number1="num1" :number2="num2"></cpn> </div> <template id="cpn"> <div> <h2>{{number1}}</h2> <h2>{{number2}}</h2> </div> </template> <script> const app = new Vue({ el: "#app", data: { num1: 0, num2: 1, }, components: { // 定義子組件cpn "cpn": { template: `#cpn`, props: { number1: Number, number2: Number, } } }, }) </script>
代碼做了如下的事情
- 1.定義了子組件
cpn
,又定義了2個(gè)屬性number1
和number2
用來(lái)接收父組件傳遞的數(shù)據(jù) - 2.在
html
代碼中引用了子組件cpn,并將app實(shí)力中的num1和num2傳遞給子組件props中的屬性 - 3.最后我們?cè)陧?yè)面上顯示的數(shù)據(jù)
number1
和number2其實(shí)就是data中的num1和num2
最后頁(yè)面展示的效果就是:
0
1
2、增加雙向綁定
在上面的模板基礎(chǔ)上,我們新增雙向綁定,新增2
個(gè)input
標(biāo)簽,并使用v-model
與props
中的屬性進(jìn)行綁定
<template id="cpn"> <div> <h2>props:{{number1}}</h2> <input type="text" v-model="number1"> <h2>props:{{number2}}</h2> <input type="text" v-model="number2"> </div> </template>
以上代碼就完成了雙向綁定,但是會(huì)有報(bào)錯(cuò)警告
當(dāng)我們?cè)谧咏M件中與props
雙向綁定的時(shí)候,會(huì)出現(xiàn)警告,意思是不要使用props
雙向綁定,建議使用data
或者compused
來(lái)雙向綁定,這里修改成與data
綁定
<template id="cpn"> <div> <h2>data:{{dnumber1}}</h2> <input type="text" v-model="dnumber1"> <h2>data:{{dnumber2}}</h2> <input type="text" v-model="dnumber2"> </div> </template> data(){ return{ dnumber1: this.number1, dnumber2: this.number2, } },
當(dāng)我們與data
進(jìn)行綁定以后,就不會(huì)出現(xiàn)報(bào)錯(cuò)了
3、反向綁定
接著上面的思路,我們希望input
輸入值的時(shí)候,改變data
中的同時(shí),也同時(shí)改變父組件中num1
和num2
的值,這時(shí)就需要反向綁定通過(guò)子傳父,
下面是完整的代碼:
<div id="app"> <cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"></cpn> </div> <template id="cpn"> <div> <h2>props:{{number1}}</h2> <h2>data:{{dnumber1}}</h2> <label> <input type="text" :value="dnumber1" @input="num1Input"> </label> <h2>props:{{number2}}</h2> <h2>data:{{dnumber2}}</h2> <label> <input type="text" :value="dnumber2" @input="num2Input"> </label> </div> </template> <script> const app = new Vue({ el: "#app", data: { num1: 0, num2: 1, }, methods: { num1change(value){ this.num1 = parseInt(value) }, num2change(value){ this.num2 = parseInt(value) }, }, components: { // 定義子組件cpn "cpn": { template: `#cpn`, props: { number1: Number, number2: Number, }, data(){ return{ dnumber1: this.number1, dnumber2: this.number2, } }, methods: { num1Input(event){ // 1.將input中的value賦值到dnumber中 this.dnumber1 = event.target.value // 2.為了讓父組件可以修改值,需要發(fā)出一個(gè)事件 this.$emit("num1change", this.dnumber1) }, num2Input(event){ // 1.將input中的value賦值到dnumber中 this.dnumber2 = event.target.value // 2.為了讓父組件可以修改值,需要發(fā)出一個(gè)事件 this.$emit("num2change", this.dnumber2) } } } }, }) </script>
效果如下:
六、組件訪問(wèn)父訪問(wèn)子
當(dāng)我們父組件中需要使用子組件中的函數(shù)或者屬性值,我們可以使用$refs
,它返回的類型是Object
,先看如下代碼
<div id="app"> <cpn ref="aaa"></cpn> <button @click="btnClick">按鈕</button> </div> <template id="cpn"> <div> 我是子組件 </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message: "hello" }, methods: { btnClick(){ console.log(this.$refs.aaa.name) this.$refs.aaa.showMessage() } }, components: { "cpn": { template: `#cpn`, data(){ return{ name: "我是子組件的name" } }, methods: { showMessage(){ console.log("showMessage") } } } } }) </script>
上述代碼干了如下幾件事情
- 1.創(chuàng)建了組件
cpn
,組件中定義了一個(gè)方法showMessage
和屬性name
- 2.父組件中使用子組件
cpn
,并綁定了一個(gè)屬性ref
值為aaa
,相當(dāng)于是唯一標(biāo)識(shí) - 3.父組件的方法
btnClick
需要使用子組件中的方法和屬性,只需要this.$refs.aaa
,這里的aaa就是上面綁定的子組件的屬性 - 4.最后使用
this.$refs.aaa.name
就代表使用了子組件中的name
屬性
到此這篇關(guān)于Vue子組件與父組件詳細(xì)解析的文章就介紹到這了,更多相關(guān)Vue子組件與父組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue項(xiàng)目打包后可修改基礎(chǔ)接口地址配置的具體操作
vue項(xiàng)目打包過(guò)后發(fā)現(xiàn)地址錯(cuò)了或者發(fā)布到別的服務(wù)器發(fā)現(xiàn)請(qǐng)求的地址不對(duì),每次都要去重新打包,太浪費(fèi)時(shí)間,下面這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目打包后可修改基礎(chǔ)接口地址配置的具體操作,需要的朋友可以參考下2022-08-08vue 項(xiàng)目中使用Loading組件的示例代碼
這篇文章主要介紹了vue 項(xiàng)目中使用Loading組件的示例代碼,使用 loding 過(guò)渡數(shù)據(jù)的加載時(shí)間2018-08-08vite創(chuàng)建vue3項(xiàng)目頁(yè)面引用public下js文件失敗解決辦法
Vue3相較于之前的版本有了不少變化,如引用全局Js文件,這篇文章主要給大家介紹了關(guān)于vite創(chuàng)建vue3項(xiàng)目頁(yè)面引用public下js文件失敗的解決辦法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11vue使用Highcharts實(shí)現(xiàn)3D餅圖
這篇文章主要為大家詳細(xì)介紹了vue使用Highcharts實(shí)現(xiàn)3D餅圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03vue實(shí)現(xiàn)一個(gè)6個(gè)輸入框的驗(yàn)證碼輸入組件功能的實(shí)例代碼
這篇文章主要介紹了vue實(shí)現(xiàn)一個(gè)6個(gè)輸入框的驗(yàn)證碼輸入組件功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06Vue使用 onMounted 確保在組件掛載后執(zhí)行異步操作示例詳解
在 Vue.js 或其他類似框架中,使用 onMounted 是為了確保在組件掛載后執(zhí)行異步操作,這篇文章主要介紹了Vue使用onMounted確保在組件掛載后執(zhí)行異步操作,需要的朋友可以參考下2023-06-06vue項(xiàng)目本地開(kāi)發(fā)完成后部署到服務(wù)器后報(bào)404錯(cuò)誤解決方案
很多時(shí)候我們發(fā)現(xiàn)辛辛苦苦寫的VueJs應(yīng)用經(jīng)過(guò)打包后在自己本地搭建的服務(wù)器上測(cè)試沒(méi)有什么問(wèn)題,但真正放在服務(wù)器上后會(huì)發(fā)現(xiàn)或多或少的問(wèn)題,這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目本地開(kāi)發(fā)完成后部署到服務(wù)器后報(bào)404錯(cuò)誤的解決方案,需要的朋友可以參考下2024-01-01