Vue2的16種傳參通信方式總結(jié)和示例講解
前言
先直入主題列出有哪些傳參方式,下面再通過事例一一講解。
props
(父傳子)$emit
與v-on
(子傳父)EventBus
(兄弟傳參).sync
與update:
(父子雙向)v-model
(父子雙向)ref
$children
與$parent
$attrs
與$listeners
(爺孫雙向)provide
與inject
(多層傳參)Vuex
(全局)Vue.prototype
(全局)
路由
瀏覽器緩存 (全局)window
(全局)$root
(頂層)slot
(父傳子)
一、props
(父傳子)
思路簡述:父組件直接用冒號
:
綁定變量,然后子組件通過props
接收父組件傳過來的內(nèi)容。
父組件代碼:核心代碼在第3
行,直接用:message="message"
傳參。
<template> <div> <child :message="message" /> </div> </template> <script> import child from './child .vue'; export default { components: { child }, data() { return { message: '這是父組件傳過去的' }; } }; </script>
子組件代碼: 用props
接收消息后可以直接使用,如下第3
行和第16
行中直接使用
注意: props
有兩種接收方法,如下第9
行注釋的就是簡寫用法,此用法不能設(shè)置默認(rèn)值。
<template> <div> <p>接收到的消息: {{ message }}</p> </div> </template> <script> export default { //props:['message'], props: { message: { type: String, default: '', // 這里能設(shè)置默認(rèn)值,如果父組件沒有傳參,默認(rèn)值會生效 }, }, mounted() { console.log(this.message); }, }; </script>
注意: 此傳參方式是單向的,即子組件接收到父組件的數(shù)據(jù)后,是不能直接修改props
接收的數(shù)據(jù),否則會直接報錯。
二、$emit
與v-on
(子傳父)
思路簡述: 子組件通過$emit
觸發(fā)父組件的指定方法并且在此方法中攜帶任意參數(shù),父組件通過在被觸發(fā)的方法中拿到攜帶的參數(shù)完成子傳父。
語法:$emit(方法名,參數(shù))
子組件代碼:核心代碼在第11
行,觸發(fā)方法并且攜帶參數(shù)。
<template> <div> <button @click="sendParent">點(diǎn)擊發(fā)送數(shù)據(jù)給父組件</button> </div> </template> <script> export default { methods: { sendParent() { this.$emit('my-event', '這是傳遞的參數(shù)'); }, }, }; </script>
父組件代碼:核心代碼在第3
行觸發(fā)事件,獲取到子組件的傳參。
<template> <div> <child v-on:my-event="childEvent" /> // 或者用@簡寫代替v-on <child @my-event="childEvent" /> </div> </template> <script> import child from './child.vue'; export default { components: { child, }, methods: { childEvent(item) { console.log('接收到子組件的傳參:', item); }, }, }; </script>
三、EventBus
(兄弟傳參)
思路簡述: 先創(chuàng)建一個全局的事件總線Bus
(可以隨意命名),并掛載在Vue.prototype
上。
然后兄弟組件A
通過$emit
發(fā)送參數(shù),兄弟組件B
通過$on
接收參數(shù)。
- 有兩種使用方法,下面分別講解。
方法一:直接掛載全局事件總線,全局直接使用不需要額外引入。
先在項(xiàng)目的入口文件中(main.js
或main.ts
)創(chuàng)建全局事件Bus
并且掛載在Vue.prototype
*
import Vue from 'vue'; const Bus = new Vue(); Vue.prototype.$Bus = Bus;
兄弟組件A
代碼:通過this.$Bus.$emit(方法名,參數(shù))
發(fā)送參數(shù)。
<template> <div> <button @click="sendSibling">點(diǎn)擊發(fā)送內(nèi)容給兄弟組件</button> </div> </template> <script> export default { methods: { sendSibling() { this.$Bus.$emit('my-event', '參數(shù)'); }, }, }; </script>
兄弟組件B
代碼:通過this.$Bus.$on(對應(yīng)$emit的方法,本地方法)
觸發(fā)本地的方法,從而接收參數(shù)。
<template> <div> 我是兄弟組件B </div> </template> <script> export default { created() { this.$Bus.$on('my-event', this.handleMessage); }, beforeDestroy() { this.$Bus.$off('my-event', this.handleMessage); }, methods: { handleMessage(message) { console.log('來自兄弟的參數(shù):', message); }, }, }; </script>
注意: 如上第10-12
行所示,在組件銷毀前要在 beforeDestroy
生命周期中使用$off
移除移除$on
的事件監(jiān)聽器,防止避免內(nèi)存泄漏影響性能。如下所示
方法二: 不創(chuàng)建全局事件總線,單獨(dú)開一個文件,哪里需要就哪里引用。
創(chuàng)建一個單獨(dú)文件命名為Bus.js
(可以自由命名)
import Vue from "vue" export default new Vue()
兄弟組件A
代碼: 先引入Bus.js
文件,然后通過Bus.$emit(方法名,參數(shù))
發(fā)送參數(shù)。
<template> <div> <button @click="sendSibling">點(diǎn)擊發(fā)送內(nèi)容給兄弟組件</button> </div> </template> <script> import Bus from './Bus.js'; export default { methods: { sendSibling() { Bus.$emit('my-event', '參數(shù)'); }, }, }; </script>
兄弟組件B
代碼:先引入Bus.js
文件,然后通過Bus.$on(對應(yīng)$emit的方法,本地方法)
觸發(fā)本地的方法,從而接收參數(shù)。同樣也需要使用$off
銷毀事件監(jiān)聽。
<template> <div> 我是兄弟組件B </div> </template> <script> import Bus from './Bus.js'; export default { created() { Bus.$on('my-event', this.handleMessage); }, beforeDestroy() { Bus.$off('my-event', this.handleMessage); }, methods: { handleMessage(message) { console.log('來自兄弟的參數(shù):', message); }, }, }; </script>
四、.sync
與update:
(父子雙向)
思路簡述:
.sync
其實(shí)是一個語法糖, 配合子組件用this.$emit('update:綁定的屬性名', 方法)
修改父組件屬性, 能解決props
只能單向傳遞的問題。
父組件代碼:核心代碼在第3行,比普通的父傳子多使用了.sync
修飾符。
<template> <div> <chile :myprop.sync="myData" /> </div> </template> <script> import chile from './chile.vue'; export default { components: { chile }, data() { return { myData: '父組件數(shù)據(jù)' }; } }; </script>
子組件代碼:核心代碼是第14
行,通過this.$emit
同步修改父組件內(nèi)容。
<template> <div> <button @click="updateData">點(diǎn)擊子修改父傳過來的數(shù)據(jù)</button> </div> </template> <script> export default { props: { myprop: String, }, methods: { updateData() { this.$emit('update:myprop', 新內(nèi)容); }, }, }; </script>
注意:使用.sync
修飾符時,this.$emit
里面總是以update:
開頭,后面接要修改的屬性名稱。
五、v-model
(父子雙向)
思路簡述:v-model
最常用于表單,它其實(shí)是一個語法糖,并且和上面.sync
有點(diǎn)類似。v-model
本質(zhì)上是v-bind:value
和@input
組件效果。通過v-bind:value
綁定數(shù)據(jù)父傳子,通過@input
觸發(fā)對應(yīng)事件子傳父從而實(shí)現(xiàn)雙向綁定。
父組件代碼:直接用v-model
綁定要傳給子組件的參數(shù),當(dāng)子組件觸發(fā)input
事件時父組件myData
會同步更新。
<template> <div> <child v-model="myData" /> </div> </template> <script> import child from './child.vue'; export default { components: { child }, data() { return { myData: '天天鴨' }; } }; </script>
子組件代碼:當(dāng)input
輸入框的內(nèi)容發(fā)生變化時,就會觸發(fā)@input
事件,然后this.$emit
同步修改父組件的值
<template> <div> <input :value="childData" @input="handleChange" /> </div> </template> <script> export default { model: { prop: 'myProp', event: 'input' }, props: { myProp: String }, data() { return { childData: this.myProp }; }, methods: { handleChange(event) { this.childData = event.target.value; this.$emit('input', this.childData); } } }; </script>
注意:在子組件當(dāng)中,必須要定義model
來指定props
和事件名稱(名稱默認(rèn)為input
)。
六、ref
思路講解: ref
主要用來訪問子組件的方法和屬性,是直接操縱DOM
的方式。主要用法是在子組件上綁定一個ref
,然后父組件用this.$refs
直接訪問子組件的方法
父組件代碼:子組件上用ref="refChild"
綁定一個ref
,然后用this.$refs.refChild
獲取到子組件實(shí)例,能獲取到子組件屬性和操縱子組件方法。
<template> <div> <child ref="refChild" /> </div> </template> <script> import child from './child.vue'; export default { components: { child, }, mounted() { let childObj = this.$refs.refChild; console.log(childObj.name); // 直接獲取到子組件的屬性內(nèi)容 打印出來:天天鴨 childObj.childMethod('參數(shù)'); // 觸發(fā)子組件的方法 }, }; </script>
子組件代碼:
<template> <div></div> </template> <script> export default { data() { return { name: '天天鴨', }; }, methods: { childMethod(val) { console.log(val); }, }, }; </script>
七、$children
與$parent
簡述: $children
和 $parent
是Vue
用于訪問子組件實(shí)例和父組件實(shí)例的特殊屬性。其中$children
能獲取所有子組件實(shí)例但不能獲取孫子的,而$parent
獲取當(dāng)前組件的父組件實(shí)例。
父組件代碼: 直接使用this.$children
即可獲取。
注意: 獲取到的實(shí)例可能為空,因此需要判空。并且如果有多個子組件時返回的是一個數(shù)組,所以需要通過下標(biāo)確認(rèn)對應(yīng)的子組件數(shù)據(jù)。
<template> <div> <child /> <button @click="getChildMethod">調(diào)用子組件方法</button> </div> </template> <script> import child from './child.vue'; export default { components: { child, }, methods: { getChildMethod() { // 判空,然后用下標(biāo)獲取 if (this.$children.length > 0) { this.$children[0].childMethod(); // 使用子組件方法 this.$children[0].name; // 使用子組件屬性 } }, }, }; </script>
子組件代碼: 類似地,父組件也是同樣用法,但區(qū)別是返回的不是數(shù)組而且一個對象,能直接使用。
<template> <div></div> </template> <script> export default { mounted(){ this.$parent.parMethod() this.$parent.name } }; </script>
八、$attrs
與$listeners
(爺孫雙向)
簡述: $attrs
和 $listeners
相當(dāng)于是使用在父親組件上的一個中轉(zhuǎn)站。 $attrs
用于將props
外的數(shù)據(jù)從爺組件傳遞給孫組件的,而$listeners
用于從孫組件中觸發(fā)爺組件中事件達(dá)到傳參效果。
下面把$attrs
與$listeners
分開講解更易于理解。
$attrs
使用流程代碼:
(1)爺組件代碼: 類似父傳子,正常用冒號:
綁定屬性傳參。
<GrandParent :name=name></GrandParent>
(2)父組件代碼:$attrs
作用在父組件,意思是把props
之外屬性全部傳遞給到孫子。
注意:如果這里父組件用
props
接收了name
屬性,那么用$attrs
無法傳遞到孫子組件,因?yàn)橹荒軅鬟fprops
之外屬性。
<Parent v-bind="$attrs"></Parent>
(3)孫組件代碼:類似父傳子,正常用popos
接收爺組件傳過來的參數(shù)。
<template> <div> 爺組件傳來的:{{ name }} </div> </template> <script> export default { props: { name: { default: String, }, }, }; </script>
$listeners
使用流程代碼:
(1)孫組件代碼 直接this.$emit
類似子傳父
<template> <div> <el-button @click="update">點(diǎn)擊孫傳爺</el-button> </div> </template> <script> export default { methods: { update() { this.$emit('my-event', '孫傳給爺?shù)臄?shù)據(jù)'); }, }, }; </script>
(2)父組件代碼:$listeners
作用在父組件。
<Parent v-bind="$listeners"></Parent>
(3)爺組件代碼: 類似子傳父中的父組件,觸發(fā)對應(yīng)孫子組件this.$emit
中的my-event
事件接收到參數(shù)。
<template> <div> <Parent @my-event="getMyEvent" /> </div> </template> <script> import Parent from './Parent.vue'; export default { components: { Parent, }, methods: { getMyEvent(val) { console.log('爺組件接收到的數(shù)據(jù):', val); }, }, }; </script>
這里感覺算兩種(爺傳孫與孫傳爺)傳參方式了,但由于都是類似中轉(zhuǎn)站效果,所以放一起說比較好理解。
九、provide
與inject
(多層傳參)
簡述: provide
與inject
無論多少層組件都能傳參。頂層組件通過provide
傳參,下面所有組件都能用inject
接收,而且子組件也能通過方法給頂層組件傳參。
頂層組件代碼: 核心代碼在第8
行的provide()
中,可以傳遞常量、變量和方法。
<template> <div> </div> </template> <script> export default { provide() { return { name: '天天鴨', age: this.age, myMethod: this.myMethod, }; }, data() { return { age: '18', }; }, methods: { myMethod(data) { console.log('收到來自某個孫子的數(shù)據(jù):', data); }, }, }; </script>
子孫組件代碼:核心代碼在第10
行接收參數(shù), 除了能接收頂層參數(shù)外,還能通過參考第13
行的用法,通過頂層給到的方法傳參給頂層組件。
<template> <div> <el-button @click="myMethod('我是孫子組件')">我是孫子組件</el-button> 這是頂層傳下來的參數(shù): {{ name }} </div> </template> <script> export default { inject: ['name', 'age', 'myMethod'], methods: { myMethod(data) { this.myMethod(data); // 傳參給頂層祖先組件 }, }, }; </script>
十、Vuex
(全局)
有針對性寫過對應(yīng)的文章,可以直接跳轉(zhuǎn)細(xì)看:對比學(xué)習(xí)vuex和pinia用法
十一、Vue.prototype
(全局)
簡述:能用Vue.prototype
把任何屬性和方法掛載在Vue
實(shí)例了,讓所有Vue
實(shí)例共用。
(1)掛載屬性 直接往Vue.prototype
掛載即可
Vue.prototype.$testName = '天天鴨';
(2)掛載方法直接往Vue.prototype
掛載即可
Vue.prototype.$testMethod = function(val) { console.log(val); };
調(diào)用:直接在任何頁面用this
調(diào)用
this.$appName; this.$testMethod('參數(shù)');
十二、瀏覽器緩存
簡述: localStorage
和sessionStorage
:主要是瀏覽器用來持久化存儲的,這算是用的不多,但也是必用的一種通信方式。兩者區(qū)別如下
sessionStorage
(臨時存儲):最大空間5M
,為每一個數(shù)據(jù)源維持一個存儲區(qū)域,但只在瀏覽器打開期間存在,關(guān)閉后數(shù)據(jù)會不會消失,包括頁面重新加載。localStorage
(長期存儲):最大空間5M
,與 sessionStorage 一樣,但是哪怕瀏覽器關(guān)閉后,數(shù)據(jù)依然會一直存在,除非手動刪除。
具體用法如下所示:
// 存儲 sessionStorage.setItem('key', 'value'); localStorage.setItem('key', 'value'); // 獲取 let valueFromSessionStorage = sessionStorage.getItem('key'); let valueFromLocalStorage = localStorage.getItem('key'); // 刪除 sessionStorage.removeItem('key'); localStorage.removeItem('key'); // 清空所有 sessionStorage.clear(); localStorage.clear();
注意:存儲的數(shù)據(jù)只能是字符串形式,因此如果要存儲對象或者數(shù)組,則需要使用JSON.stringify
來轉(zhuǎn)換后再存儲,讀取后用JSON.parse
還原。
十三、window
(全局)
簡述: 直接用語法 window.age = '18'
定義然后全局
通用即可。(此方式是存放在內(nèi)存刷新會清空)
注意:在 Vue
應(yīng)用中,雖然可以直接將屬性掛載到 window
對象上實(shí)現(xiàn)全局通用,但并推薦,因?yàn)?code>這可能會出現(xiàn)命名沖突、導(dǎo)致代碼難以維護(hù)。
添加屬性和方法:直接定義,可以是屬性也可以是對象
window.Obj = { test: '掛載對象' } window.name = '天天鴨'
使用:
console.log( window.Obj); console.log( window.name);
十四、路由
簡述: Vue
在路由跳轉(zhuǎn)時攜帶參數(shù)其實(shí)也很常用的方式,下面匯總一下三種路由傳參。
(1)通過 params
傳參 跳轉(zhuǎn)頁面用法:
this.$router.push({name:"index", params:{id}})
目標(biāo)頁面接收參數(shù):
this.$route.params.id
(2)通過 query
傳參
跳轉(zhuǎn)頁面用法:有幾種方式
this.$router.push({ name:"index", query:{id}}) this.$router.push({ path:"/index", query:{id}}) this.$router.push('/index?name='+obj.name+'&age='+obj.age)
目標(biāo)頁面接收參數(shù):
this.$route.query.id
(3)通過動態(tài)路由傳參
注意: 如果用動態(tài)路由傳參需要對路由進(jìn)行配置;并且參數(shù)會在 url
中顯示。 如下所示,在path
后面要配置:name/:age
.
{ path: '/about/:name/:age' , name: 'About', component() => import('@/views/About.vue') }
跳轉(zhuǎn)頁面用法:
this.$router.push('/about/'+obj.name+'/'+obj.age)
目標(biāo)頁面接收參數(shù):
this.$route.params
十五、$root
(頂層)
簡述: 可以通過 $root
訪問到整個 Vue
樹的根實(shí)例,也就是可以使用 $root
來訪問全局的屬性或者修改全局的屬性。
示例:在main.js
文件中定義一個globalName
屬性,可以全局使用。
import App from './App.vue'; import Vue from 'vue'; new Vue({ el: '#app', render: h => h(App), data: { globalName: '天天鴨' } });
在下層任意組件使用或者修改內(nèi)容
<template> <div> {{ globalName }} </div> </template> <script> export default { mounted() { this.$root.globalName = '修改數(shù)據(jù)'; }, }; </script>
十六、slot
(父傳子)
簡述: 通過插槽也是可以傳遞參數(shù),這也是很多人忽略的一種方式。父組件可以通過插槽向子組件傳遞參數(shù),然后子組件拿到參數(shù)進(jìn)行渲染。
下面主要講解具名插槽和默認(rèn)插槽兩種使用方式。
(1)具名插槽用法
子組件代碼: 用slot
定義一個名叫header
的插槽。
<template> <div> <slot name="header"></slot> </div> </template> <script> export default { }; </script>
父組件代碼:用v-slot:header
向子組件的header
插槽傳遞內(nèi)容。這邊傳遞什么那邊就會在對應(yīng)區(qū)域顯示什么。
<template> <div> <child> <template v-slot:header> <h1>這是插槽的內(nèi)容</h1> </template> </child> </div> </template> <script> import child from './child.vue'; export default { components: { child } }; </script>
(2)無參數(shù)傳遞的默認(rèn)插槽
子組件代碼: 用slot
定義插槽時不需要指定name
名稱。
<template> <div> <slot></slot> </div> </template> <script> export default { }; </script>
父組件代碼:不需要指定插槽名稱,只要在組件中間填寫內(nèi)容就會渲染在默認(rèn)插槽中。
<template> <div> <child> <p>默認(rèn)插槽中的內(nèi)容。</p> </child> </div> </template> <script> import child from './child.vue'; export default { components: { child } }; </script>
總結(jié)
Vue2中路由傳參數(shù)方式:props(父傳子),$emit與v-on(子傳父),EventBus(兄弟傳參),.sync與update:(父子雙向),v-model(父子雙向),ref $children與$parent,$attrs與$listeners(爺孫雙向),provide與inject(多層傳參),Vuex,Vue.prototype,路由,瀏覽器緩存,window,$root,slot(父傳子)。
到此這篇關(guān)于Vue2的16種傳參通信方式總結(jié)和示例講解的文章就介紹到這了,更多相關(guān)Vue2的16種傳參通信方式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue CLI3搭建的項(xiàng)目中路徑相關(guān)問題的解決
這篇文章主要介紹了Vue CLI3搭建的項(xiàng)目中路徑相關(guān)問題的解決,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09nuxt框架中對vuex進(jìn)行模塊化設(shè)置的實(shí)現(xiàn)方法
這篇文章主要介紹了nuxt框架中對vuex進(jìn)行模塊化設(shè)置的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09關(guān)于Vue-extend和VueComponent問題小結(jié)
這篇文章主要介紹了Vue-extend和VueComponent問題,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08vue 彈窗時 監(jiān)聽手機(jī)返回鍵關(guān)閉彈窗功能(頁面不跳轉(zhuǎn))
這篇文章主要介紹了vue 彈窗時 監(jiān)聽手機(jī)返回鍵關(guān)閉彈窗功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值(頁面不跳轉(zhuǎn)) ,需要的朋友可以參考下2019-05-05