2023 Vue直播班筆記 - 跨層級資料傳遞 provide(含是否有響應式及雷區)

閱讀時間約 14 分鐘
此筆記僅以個人理解方式記錄

前言

VUE為單向資料流的框架,在鄰近層級之間我們可以依靠 props 由父層向子層來傳遞需要的資料,然而遇到跨層級的架構時,雖然也是可以一層層傳進去,只是這會造成多餘的處理及凌亂的程式碼,因此才有了 "provide" 來解決我們跨層級的需求。


層級展示圖

raw-image
raw-image


程式碼區塊(非響應寫法)

先準備範例

<div id="app"> //根元件
<div class="container my-5 py-3">
<div class="btn-group d-block text-center" role="group" aria-label="Basic example">
<button type="button" class="btn btn-primary">Left</button>
<button type="button" class="btn btn-success">Middle</button>
<button type="button" class="btn btn-danger">Right</button>
<button type="button" class="btn btn-dark">{{text}}</button>
</div>
<card></card>
</div>
</div>
<script type="module" src="./index.js"></script>
//index.js
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
import { card } from "./templates.js";

const app = createApp({
data() {
return {
text: '我是最外層的text,我要被傳入最內層'
}
},
components: {
card
}
})
app.mount('#app')
//templates.js
const listGroups = {
template: `
<ul class="list-group ps-0">
<li class="list-group-item" aria-current="true">An active item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
<li class="list-group-item">A fourth item</li>
<li class="list-group-item">And a fifth one</li>
</ul>
`
}

const card = {
template: `
<div class="card my-3">
<div class="row">
<div class="col-md-4">
<img src="https://fluv.com/blog/wp-content/uploads/sites/2/2023/08/%E6%9C%AA%E5%91%BD%E5%90%8D%E8%A8%AD%E8%A8%88-9.png" class="img-fluid rounded-start" alt="貓咪">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
<p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<listGroups></listGroups>
</div>
</div>
</div>
`,
components: {
listGroups
}
}

export { card }


架好後就開始展現跨層級用法

1.在外層加入 provide

raw-image


2.內層元件補上 inject

raw-image


3.這樣就實現了跨層級功能了,如下圖。

raw-image


響應式寫法僅差別在於provide寫法,而這裡面也有個地方要注意

-非響應寫法,很直接能看出要傳入甚麼資訊

//非響應
provide:{
text: '我是最外層的text,我要被傳入最內層'
},

//題外話(雷點分享)
//剛接觸響應時以為只要改成return function就會響應
//這樣其實也只會單純傳入而已哦
provide(){
return {
text: '我是最外層的text,我要被傳入最內層'
}
},


-再來說說響應,對我來說有兩種意思

1.外層provide更動時,連帶內層注入的inject一同更動
2.內層利用"物件傳參考特性",來達到修改內層進而影響外層

我們稍微調整下程式碼方便展示

利用computed

<div id="app">
<div class="container my-5 py-3">
<div class="btn-group d-block text-center" role="group" aria-label="Basic example">
<button type="button" class="btn btn-primary">Left</button>
<button type="button" class="btn btn-success">Middle</button>
<input type="text"class="btn btn-light" v-model="text" placeholder="請輸入文字">
<button type="button" class="btn btn-dark">{{text}}</button>
</div>
<card></card>
</div>
</div>
<script type="module" src="./index.js"></script>
//index.js
import {createApp,computed} from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
import {card} from "./templates.js";
const app = createApp({
data() {
return {
text: "測試響應",
};
},
//響應
provide() {
return {
text: computed(() => this.text),
};
},
components: {
card,
},
});
app.mount("#app");
//templates.js
const listGroups = {
template: `
<ul class="list-group ps-0">
<li class="list-group-item" aria-current="true">An active item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
<li class="list-group-item">A fourth item</li>
<li class="list-group-item">顯示inject => {{text}}</li>
</ul>
`,
inject:['text'],
}

const card = {
template: `
<div class="card my-3">
<div class="row">
<div class="col-md-4">
<img src="https://fluv.com/blog/wp-content/uploads/sites/2/2023/08/%E6%9C%AA%E5%91%BD%E5%90%8D%E8%A8%AD%E8%A8%88-9.png" class="img-fluid rounded-start" alt="貓咪">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
<p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<listGroups></listGroups>
</div>
</div>
</div>
`,
components: {
listGroups
}
}

export { card }


raw-image


利用物件傳參考特性

<div id="app">
<div class="container my-5 py-3">
<div class="btn-group d-block text-center" role="group" aria-label="Basic example">
<button type="button" class="btn btn-primary">Left</button>
<button type="button" class="btn btn-success">Middle</button>
<button type="button" class="btn btn-danger">{{obj}}</button>
<button type="button" class="btn btn-dark">{{text}}</button>
</div>
<card></card>
</div>
</div>
<script type="module" src="./index.js"></script>
//index.js
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
import { card } from './templates.js'
const app = createApp({
data() {
return {
text: '我是最外層的text,我要被傳入最內層',
obj:{
name:'小明',
age:18
}
}
},
//響應
provide() {
return {
text: this.text,
obj:this.obj
}
},
components: {
card
}
})
app.mount('#app')
//templates.js
const listGroups = {
template: `
<ul class="list-group ps-0">
<li class="list-group-item" aria-current="true">An active item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
<li class="list-group-item">A fourth item</li>
<li class="list-group-item">顯示inject => {{text}}</li>
<li class="list-group-item">顯示inject => {{obj}}</li>
</ul>
`,
inject:['text','obj'],
//更改
created(){
this.text = '我是text,我被更改了'
this.obj.age = 20
}
}

const card = {
template: `
<div class="card my-3">
<div class="row">
<div class="col-md-4">
<img src="https://fluv.com/blog/wp-content/uploads/sites/2/2023/08/%E6%9C%AA%E5%91%BD%E5%90%8D%E8%A8%AD%E8%A8%88-9.png" class="img-fluid rounded-start" alt="貓咪">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
<p class="card-text"><small class="text-muted">Last updated 3 mins ago</small></p>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<listGroups></listGroups>
</div>
</div>
</div>
`,
components: {
listGroups
}
}

export { card }


我們可以看到如果是 "利用物件傳參考" 的方式跟 "一般傳值" 的方式的差別,text 雖然也有在子組件做修改的動作,但影響範圍也只侷限在該組件上。

raw-image


最後感謝卡斯伯老師的指點,才能順利釐清。
raw-image


  • joker
  • 2024/03/20
3會員
19內容數
是一隻喜愛前端勇往直前的霹靂酷樂貓
留言0
查看全部
發表第一個留言支持創作者!
你可能也想看
【程式學習日記】六角學院:2023 Vue 作品實戰班從 Vue 班畢業已經 1 個多月,最近也轉職成功,終於有機會把這段歷程記錄下來,當作一個里程碑。此次參加 Vue 班,心境上最大的不同,大概是知道自己即將在完課後,踏上求職道路。所以如果能在課堂期間 2 個月內完成求職作品,我就能提早出發。 ▍學習狀況 雖然先前有稍微玩過 Vue,但也早已
Thumbnail
avatar
Ann Chou
2024-05-11
2023這一年讓我知道了沒有完美的人事物 我也是一個充滿缺失的個體
Thumbnail
avatar
Po
2024-03-11
2023這些那些關於即將成為過去的那一年 在這個名之為我的小宇宙 泛起過一片漣漪 和其他生命的交會與告別 或久別重逢 或不如歸去 留下些什麼 我們就逐漸長成那個模樣 記憶的刻痕是我們選擇的事實 似真還假 孰是孰非 有何干係 物質構築的既成事實 缺席的不在場證明
Thumbnail
avatar
YiYi
2023-12-31
2023年草嶺古道芒草季|交通路徑、美景圖文紀錄幫大家標示容易走錯的幾個路口,希望可以幫助大家的旅途順利~ 嘗試用圖文方式記錄遊記,好像讀起來更生動了。
Thumbnail
avatar
喬安納
2023-12-04
2023-Vue六角直撥班心得為什麼會參加這個課程 2022年是個不一樣的年,因為當初自學由設計轉前端工程師、一路上跌跌撞撞因為想要把基底打穩所以今年下定了決心從2022切版班、Js直播班、一路跟到目前2022秋季Vue直播班。 Vue直播班的心得 前兩週其實都還跟得上,但到了第三週對我而言確實感覺有些難了啊~正在心裡徬徨第三週
Thumbnail
avatar
布萊N
2023-03-19
20232023年
Thumbnail
avatar
竹川獅
2023-01-21
2023新年一年新的開始,最近事情太多,本想說寫點什麼的...但最近真的工作遇到些瓶頸,剛好在年底把這些不順遂的事情一併都處理掉了,稍微有點時間可以好好的敘述一下最近發生的事情。是這樣的,我前份工作傳統產業做得不太開心,本人的職業是平面設計師,據大家的認知傳產從上到下都是親戚接管事業,當然我的工作也不例外,
Thumbnail
avatar
不惑人生
2023-01-01
2023欲說還休,欲說還休,卻道天涼好個秋 想來也到了「欲說還休」的時候了。 是年紀的增長多了顧慮,還是收斂了自己的負面情緒,或者,只是懶了,我在也不像從前能在FB上po出長文。不管當下的情緒多麼澎派,多想要發表言論,回到家了,坐在電腦前面,就沒了發文的欲望了。 其實也有點擔心,難道已經被速食文化變得淺薄了
Thumbnail
avatar
Hedi Yang
2022-12-31
2023新的一年即將開始,人類這種生物很奇妙,喜歡有一種重新啟動的感覺。
Thumbnail
avatar
記憶,那些
2022-12-30
2023 2023 1.我希望我可以自由的工作、開心的工作、利用我的工作能力我自己賺到生活費。 2.我希望我可以有車子、讓我自由的旅行、享受大自然、我並不是想要在家裡放一台車、而是可以讓我隨時隨時都有一台車。 3.我希望我可以去一些國家旅行想去泰國、加拿大,芬蘭、歐洲。 4.我想瘦到我想要的體重。
Thumbnail
avatar
阿硬
2022-07-07