詳細(xì)解讀VUE父子組件的使用
我們對父子組件的學(xué)習(xí),接觸的一般是子組件通過事件傳參給父組件,父組件拿到參數(shù)再進(jìn)行處理,用來處理表單提交,彈框信息等等,再者就是父組件通過自定義屬性傳值給子組件,子組件通過props接收,watch監(jiān)聽新值,達(dá)到組件的復(fù)用的效果;
后我在vue官網(wǎng)接觸到一種子父組件深度耦合的方式,使我們不用額外的創(chuàng)建新的組件,也可以達(dá)到一些效果,下面與你們分享一下:
1.遞歸組件
看名字我們就知道,這是對組件進(jìn)行遞歸,vue給我們提供的不只是遞歸子組件,而且可以在自己的模板中調(diào)用自己;
//parent.vue
<template>
<div>
//對子組件傳值
<HomeView :list="list"></HomeView>
</div>
</template>
import HomeView from "./HomeView.vue";
<script>
export default{
component:{
HomeView
}
data(){
return{
list: [{
name: "經(jīng)濟(jì)",
children: [{
name: "如家",
children: [{
name: "上江路-如家"
},
{
name: "望江路-如家"
}]
},{
name: "7天",
children: [{
name: "長江路-7天"
},
{
name: "望江路-7天"
}]
}]
}],
}
}
}
</script>這里面的數(shù)據(jù)是嵌套的,嵌套兩層children,一般我們可能會拿到數(shù)據(jù)用兩個標(biāo)簽嵌套渲染,這里vue給我們提供了調(diào)用自己組件的方法:
//child.vue
<template>
<div>
<div class="list-item" v-for="(item, index) in list" :key="index">
<div class="item-name">
<span>{{item.name}}</span>
</div>
<div v-if="item.children" class="children-item">
//調(diào)用自身 節(jié)省一個for循環(huán)
<HomeView :list="item.children"></HomeView>
</div>
</div>
</div>
</template>
<script>
export default{
//通過name選項做調(diào)用自身的事情
name:'HomeView',
props:{
list: Array
},
}
</script>讓原本兩次for循環(huán)的模板變得簡潔易懂,雖然節(jié)省了一次for循環(huán),但是這樣做也是有缺點的,就是容易陷入無限循環(huán)中,這是我們需要注意的,最后得到的效果是:

這是vue給我們提供的多一種的使用組件方式
2.組件之間的循環(huán)使用
你可以理解為子父組件的深度耦合,相互調(diào)用從而更方便達(dá)到節(jié)點數(shù)的效果,形成相互循環(huán)渲染的效果
效果圖:

數(shù)據(jù)源:
folders: [
{
name: 'folder1',
children: [{
name: 'folder1 - folder1',
children: [{
name: 'folder1 - folder1 - folder1'
}]
}, {
name: 'folder1 - folder2',
children: [{
name: 'folder1 - folder2 - folder1'
}, {
name: 'folder1 - folder2 - folder2'
}]
}]
},
{
name: 'folder 2',
children: [{
name: 'folder2 - folder1',
children: [{
name: 'folder2 - folder1 - folder1'
}]
}, {
name: 'folder2 - folder2',
children: [{
name: 'folder2-content1'
}]
}]
},
{
name: 'folder 3',
children: [{
name: 'folder3 - folder1',
children: [{
name: 'folder3 - folder1 - folder1'
}]
}, {
name: 'folder3 - folder2',
children: [{
name: 'folder3-content1'
}]
}]
}
],這個案例有爺爺組件這塊我有在全局進(jìn)行注冊,HomeView.vue是爺爺組件,包含數(shù)據(jù)源,引進(jìn)父級組件等操作;
main.js全局注冊:

HomeView.vue(爺爺組件):
<template>
<div class="home">
<li v-for="folder in folders">
<about-view :folder="folder"></about-view>
</li>
</div>
</template>
<script>
//引進(jìn)父組件
import AboutView from './AboutView.vue';
export default {
components:{
AboutView,
},
data(){
return{
folders: [
{
name: 'folder1',
children: [{
name: 'folder1 - folder1',
children: [{
name: 'folder1 - folder1 - folder1'
}]
}, {
name: 'folder1 - folder2',
children: [{
name: 'folder1 - folder2 - folder1'
}, {
name: 'folder1 - folder2 - folder2'
}]
}]
},
{
name: 'folder 2',
children: [{
name: 'folder2 - folder1',
children: [{
name: 'folder2 - folder1 - folder1'
}]
}, {
name: 'folder2 - folder2',
children: [{
name: 'folder2-content1'
}]
}]
},
{
name: 'folder 3',
children: [{
name: 'folder3 - folder1',
children: [{
name: 'folder3 - folder1 - folder1'
}]
}, {
name: 'folder3 - folder2',
children: [{
name: 'folder3-content1'
}]
}]
}
],
}
},
}
</script>AboutView.vue(父級組件):
<template>
<div class="about">
<p>
<span>{{folder.name}}</span>
<second-view :children="folder.children"></second-view>
</p>
</div>
</template>
<script>
export default{
props:['folder'],
components:{
// HomeView
SecondView:()=>import('./SecondView.vue')
},
data(){return{}},
}
</script>SecondView.vue(孫子組件):
<template>
<div>
<ul>
<li v-for="child in children">
<about-view v-if="child.children" :folder="child"></about-view>
<span v-else>{{child.name}}</span>
</li>
</ul>
</div>
</template>
<script>
// import AboutView from './AboutView.vue'
export default{
props:['children'],
components:{
AboutView:()=>import ('./AboutView.vue')
},
data(){return{}},
}
</script>寫這個案例的時候出現(xiàn)了一個報錯,是一個引入的邏輯錯誤,你需要找到一個循環(huán)支撐點,而又不能讓他陷入無限循環(huán),所以我讓爺爺組件在全局注冊,讓子父組件異步引入,這樣就可以解決報錯問題,當(dāng)然解決方法還有其他方式,例如在beaforecreate中引入,利用webpack等,歡迎相互討論!
二,深層次的問題
該文章是介紹對于多次使用的表單抽離成公共組件,圍繞抽離的公共組件的一些技巧和方法;
包含公共組件在父組件的多次使用方法,父組件通過ref調(diào)用子組件的方法等;
這是最基礎(chǔ)的組件通訊方案:
1,2,3是回顧子組件,父子間,非父子組件的傳參;
4,5介紹的是子組件復(fù)用,父組件調(diào)用子組件的方法使用;
**1.父傳子**
/父傳子是自定義屬性傳值給子組件,子組件通過props接受傳值,并渲染
//父頁面
//<!-- 通過自定義屬性傳值給子組件 -->
<Child :msg='msg'></Child>
return {
msg:'父組件的值'
}
//子頁面
<p>父組件的值為:{{msg}}</p>
// 接受父組件傳過來的值
props:['msg'],**2.子傳父*
//子傳父是自定義事件,通過$emit發(fā)送,父組件綁定自定義事件 //子組件
<button @click="sentInfo">通過自定義事件將值發(fā)送給父組件</button>
return {
childInfo:'子組件的值'
}
methods: {
sentInfo(){
// 發(fā)送自定義事件
// console.log(this)
// this.$emit('自定義事件名',發(fā)送的值)
this.$emit('sendV',this.childInfo)
}
},
//父組件
<!-- 監(jiān)聽子組件的自定義事件 -->
Child @sendV='showInfo'></Child>
return {
msg:'',//等待子組件的值
}
methods:{
// 監(jiān)聽的事件的函數(shù)的第一個參數(shù)就是傳過來的值
showInfo(v){
console.log(v)// v只在{}內(nèi)有效,父組件模板想要使用這個值,必須將值保存到自己的data中
this.msg = v
}
}**3.兄弟關(guān)系**
main.js中
//bus事件中心
Vue.prototype.$event = new Vue()
//兄弟組件是先在main.js初始化頁面自定義事件通過?emit發(fā)送,b頁面$on監(jiān)聽,
one.vue:
<button @click="senMsg">發(fā)起自定義事件并攜帶參數(shù)</button>
return {
msg:"one組件的值"
},
methods:{
senMsg(){
this.$event.$emit('sendmsgInfo',this.msg)
}
}
//two.vue 監(jiān)聽自定義事件,并接受
mounted() {
// 進(jìn)入頁面就開始監(jiān)聽one的自定義事件
// this.$event.$on('監(jiān)聽的自定義事件名'函數(shù)(函數(shù)的第一個參數(shù)就是傳過來的值))
this.$event.$on('sendmsgInfo',(v)=>{
console.log(v)//one組件的值
})
},4.子組件復(fù)用
//這是需要復(fù)用的結(jié)構(gòu),需要抽離成公共組件
<template>
<div class=".main_input">
<el-select
v-model="name"
filterable
:filter-method="typeFiltersixone"
placeholder="請選擇"
@change="chooseCustom"
ref="multiSelectsixone"
clearable>
<el-option
:value="treeDataValue"
style="height: auto">
<el-tree
:data="uDeptOptions"
:props="defaultProps"
:expand-on-click-node="false"
:filter-node-method="filterNode"
ref="treesixone"
default-expand-all
@node-click="handleNodeClick"
node-key="deptId" />
</el-option>
</el-select>
</div>
</template>需求是需要復(fù)用表單查詢,寫一個組件復(fù)用人員查詢模塊;
這是正常的子父組件信息通訊,子組件通過事件$emit傳遞name和id,父組件傳值watch監(jiān)聽變化;
//父組件傳值監(jiān)聽
props:{
wzryName:{
required: false
},
wzryId:{
required: false
},
},
watch:{
wzryName:{
handler(newValue, oldValue){
this.name = newValue
}
},
wzryId:{
handler(newValue, oldValue){
this.ids = newValue
}
}
},復(fù)用的方案是使用同一個子組件,父組件使用時,用單獨的方法!
//這就是復(fù)用的結(jié)構(gòu),
//staff-queryitem是復(fù)用組件,復(fù)用兩次,不同的是@returninput的方法不一樣
<el-col :span="5">
<el-form-item label="派發(fā)人姓名" prop="pfryxm">
<staff-queryitem @returninput="inputData"></staff-queryitem>
//第一個組件時inpuData方法
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="監(jiān)督人姓名" prop="jdryxm">
<staff-queryitem @returninputtwo="inputDatatwo"></staff-queryitem>
//第二個組件時inputDatatwo方法
</el-form-item>
</el-col>單獨傳參
//子傳父
//兩次復(fù)用對應(yīng)兩各不同的方法,分別傳參
inputData(name,id){
this.queryParams.pfryxm=name
this.queryParams.pfryId=id
},
inputDatatwo(name,id){
this.queryParams.jdryxm=name
this.queryParams.jdryId=id
},5.父組件通過ref調(diào)用子組件的方法
案例一:父組件調(diào)用子組件的方法,對父組件的數(shù)據(jù)進(jìn)行處理
//以轉(zhuǎn)換字符串方法為例:
//子組件的方法
methods:{
//在子組件中寫好一個反轉(zhuǎn)字符串的方法,
changetext(value){
return value.split('').reverse().join("");
}
},
//父組件
<template>
<div class="home">
<p>{{list}}</p>
<One ref="once"></One>
<button @click="reverse">轉(zhuǎn)換子組件</button>
</div>
</template>
//引入子組件
import One from '../components/One.vue';
export default {
components:{
One,
},
data(){
return{
list:'hellow'
}
},
methods:{
通過ref調(diào)用子組件寫好的changetext方法
reverse(){
console.log(this.$refs.once)//返回的是一個vue對象,所以可以直接調(diào)用其方法
this.list= this.$refs.once.changetext(this.list)
},
},
}
</script>此方法可以用來解決子組件復(fù)用時,需要對表單進(jìn)行聯(lián)動時使用;避免子父組件的反復(fù)傳參;
案例二:父組件調(diào)用組件一的方法,調(diào)用組件二的數(shù)據(jù)進(jìn)行處理
//還是以反轉(zhuǎn)字符串為例
//組件一:
methods:{
//組件一提供方法
changetext(value){
return value.split('').reverse().join("");
}
},
//組件二:
<template>
<div class="home">
<p>{{list}}</p>
<button @click="twos">發(fā)送數(shù)據(jù)</button>
</div>
</template>
<script>
export default {
data(){
return{
list:'總是在夢里 我看到你無助的雙眼'
}
},
methods:{
//組件二點擊發(fā)送this.list數(shù)據(jù)給父組件
twos(){
this.$emit('sendV',this.list)
},
},
}
</script>
//父組件
<template>
<div class="home">
<p>{{info}}</p>
<One ref="once"></One>
<Two @sendV="Towsinfo"></Two>
<button @click="reverse">轉(zhuǎn)換子組件</button>
</div>
</template>
<script>
import One from '../components/One.vue'
import Two from '../components/Two.vue'
export default {
components:{
One,
Two
},
data(){
return{
info:''
}
},
methods:{
reverse(){
this.info= this.$refs.once.changetext(this.info)
},
Towsinfo(v){
console.log(v); //組件二發(fā)送的數(shù)據(jù)
this.info=v //需要有一個變量接收
}
},
}
</script>
通過這兩個案例發(fā)現(xiàn)vue通過ref操作dom帶來的好處是很明顯的,便捷靈活的實現(xiàn)方案需求
到此這篇關(guān)于詳細(xì)解讀VUE父子組件的使用的文章就介紹到這了,更多相關(guān)VUE父子組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue中利用three.js實現(xiàn)全景圖的完整示例
這篇文章主要給大家介紹了關(guān)于vue中利用three.js實現(xiàn)全景圖的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
Vue??vuex配置項和多組件數(shù)據(jù)共享案例分享
這篇文章主要介紹了Vue??vuex配置項和多組件數(shù)據(jù)共享案例分享,文章圍繞Vue?Vuex的相關(guān)資料展開配置項和多組件數(shù)據(jù)共享的案例分享,需要的小伙伴可以參考一下2022-04-04
vue-cli腳手架config目錄下index.js配置文件的方法
下面小編就為大家分享一篇vue-cli腳手架config目錄下index.js配置文件的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03
vue中promise的使用及異步請求數(shù)據(jù)的方法
這篇文章主要介紹了vue中promise的使用及異步請求數(shù)據(jù)的方法,文章給大家較詳細(xì)的介紹了遇到的問題及解決方法,需要的朋友可以參考下2018-11-11
Vue Element前端應(yīng)用開發(fā)之樹列表組件
本篇隨筆主要介紹樹列表組件和下拉列表樹組件在項目中的使用,以及一個SplitPanel的組件。2021-05-05
Vue3+TypeScript封裝axios并進(jìn)行請求調(diào)用的實現(xiàn)
這篇文章主要介紹了Vue3+TypeScript封裝axios并進(jìn)行請求調(diào)用的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

