0%

[Vue] Vue 元件 - props 篇

上一篇我們提到,要從根實例傳資料到元件裡,需要使用 props 特性來傳遞,今天這篇筆記會談談 props 如何實際使用。

在 HTML 放入元件

1
2
3
4
5
6
<div id="app">
<h2>靜態傳遞</h2>
<photo></photo>
<h2>動態傳遞</h2>
<photo></photo>
</div>

定義元件模板

1
2
3
4
5
6
<script type="text/x-template" id="photo">
<div>
<img :scr="imgUrl" class="img-fluid" alt="" />
<p>風景照</p>
</div>
</script>

宣告 Vue 根實例

1
2
3
4
5
6
var app = new Vue({
el: '#app',
data: {
url: '一個圖片網址'
}
});

在 Vue 根實例上方宣告一個元件

1
2
3
4
5
6
7
8
9
10
11
Vue.component('自定義元件名稱',{
template: '# template 的 id 名稱',
props: ['取得 data 資料的屬性名']
// 之後要用這裡的資料屬性名稱在 HTML 上設定 v-bind,就能得到上層的資料
})

// 範例
Vue.component('photo',{
props: ['imgUrl'],
template: '#photo'
})

接下來傳遞資料的方式可以選擇靜態傳遞或動態傳遞。

靜態與動態傳入數值差異

加在 HTML 標籤上的屬性可以分為靜態跟動態兩種,沒有設定 v-bind 的屬性為靜態,有設定 v-bind 的屬性為動態。

靜態屬性的值一律會轉為字串型別,動態屬性的值則不一定是字串。

靜態傳遞

<photo img-url="圖片的網址"></photo>
原本在元件內的 props 值為 imgUrl,放到 HTML 中時要把駝峰改成 -
img-url的值(圖片網址)會透過 x-template:src="imgUrl" 而跑到元件 props 裡。

動態傳遞

<photo :img-url="url"></photo>
這裡的 url 作為與元件 props imgUrl 綁定的值,同時代表的是根實例 data 物件中的 url 特性,因此會把 url 中的圖片網址帶進 props 裡面。

props 圖解

這張圖屬於建良

props 使用注意事項

1. 單向數據流

像上面這樣使用 v-bind 綁定 props,並傳入 Vue 實例的 data 資料,如果又在 DOM 運用 props 屬性建立 v-model 會形成一個問題,就是當使用者從畫面上修改資料時,會去動到根實例的 data ,但這樣是不合規範的,所以會跳錯。

解決辦法是在元件中新增 data 特性,對應一個 function,並在裡面 return 新的特性,當作與畫面雙向綁定的標的,這樣就不會跳錯了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// JS
Vue.component('photo', {
props: ['imgUrl'],
template: '#photo',
data: function () {
return {
newUrl: this.imgUrl
}
}
})

// HTML
<script type="text/x-template" id="photo">
<div>
<img :src="imgUrl" class="img-fluid" alt="" />
<input type="text" class="form-control" v-model="newUrl">
</div>
</script>

newUrl 的值有兩個角色,第一個是接收 props 傳入的資料,第二個是放在元件模板中設定 v-model,使用 newUrl 來與畫面做雙向綁定,就能把 props 資料與 Vue 實例的 data 做隔離。

2. 尚未宣告的變數

當我們在根實例 data 物件新增空的物件,並希望透過 AJAX 推資料進去這個空物件時,元件渲染會發生在 AJAX 資料推進來之前,就會造成抓不到資料而跳錯。

解決方法是使用 v-if="AJAX 傳入的資料特性",確保 AJAX 取得資料後,才渲染元件;在資料尚未取得前,元件都不會顯示。

範例:
<card :user-data="user" v-if="user.phone"></card>

v-if 裡對應的值可以是 AJAX 資料中隨便一個資料特性,這邊的 user 指的是一開始就宣告的空物件名稱。

3. 物件透過參考的方式傳遞資料

在 JavaScript 中,當我們宣告一個變數並賦予它一個新的物件時,記憶體的某處也會建立起一個物件,然後把剛剛的變數指向新生成的物件。

接著,如果我們又宣告第二個變數,並將這個變數指向第一個變數的話,當我們更新第一個變數裡的特性值,第二個變數的內容也會隨之更新。

也就是說,兩個變數都是指向同一個實體。

所以,當我們在畫面上修改資料,會更改到 props 的值,甚至連 Vue 實例的 data 物件也會跟著被改變。

那為何單向數據流無法像這樣傳遞呢?因為單向數據流傳遞的是一般字串,所以無法像物件這樣傳遞參考的特性。如果沒有修改物件的特性,都還是維持單向數據流的概念。

4. 維持狀態與生命週期

如果不希望元件每次都重新生成,或是元件內的內容是由 AJAX 而來,而你不希望每次重整,元件都接收到不一樣的內容的話,就可以使用 <keep-alive> 標籤包住元件,這樣就能維持元件的狀態了。

props 值的型別

預先定義 props 應該傳入哪種型別的資料,避免傳入錯誤的資料。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 原本是這樣寫
Vue.component('prop-type', {
props: ['cash'],
template: '#propType',
data: function() {
return {
newCash: this.cash
}
}
});

// 預先定義 props 值型別
Vue.component('prop-type', {
props: {
cash: {
type: Number,
}
},
template: '#propType',
data: function() {
return {
newCash: this.cash
}
}
});

有時候 props 不會接收到來自外部的值,但如果我們希望它帶有預設值,可以這樣做:

1
2
3
4
5
6
props: {
cash: {
type: Number,
default: 預設值
}
}