uniapp和vue組件之間的傳值(父子傳值,兄弟傳值,跨級(jí)傳值,vuex)
前言
在做vue項(xiàng)目或者uniapp開(kāi)發(fā)微信小程序時(shí),經(jīng)常會(huì)用到組件之間傳值,因此想總結(jié)記錄下。
一、父子傳值
- 父向子傳遞:
props - 子向父?jìng)鬟f:通過(guò) events(
$emit) - 父組件想調(diào)用子組件的方法:通過(guò)
this.$refs(ref)
a)ref 用在組件可以調(diào)用組件的屬性方法
b)ref 用在標(biāo)簽可以對(duì)標(biāo)簽進(jìn)行操作
c) ref屬性不能用在uniapp的內(nèi)置組件上面,只能用在自定義組件上面;用在內(nèi)置組件比如<view>標(biāo)簽,this.$refs.xxx獲取dom是undefind
父組件調(diào)用子組件的方法
// 父組件
<template>
<view>
<view class="index-goods-list-con">
<WaterfallList
ref="waterFallCon"
:status="waterfall.status"
:list="waterfall.list"
:reset="waterfall.reset"
@clickCard="onClickCard"
@handleGood="handleGood"
@done="onDone"
></WaterfallList>
</view>
</view>
</template>
<script>
import WaterfallList from '@/components/waterfall/waterfall-list.vue'
export default {
data() {
return {}
},
methods: {
handleDailyBestGood(e, good) {
// 用$refs賦值調(diào)用子組件的handleDailyBestNum方法
this.$refs.waterFallCon.handleDailyBestNum(good)
},
},
}
</script>
<style></style>// 子組件
<template></template>
<script>
export default {
data() {
return {
renderBasic: ''
}
},
methods: {
//父組件調(diào)用的方法
handleDailyBestNum(good) {
//good 是父組件彈窗傳遞過(guò)來(lái)的值,我們可以打印看看
console.log(good)
this.renderBasic = good
},
},
}
</script>二、兄弟傳值
借助中間代理, $emit 和 $on
比如在uniapp項(xiàng)目中使用兄弟傳值,vue同理 uniapp頁(yè)面通訊官方文檔
a) 說(shuō)明


b) 使用場(chǎng)景
在商品下單頁(yè)點(diǎn)擊選擇優(yōu)惠券,進(jìn)入優(yōu)惠券頁(yè)面,選擇一張適合的,再返回下單頁(yè),需要帶著優(yōu)惠券id返回,現(xiàn)在商品 提交訂單頁(yè)和優(yōu)惠券頁(yè)面是 跨頁(yè)面 的。
c) 使用方法
//優(yōu)惠券頁(yè)面
clickCoupon (item) {
if (this.orderSource) {
// 觸發(fā)全局自定義事件,傳參id
uni.$emit('updateData', item.id)
uni.navigateBack({
delta: 1
})
}
}, // 從優(yōu)惠券跳回下單頁(yè)
// 監(jiān)聽(tīng)全局自定義事件updateData,接收參數(shù)id
uni.$on('updateData', async function (couponId) {
that.couponId = couponId
})d) 注意事項(xiàng)
- uni.$emit、 uni.$on 、 uni.$once 、uni.$off 觸發(fā)的事件都是 App 全局級(jí)別的,跨任意組件,頁(yè)面,nvue,vue 等
- 使用時(shí),注意及時(shí)銷毀事件監(jiān)聽(tīng),比如,頁(yè)面 onLoad 里邊 uni.$on 注冊(cè)監(jiān)聽(tīng),onUnload 里邊uni.$off 移除,或者一次性的事件,直接使用 uni.$once 監(jiān)聽(tīng)。
- 注意 uni.$on 定義完成后才能接收到 uni.$emit 傳遞的數(shù)據(jù)
三、祖孫或者更深嵌套的組件間傳值: provide/inject
a) 類型
provide:Object | () => Object
inject:Array<string> | { [key: string]: string | Symbol | Object }b) 詳細(xì)
這對(duì)選項(xiàng)需要一起使用,以允許一個(gè)祖先組件向其所有子孫后代注入一個(gè)依賴,不論組件層次有多深,并在其上下游關(guān)系成立的時(shí)間里始終生效。
provide 選項(xiàng)應(yīng)該是一個(gè)對(duì)象或返回一個(gè)對(duì)象的函數(shù)。該對(duì)象包含可注入其子孫的 property。
inject 選項(xiàng)應(yīng)該是: 一個(gè)字符串?dāng)?shù)組,或一個(gè)對(duì)象
提示:provide 和 inject 綁定并不是可響應(yīng)的。這是刻意為之的。然而,如果你傳入了一個(gè)可監(jiān)聽(tīng)的對(duì)象,那么其對(duì)象的 property 還是可響應(yīng)的。
c) 使用場(chǎng)景
如果要將祖先組件直接傳遞給孫子組件,我們要將props逐級(jí)傳遞下去:祖先組件 =》子組件 =》孫子組件,而通過(guò)provide/inject,可直接從祖先組件傳給孫子組件,即使再嵌套多層也沒(méi)關(guān)系。
d) 使用方法
<template>
<div>
<button @click="changeMsg">祖組件觸發(fā)</button>
<h1>祖組件</h1>
<parent></parent>
</div>
</template>
<script>
import parent from './parent.vue';
export default {
data(){
return{
obj:{
name:'JavaScript',
},
developer:'布蘭登·艾奇',
year:1995,
update:'2021年06月',
}
},
provide(){
return {
obj: this.obj, // 方式1.傳入一個(gè)可監(jiān)聽(tīng)的對(duì)象
developerFn:() => this.developer, // 方式2.通過(guò) computed 來(lái)計(jì)算注入的值
// developerFn: this.getDeveloper, 方式3.或者調(diào)用一個(gè)方法,也能實(shí)現(xiàn)響應(yīng)式
year: this.year, // 方式4.直接傳值
app: this, // 方式5. 提供祖先組件的實(shí)例 缺點(diǎn):實(shí)例上掛載很多沒(méi)有必要的東西 比如:props,methods。
}
},
components: {
parent,
},
methods:{
getShowCartValue() {
return this.developer
},
changeMsg(){
this.obj.name = 'Vue';
this.developer = '尤雨溪';
this.year = 2014;
this.update = '2021年6月7日';
},
},
}
</script>子組件
<template>
<div class="wrap">
<h4>子組件(只做中轉(zhuǎn))</h4>
<child></child>
</div>
</template>
<script>
import child from './child.vue';
export default {
components:{
child,
},
}
</script>孫組件
<template>
<div>
<h5>孫組件</h5>
<span>名稱:{{obj.name}}</span> |
<span>作者:{{developer}}</span> |
<span>誕生于:{{year}}</span> |
<span>最后更新于:{{this.app.update}}</span>
</div>
</template>
<script>
export default {
computed:{
developer(){
return this.developerFn()
}
},
inject:['obj','developerFn','year','app'],
}
</script>未點(diǎn)擊按鈕,原有狀態(tài)

當(dāng)點(diǎn)擊按鈕觸發(fā) changeMsg 方法后,效果如下:

對(duì)比一下前后差異:無(wú)論點(diǎn)擊多少次,孫組件中的誕生于 year 字段永遠(yuǎn)都是1995 并不會(huì)發(fā)生變化,通過(guò) 方式1、方式2、方式3、方式5傳值是可以響應(yīng)的。
正是官網(wǎng)所提到的:provide 和 inject 綁定并不是可響應(yīng)的。這是刻意為之的。然而,如果你傳入了一個(gè)可監(jiān)聽(tīng)的對(duì)象,那么其對(duì)象的 property 還是可響應(yīng)的。
注意:
1)另外如果孫子組件更改祖先組件傳來(lái)的值,會(huì)發(fā)現(xiàn)祖先組件的值也會(huì)跟著變,所以慎用 provide / inject;
2)Vuex 和 provide/inject 最大的區(qū)別:Vuex 中的全局狀態(tài)的每次修改是可以追蹤回溯的,而 provide/inject 中變量的修改是無(wú)法控制的。換句話說(shuō),不知道是哪個(gè)組件修改了這個(gè)全局狀態(tài)。
所以對(duì)于業(yè)務(wù)龐大而復(fù)雜的,還是建議使用vuex~
四、更復(fù)雜的結(jié)構(gòu):vuex
請(qǐng)移步看我之前寫(xiě)的關(guān)于vuex使用總結(jié)文章,學(xué)習(xí)筆記之Vuex總結(jié)(Vue狀態(tài)管理)
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Electron+vite+vuetify項(xiàng)目搭建的流程和方法
最近想用Electron來(lái)進(jìn)行跨平臺(tái)的桌面應(yīng)用開(kāi)發(fā),同時(shí)想用vuetify作為組件,于是想搭建一個(gè)這樣的開(kāi)發(fā)環(huán)境,這里分享下Electron+vite+vuetify項(xiàng)目搭建的流程和方法,感興趣的朋友一起看看吧2024-06-06
vue-cli創(chuàng)建項(xiàng)目ERROR?in?Conflict:?Multiple?assets?emit?dif
最近vue/cli創(chuàng)建項(xiàng)目后出現(xiàn)了錯(cuò)誤,下面這篇文章主要給大家介紹了關(guān)于vue-cli創(chuàng)建項(xiàng)目ERROR?in?Conflict:?Multiple?assets?emit?different?content?to?the?same?filename?index.html問(wèn)題的解決辦法,需要的朋友可以參考下2023-02-02
如何在Vue中實(shí)現(xiàn)登錄驗(yàn)證功能(代碼示例)
Vue是一種流行的JavaScript框架,可以幫助開(kāi)發(fā)者建立高效的Web應(yīng)用程序,本文將為您介紹如何在Vue中實(shí)現(xiàn)登錄驗(yàn)證功能,并為您提供具體的代碼示例,感興趣的朋友一起看看吧2023-11-11
如何將HTML頁(yè)面改寫(xiě)到vue項(xiàng)目中詳解
html和vue都是前端技術(shù)中非常重要的一部分,其中html是web開(kāi)發(fā)的基石,而vue則是現(xiàn)代化的前端開(kāi)發(fā)框架之一,下面這篇文章主要給大家介紹了關(guān)于如何將HTML頁(yè)面改寫(xiě)到vue項(xiàng)目中的相關(guān)資料,需要的朋友可以參考下2024-08-08
vue+django實(shí)現(xiàn)下載文件的示例
這篇文章主要介紹了vue+django實(shí)現(xiàn)下載文件的示例,幫助大家更好的理解和學(xué)習(xí)使用vue框架,感興趣的朋友可以了解下2021-03-03

