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(父傳子)
思路簡述:父組件直接用冒號(hào)
:綁定變量,然后子組件通過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)值會(huì)生效
},
},
mounted() {
console.log(this.message);
},
};
</script>注意: 此傳參方式是單向的,即子組件接收到父組件的數(shù)據(jù)后,是不能直接修改props接收的數(shù)據(jù),否則會(huì)直接報(bào)錯(cuò)。
二、$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)建一個(gè)全局的事件總線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(對(duì)應(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ú)開一個(gè)文件,哪里需要就哪里引用。
創(chuàng)建一個(gè)單獨(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(對(duì)應(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í)是一個(gè)語法糖, 配合子組件用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修飾符時(shí),this.$emit里面總是以update:開頭,后面接要修改的屬性名稱。
五、v-model (父子雙向)
思路簡述:v-model最常用于表單,它其實(shí)是一個(gè)語法糖,并且和上面.sync有點(diǎn)類似。v-model本質(zhì)上是v-bind:value和@input組件效果。通過v-bind:value綁定數(shù)據(jù)父傳子,通過@input觸發(fā)對(duì)應(yīng)事件子傳父從而實(shí)現(xiàn)雙向綁定。
父組件代碼:直接用v-model綁定要傳給子組件的參數(shù),當(dāng)子組件觸發(fā)input事件時(shí)父組件myData會(huì)同步更新。
<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ā)生變化時(shí),就會(huì)觸發(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的方式。主要用法是在子組件上綁定一個(gè)ref,然后父組件用this.$refs直接訪問子組件的方法
父組件代碼:子組件上用ref="refChild"綁定一個(gè)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í)例可能為空,因此需要判空。并且如果有多個(gè)子組件時(shí)返回的是一個(gè)數(shù)組,所以需要通過下標(biāo)確認(rèn)對(duì)應(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ù)組而且一個(gè)對(duì)象,能直接使用。
<template>
<div></div>
</template>
<script>
export default {
mounted(){
this.$parent.parMethod()
this.$parent.name
}
};
</script>八、$attrs與$listeners (爺孫雙向)
簡述: $attrs和 $listeners相當(dāng)于是使用在父親組件上的一個(gè)中轉(zhuǎn)站。 $attrs用于將props外的數(shù)據(jù)從爺組件傳遞給孫組件的,而$listeners用于從孫組件中觸發(fā)爺組件中事件達(dá)到傳參效果。
下面把$attrs與$listeners分開講解更易于理解。
$attrs使用流程代碼:
(1)爺組件代碼: 類似父傳子,正常用冒號(hào):綁定屬性傳參。
<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ā)對(duì)應(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('收到來自某個(gè)孫子的數(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 (全局)
有針對(duì)性寫過對(duì)應(yīng)的文章,可以直接跳轉(zhuǎn)細(xì)看:對(duì)比學(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:主要是瀏覽器用來持久化存儲(chǔ)的,這算是用的不多,但也是必用的一種通信方式。兩者區(qū)別如下
sessionStorage(臨時(shí)存儲(chǔ)):最大空間5M,為每一個(gè)數(shù)據(jù)源維持一個(gè)存儲(chǔ)區(qū)域,但只在瀏覽器打開期間存在,關(guān)閉后數(shù)據(jù)會(huì)不會(huì)消失,包括頁面重新加載。localStorage(長期存儲(chǔ)):最大空間5M,與 sessionStorage 一樣,但是哪怕瀏覽器關(guān)閉后,數(shù)據(jù)依然會(huì)一直存在,除非手動(dòng)刪除。
具體用法如下所示:
// 存儲(chǔ)
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();注意:存儲(chǔ)的數(shù)據(jù)只能是字符串形式,因此如果要存儲(chǔ)對(duì)象或者數(shù)組,則需要使用JSON.stringify來轉(zhuǎn)換后再存儲(chǔ),讀取后用JSON.parse還原。
十三、window (全局)
簡述: 直接用語法 window.age = '18' 定義然后全局通用即可。(此方式是存放在內(nèi)存刷新會(huì)清空)
注意:在 Vue 應(yīng)用中,雖然可以直接將屬性掛載到 window 對(duì)象上實(shí)現(xiàn)全局通用,但并推薦,因?yàn)?code>這可能會(huì)出現(xiàn)命名沖突、導(dǎo)致代碼難以維護(hù)。
添加屬性和方法:直接定義,可以是屬性也可以是對(duì)象
window.Obj = { test: '掛載對(duì)象' }
window.name = '天天鴨'使用:
console.log( window.Obj); console.log( window.name);
十四、路由
簡述: Vue在路由跳轉(zhuǎn)時(shí)攜帶參數(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)通過動(dòng)態(tài)路由傳參
注意: 如果用動(dòng)態(tài)路由傳參需要對(duì)路由進(jìn)行配置;并且參數(shù)會(huì)在 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 訪問到整個(gè) Vue 樹的根實(shí)例,也就是可以使用 $root 來訪問全局的屬性或者修改全局的屬性。
示例:在main.js文件中定義一個(gè)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定義一個(gè)名叫header的插槽。
<template>
<div>
<slot name="header"></slot>
</div>
</template>
<script>
export default {
};
</script>父組件代碼:用v-slot:header向子組件的header插槽傳遞內(nèi)容。這邊傳遞什么那邊就會(huì)在對(duì)應(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定義插槽時(shí)不需要指定name名稱。
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
};
</script>父組件代碼:不需要指定插槽名稱,只要在組件中間填寫內(nèi)容就會(huì)渲染在默認(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)問題的解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09
nuxt框架中對(duì)vuex進(jìn)行模塊化設(shè)置的實(shí)現(xiàn)方法
這篇文章主要介紹了nuxt框架中對(duì)vuex進(jìn)行模塊化設(shè)置的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Vue中對(duì)數(shù)組和對(duì)象進(jìn)行遍歷和修改方式
這篇文章主要介紹了Vue中對(duì)數(shù)組和對(duì)象進(jìn)行遍歷和修改方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
關(guān)于Vue-extend和VueComponent問題小結(jié)
這篇文章主要介紹了Vue-extend和VueComponent問題,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08
vue 彈窗時(shí) 監(jiān)聽手機(jī)返回鍵關(guān)閉彈窗功能(頁面不跳轉(zhuǎn))
這篇文章主要介紹了vue 彈窗時(shí) 監(jiān)聽手機(jī)返回鍵關(guān)閉彈窗功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值(頁面不跳轉(zhuǎn)) ,需要的朋友可以參考下2019-05-05

