詳細(xì)解讀VUE父子組件的使用
我們對(duì)父子組件的學(xué)習(xí),接觸的一般是子組件通過事件傳參給父組件,父組件拿到參數(shù)再進(jìn)行處理,用來處理表單提交,彈框信息等等,再者就是父組件通過自定義屬性傳值給子組件,子組件通過props接收,watch監(jiān)聽新值,達(dá)到組件的復(fù)用的效果;
后我在vue官網(wǎng)接觸到一種子父組件深度耦合的方式,使我們不用額外的創(chuàng)建新的組件,也可以達(dá)到一些效果,下面與你們分享一下:
1.遞歸組件
看名字我們就知道,這是對(duì)組件進(jìn)行遞歸,vue給我們提供的不只是遞歸子組件,而且可以在自己的模板中調(diào)用自己;
//parent.vue <template> <div> //對(duì)子組件傳值 <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,一般我們可能會(huì)拿到數(shù)據(jù)用兩個(gè)標(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é)省一個(gè)for循環(huán) <HomeView :list="item.children"></HomeView> </div> </div> </div> </template> <script> export default{ //通過name選項(xiàng)做調(diào)用自身的事情 name:'HomeView', props:{ list: Array }, } </script>
讓原本兩次for循環(huán)的模板變得簡潔易懂,雖然節(jié)省了一次for循環(huán),但是這樣做也是有缺點(diǎn)的,就是容易陷入無限循環(huán)中,這是我們需要注意的,最后得到的效果是:
這是vue給我們提供的多一種的使用組件方式
2.組件之間的循環(huán)使用
你可以理解為子父組件的深度耦合,相互調(diào)用從而更方便達(dá)到節(jié)點(diǎn)數(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' }] }] } ],
這個(gè)案例有爺爺組件這塊我有在全局進(jìn)行注冊(cè),HomeView.vue是爺爺組件,包含數(shù)據(jù)源,引進(jìn)父級(jí)組件等操作;
main.js全局注冊(cè):
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(父級(jí)組件):
<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>
寫這個(gè)案例的時(shí)候出現(xiàn)了一個(gè)報(bào)錯(cuò),是一個(gè)引入的邏輯錯(cuò)誤,你需要找到一個(gè)循環(huán)支撐點(diǎn),而又不能讓他陷入無限循環(huán),所以我讓爺爺組件在全局注冊(cè),讓子父組件異步引入,這樣就可以解決報(bào)錯(cuò)問題,當(dāng)然解決方法還有其他方式,例如在beaforecreate中引入,利用webpack等,歡迎相互討論!
二,深層次的問題
該文章是介紹對(duì)于多次使用的表單抽離成公共組件,圍繞抽離的公共組件的一些技巧和方法;
包含公共組件在父組件的多次使用方法,父組件通過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ù)的第一個(gè)參數(shù)就是傳過來的值 showInfo(v){ console.log(v)// v只在{}內(nèi)有效,父組件模板想要使用這個(gè)值,必須將值保存到自己的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ù)的第一個(gè)參數(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="請(qǐng)選擇" @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ù)用表單查詢,寫一個(gè)組件復(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ù)用的方案是使用同一個(gè)子組件,父組件使用時(shí),用單獨(dú)的方法!
//這就是復(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> //第一個(gè)組件時(shí)inpuData方法 </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="監(jiān)督人姓名" prop="jdryxm"> <staff-queryitem @returninputtwo="inputDatatwo"></staff-queryitem> //第二個(gè)組件時(shí)inputDatatwo方法 </el-form-item> </el-col>
單獨(dú)傳參
//子傳父 //兩次復(fù)用對(duì)應(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)用子組件的方法,對(duì)父組件的數(shù)據(jù)進(jìn)行處理
//以轉(zhuǎn)換字符串方法為例: //子組件的方法 methods:{ //在子組件中寫好一個(gè)反轉(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)//返回的是一個(gè)vue對(duì)象,所以可以直接調(diào)用其方法 this.list= this.$refs.once.changetext(this.list) }, }, } </script>
此方法可以用來解決子組件復(fù)用時(shí),需要對(duì)表單進(jìn)行聯(lián)動(dòng)時(shí)使用;避免子父組件的反復(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:{ //組件二點(diǎn)擊發(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 //需要有一個(gè)變量接收 } }, } </script>
通過這兩個(gè)案例發(fā)現(xiàn)vue通過ref操作dom帶來的好處是很明顯的,便捷靈活的實(shí)現(xiàn)方案需求
到此這篇關(guān)于詳細(xì)解讀VUE父子組件的使用的文章就介紹到這了,更多相關(guān)VUE父子組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue項(xiàng)目依賴升級(jí)報(bào)錯(cuò)處理方式
這篇文章主要介紹了vue項(xiàng)目依賴升級(jí)報(bào)錯(cuò)處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08vue中利用three.js實(shí)現(xiàn)全景圖的完整示例
這篇文章主要給大家介紹了關(guān)于vue中利用three.js實(shí)現(xiàn)全景圖的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12Vue??vuex配置項(xiàng)和多組件數(shù)據(jù)共享案例分享
這篇文章主要介紹了Vue??vuex配置項(xiàng)和多組件數(shù)據(jù)共享案例分享,文章圍繞Vue?Vuex的相關(guān)資料展開配置項(xiàng)和多組件數(shù)據(jù)共享的案例分享,需要的小伙伴可以參考一下2022-04-04vue-cli腳手架config目錄下index.js配置文件的方法
下面小編就為大家分享一篇vue-cli腳手架config目錄下index.js配置文件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03vue中promise的使用及異步請(qǐng)求數(shù)據(jù)的方法
這篇文章主要介紹了vue中promise的使用及異步請(qǐng)求數(shù)據(jù)的方法,文章給大家較詳細(xì)的介紹了遇到的問題及解決方法,需要的朋友可以參考下2018-11-11Vue Element前端應(yīng)用開發(fā)之樹列表組件
本篇隨筆主要介紹樹列表組件和下拉列表樹組件在項(xiàng)目中的使用,以及一個(gè)SplitPanel的組件。2021-05-05Vue3+TypeScript封裝axios并進(jìn)行請(qǐng)求調(diào)用的實(shí)現(xiàn)
這篇文章主要介紹了Vue3+TypeScript封裝axios并進(jìn)行請(qǐng)求調(diào)用的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04