組件之間的傳值必須透過聲明 props 的方式,這樣可以避免與HTML
的屬性(attribute)
混淆。父組件傳遞參數給子組件的方式有以下兩種方式:
陣列
的方式來定義props
,這樣只需列出父組件傳遞的 props
名稱。子組件可以直接通過this.xxx
的方式來獲取傳遞進來的props
參數。物件
的方式來定義props
,在物件中指定props
的名稱,並對其型別
、預設值
、驗證器
和是否必填
等進行限制。這樣可以更嚴格地控制傳入的數據,確保組件的行為符合預期。👉 Vue3 Options API props 基本用法實作連結
以下透過一個範例來說明props
的動態綁定基本用法,使用:
來進行綁定:
父組件 Vue Template:
<div id="app">
<child-component-a :special-msg="specialMsg"></child-component-a>
<child-component-b :special-msg="specialMsg"></child-component-b>
</div>
父組件 javascript:
// 根組件
const rootComponent = {
data() {
return {
specialMsg: "hello vue!"
};
},
components: { childComponentA, childComponentB }
};
⭐ :special-msg="specialMsg"
中,special-msg
是子組件中定義的props
名稱,優先使用HTML
可解析的 kebab-case(串燒)
命名方式,以確保與HTML
標準保持一致,並避免可能的瀏覽器解析問題,而 specialMsg
是父組件中的變數名稱。
子組件 Vue Template:
<!-- childComponentA 畫面 -->
<template id="childComponentA">
<p>childComponentA title:{{ specialMsg }}</p>
</template>
<!-- childComponentB 畫面 -->
<template id="childComponentB">
<p>childComponentB title:{{ specialMsg }}</p>
</template>
子組件 javascript:
const childComponentA = {
// 陣列定義 props,無型別的定義
props: ["specialMsg"],
template: "#childComponentA"
};
const childComponentB = {
// 物件定義,搭配型別限制
props: {
specialMsg: String
},
template: "#childComponentB"
};
父組件可以透過props
將資料傳遞給子組件,然而,子組件無法直接修改由父組件傳遞進來的props
。如果子組件需要更改props
的值,應該透過 emits
事件的方式通知父組件,由父組件來進行變更,而非直接在子組件中修改props
。這種單向資料流的設計可以更清楚資料的流向,同時也有助於後續的維護與測試。
如果意圖修改props
會跑出錯誤,告訴你props
是唯讀的:
如果想要使用props
參數在子組件做應用,可以使用下面兩種方式:
data 函數
會在props
初始化之後被呼叫一次,因此可以在data
中基於 props
進行初始值
的設定。但是其值不會因為後續props
改動而連動影響。computed
屬性會在props
變更時重新計算,因此可以在 computed
中進行props
的格式化處理或其他計算。👉 Vue3 Options API props 子組件應用實作連結
子組件 Vue Template:
<template id="child">
<!-- 使用 data 初始化 props 值(初始化執行後不會變更) -->
<p>newCount:{{ newCount }}</p>
<!-- 使用 computed 格式化 props 值(監聽 props 變化執行函數) -->
<p>doubleCount:{{ doubleCount }}</p>
</template>
子組件 javascript:
const childComponent = {
props: ["count"],
template: "#child",
data(){
return{
newCount: this.count + 1
}
},
computed: {
doubleCount() {
return this.count + this.count;
}
}
};
父組件 Vue Template:
<div id="app">
<child-component :count="count"></child-component>
<button @click="add" type="button"> +1</button>
</div>
父組件 javasciprt:
const rootComponent = {
data() {
return {
count: 10
};
},
methods: {
add() {
this.count += 1;
}
},
components: { childComponent }
};
當父組件向子組件傳遞值時,如果使用靜態傳值(例如:<test-component isShow="true"></test-component>
),isShow
參數傳入的值會被視為純字串,因為其未使用v-bind
的方式動態綁定。
若需要傳入不同類型的參數值,比如 Number、Boolean、Array、Object 等。應該使用動態傳值
的方式,即使用v-bind
或縮寫:
來動態綁定表達式。這樣可以確保傳入的值保持其原有的數據類型,而不會被轉換為字串。
👉 Vue3 Options API 動態傳值與靜態傳值實作連結
如果需要將一個物件中的多個屬性傳遞給子組件進行後續的畫面顯示或邏輯處理時,可以使用v-bind
將整個物件直接綁定到子組件。這樣做等於將物件內的所有屬性動態綁定到子組件的對應props
上。
流程說明:
userInfo
物件內有多個屬性(name、age)userInfo
全部參數值傳遞給子組件使用父組件 javascript:
const rootComponent = {
data() {
return {
userInfo: {
name: "Antonio",
age: 25,
}
};
},
components: { childComponent }
};
父組件 Vue Template:
<div id="app">
<!-- 以下兩種達到的效果相同 -->
<child-component v-bind="userInfo"></child-component>
<child-component :name="userInfo.name" :age="userInfo.age"></child-component>
</div>
子組件 Vue Template:
<template id="child">
<div class="card">
<p>姓名:{{ name }}</p>
<p>標題:{{ age }}</p>
</div>
</template>
這邊特別舉一個產品列表陣列包產品資訊物件的案例,讓大家理解當props
傳遞物件時,需要注意傳值的陷阱:
👉 Vue3 Options API v-for 搭配 props 傳值陷阱實作連結
流程說明:
v-for
綁定動態props
給子組件props
的值當作子組件v-model
綁定的初始值(改動子組件的值不應該影響props
)父組件 Vue Template:
<div id="app">
<div class="parent-content">
<h2>我是 parent-content</h2>
<li v-for="product in productList" :key="product.id">
名稱:<input type="text" v-model="product.name">
價格:<input type="text" v-model="product.price">
</li>
</div>
<div class="child-content">
<h2>我是 child-content</h2>
<child-component v-for="product in productList" :key="product.id" :product-info="product"></child-component>
</div>
</div>
⭐ javaScript
物件具有引用相同記憶體地址的特性,因此當傳遞給子組件的props
不是基礎型別(例如::product-name="product.name"
),而是引用型別(如物件或陣列)時,子組件對props
的改動會直接影響父組件中的數據。這是因為父子組件之間實際上共享的是對同一物件的引用,而不是物件本身的拷貝。
改正方式可以參考上面多參數傳遞的方式
,綁定單一屬性或是透過v-bind
一次綁定物件內所有屬性。
👉 Vue3 Options API v-for 搭配 props 傳值手動綁定物件內所有屬性實作連結
👉 Vue3 Options API v-for 搭配 props 傳值透過 v-bind 綁定物件所有屬性實作連結
在 Vue 組件中,props
是從父組件傳遞過來的參數,而非子組件本身定義的變數。為了確保後續數據的維護方便,建議對props
進行限制和驗證。在開發環境
中,如果傳入的props
未通過驗證,Vue 會發出警告並說明原因。
限制方式大致可以分成型別限制
、必填限制
或預設值
及驗證函數
三種方式,可互相搭配使用:
javascript
的內建構造函數
來限制 props 的類型,例如:String、Number、Boolean、Array、Object、Date、Function、Symbol 及 Error 等九種類型。如果傳入的型別是undefined
或是null
會直接通過型別的檢查。props
必須傳入。props
時,props
將使用預設值
。判定是否使用預設值的條件在於 props 的值是否為undefined
,不論是顯式未傳遞還是隱式未定義,都會觸發default
。props
是否符合特定規則。函數應返回 true
表示驗證通過,否則返回false
。以下面的案例示範校驗的方式,設定了四個不同型別跟行為限制組合,:
👉 Vue3 Options API props 規則限制實作連結
流程說明:
count
、title
、userInfo
和status
四個變數,這些變數將作為子組件的props
傳遞,並根據不同的組合進行測試。props
接收從根組件傳遞的值,並設定每個props
的型別
、預設值
及驗證規則
。title
及count
userInfo
及count
status(status 會給非合法值
及count
status(status 給合法值)
及count
子組件 javascript:
const childComponent = {
props: {
// 檢查型別是否為 Number 或 String
inputVal: [Number, String],
// 檢查型別是 Number 且為必填
count: {
type: Number,
required: true
},
// 檢查型別是 String,非必填,設定 undefined 情況下的預設值
title: {
type: String,
default: "子組件預設標題"
},
// 檢查型別是 Object,非必填,設定預設物件格式
// params:代表 props 物件,可以讀取其他 props 值(這邊讀取上面定義的 title)
userInfo: {
type: Object,
// params:傳入的 props 物件值
default(params) {
return { name: "預設人員名稱", age: "xxxx", title: params.title };
}
},
// 檢查型別是 String,非必填,設定預設值 big
// 設定驗證器:回傳規則是 true 通過驗證, false 則是未通過
// value:代表傳入的參數值
status: {
type: String,
default: "big",
validator(value) {
return ["big", "medium", "small"].includes(params);
}
}
},
template: "#child"
};
⭐ userInfo
物件必須透過工廠函數
來定義預設值
,不能直接定義。因為如果直接使用物件來設定預設值
,會導致所有使用該預設值的組件共享相同的物件引用,從而造成不同組件之間的資料相互影響。使用工廠函數
可以確保每個組件實例擁有自己獨立的物件。
子組件 Vue Template
<template id="child">
<div class="card">
<h2>{{ title }}</h2>
<p>Count:{{ count }}</p>
<p>{{ userInfo }}</p>
<p>狀態:{{ status }}</p>
</div>
</template>
父組件 Vue Template:
<div id="app">
<div class="card-group">
<child-component title="父組件傳入的標題" :count="count"></child-component>
<child-component :user-Info="userInfo" :count="count"></child-component>
<child-component status="fail" :count="count"></child-component>
<child-component :status="status" :count="count"></child-component>
</div>
</div>
父組件 javascript:
const rootComponent = {
data() {
return {
count: 0,
userInfo: { name: "Antonio", age: 16 },
status: "small"
};
},
components: { childComponent }
};
⭐ title
如果有傳入值,則會影響userInfo
中的title
屬性;如果title
沒有傳入,則使用title
的預設值。
⭐ 即使傳入非合法值,Vue 仍然會接收並使用該值,但在開發環境中會顯示警告訊息。可以幫助開發者在開發過程中更容易發現和維護傳入值的合法性,從而避免潛在的錯誤。
為了貼近原生button
屬性的行為,Vue 中的Boolean
型別props
會遵循以下規則:
props
定義為Boolean
型別時,只要在組件標籤上聲明了該prop
,即使沒有指定具體的值,它的值也會自動設置為true
。如果未在標籤上聲明,則默認為false
。props
同時支援Boolean
和其他型別(如 Number)
,Boolean
規則優先適用。也就是說,如果該 props
被聲明但沒有具體的值,則會設置為true
。props
同時支持Boolean
和String
型別時,若String
型別在Boolean
型別前面,且props
未給值的時候,Vue 會將其值解析為空字串 ""
,而非true
。👉 Vue3 Options API props Boolean 判定規則實作連結
props
可以有兩種定義方式。一種是無限制
的參數傳遞,通過陣列
來標註允許的props
。另一種是使用物件
來定義,並透過設定型別
和其他屬性來進行傳入參數的驗證與控制。props
是父組件傳遞給子組件的單向數據流,子組件不應直接修改props
的值。特別是當傳遞的是物件或陣列時,直接修改它們會導致父子組件之間的數據共享,從而引發維護上的困難props
值符合要求。如果props
值不合法,Vue 會在開發環境中觸發警告,幫助開發者及時發現問題。props
中的Boolean
屬性遵循類似原生button
屬性的行為。當 Boolean
型別的props
被聲明時,會自動被設置為true
;若未聲明,則為false
。即使props
定義中包含多種型別,只要有Boolean
,其規則依然適用。但在特殊情況下,當String
和Boolean
同時定義時,若傳入的值符合String
的條件,則該props
會被解析為空字串
,而不是true
。