上層傳來的 props
vue 組件,會使用 props
來接受上層傳來的資料。props
是一個陣列,裡面包含多個字串。
1 2 3 4 5 6 7 8 9 10
| Vue.component('my-component', { props: ['message', 'name'], template: ` <h1>{{message}} {{name}}</h1> `, });
new Vue({ el: '#app', });
|
1 2 3
| <div id='app'> <my-component message='hello' name='Leah'></my-component> </div>
|
props 命名
假設在 component 中的 props 使用 camelCase、Pascalcase,在 html 模板中引用時,一律使用 kebab-case ,因為會需要先經過瀏覽器解析。
1 2 3 4 5 6 7 8 9
| Vue.component('my-component', { props: ['myMesssage', 'MyLastName'], template: ` <h1>{{myMesssage}} {{MyLastName}}</h1>`, });
new Vue({ el: '#app', });
|
1 2 3 4
| <div id='app'> <my-component my-messsage='Hello' my-last-name='Lin' > </my-component> </div>
|
如果是在 template 中,即可使用 camelCase、Pascalcase。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Vue.component('my-component', { props: ['myMesssage', 'MyLastName'], template: `<h1>{{myMesssage}} {{MyLastName}}</h1>`, });
new Vue({ el: '#app', template: ` <div> <my-component myMesssage='Hello' MyLastName='Lin'> </my-component> </div> `, });
|
動態綁定 props
- 先使用
v-bind:date='today'
語法,讓 tag 中的 prop 值可以綁定到 data 中的資料,所以此時的 date
的值是 ‘20180606’(如果沒有使用v-bind:
,直接寫 date='today'
,則 date
的值是 ‘today’)
- 接著在 component ,props 屬性定義傳入的資要有 ‘date’,此時,component 即已經接到上層傳來的資料
- 接著在 component 中的 template 就可以引出 date 的值

陣列資料
如果是資料是陣列,在 tag 中可以用 v-for
將 data 中的 users
一個個以 text 叫出來,並用 v-bind:user
將users
中的值綁定給 user
1 2 3 4
| <div id='app'> <post v-for='text in users' :user='text'> </post> </div>
|
接著在 component 中,同樣在 props 屬性定義傳入的資料有 ‘user’,此時 component 即已經取得該值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| new Vue({ el: '#app', data: { users: ['Amy', 'Betty', 'Celine', 'Doris'], }, components: { post: { props: ['user'], template: ` <div>{{user}}<div> `, }, }, });
|
物件資料
1 2 3 4 5
| <div id='app'> <lists v-for='member in members' :name='member.name' :gender='member.gender'> </lists> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| new Vue({ el: '#app', data: { members: [ { name: 'Amy', gender: 'F' }, { name: 'Jack', gender: 'M' }, { name: 'Cindy', gender: 'F' }, { name: 'Doris', gender: 'F' }, ], }, components: { lists: { props: ['name', 'gender'], template: ` <div> {{name}} <small>{{gender}}</small><div> `, }, }, });
|
如果要將一個物件裡面的所有屬性,指定給一個 component 的 props ,除了上述一個個綁定以外,有另外一個特殊用法,將 html 改寫如下:
1 2 3 4
| <div id='app'> <lists v-for='member in members' v-bind='member'> </lists> </div>
|
數值資料
在 tag 中,當要綁定 props 的資料為數值,必須要用 v-bind
語法綁定(如果直接寫 number=’1’,則接受到的資料會是字串’1’)
1 2 3 4
| <div id='app'> <counter :number='1'> </counter> </div>
|
1 2 3 4 5 6 7 8 9 10 11
| new Vue({ el: '#app', components: { counter: { props: ['number'], template: ` <div> {{number+1}}<div> `, }, }, });
|
單向數據流
上傳下
codepen 結果呈現
透過 props 上傳下,上層資料可以往下傳,所以上層資料改變,下層資料也會跟著變;這個資料傳遞的動作是單向的,資料並不會往上傳,所以下層數據改變,並不會影響上層。
- 第 5 行,引入
<counter/>
組件,:count='count'
的意思代表,counter 組件的 props 資料中,:count
的數據綁定上層'count'
的資料。
1 2 3 4 5 6
| <!-- html --> <div id='app'> <h1>{{count}}</h1> <button @click='count+=1'>Add+1</button> <counter :count='count'></counter> </div>
|
- 第 1-5 行是上層的資料,第 6-16 行是註冊區域組件的資料。
- 由上傳下的單向原理解釋,當第 4 行上層 count 的數據變動,第 8 行組件中的 props 數據也會連帶跟著變動;可是,當組件內的 count 數據變動,並不會影響到上層。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| new Vue({ el: '#app', data: { count: 10, }, components: { counter: { props: ['count'], template: ` <div> <h1>{{count}}</h1> <button @click='count+=1'>Add+1</button> </div> `, }, }, });
|
父子階層數據分離
codepen 結果呈現
如果不希望上層的數據跟下層的 props 資料發生連動,則可以在下層組件中的 data 自定義一個變數,並僅接住上層一開始傳來的數據做為初始值,並獨立做操作。
- 第 5 行引入 counter 組件,
:start='count'
的意思代表,counter 組件的 props 資料中,:start
的數據綁定上層'count'
的資料。
1 2 3 4 5 6
| <!-- html --> <div id='app'> <h1>{{count}}</h1> <button @click='count+=1'>Add+1</button> <counter :start='count'></counter> </div>
|
- 第 8 行 counter 組件的 props 屬性中,start 收到上層傳來的數據時,不直接在組件中的 DOM 做使用,而是先在組件中的 data 重新賦值給 count,接著才在組件中的 DOM (第 16 行) 使用 count。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| new Vue({ el: '#app', data: { count: 10, }, components: { counter: { props: ['start'], data() { return { count: this.start, }; }, template: ` <div> <h1>{{count}}</h1> <button @click='count+=1'>Add+1</button> </div> `, }, }, });
|
運算上層傳來的資料
codepen 結果呈現
如果希望下層資料能夠連動上層傳來的數據,並且直接做運算,可以使用組件中的 computed 做處理
1 2 3 4 5 6
| <!-- html --> <div id='app'> <h1>{{count}}</h1> <button @click='count+=1'>Add+1</button> <counter :start='count'></counter> </div>
|
- 第 10 行的 doubleCount,是直接承接上層傳來的資料做運算所得出的結果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| new Vue({ el: '#app', data: { count: 10, }, components: { counter: { props: ['start'], computed: { doubleCount() { return this.start * 2; }, }, template: ` <div> <h1>{{doubleCount}}</h1> </div> `, }, }, });
|
Props 驗證
codepen 結果呈現
型別驗證
當一個組件在多處被使用時,我們會需要事先定義好 props 的資料有哪些,另一方面也必須定義好 props 數據的資料型態,以避免傳入不符合格式型態的資料。例如:應當傳入 Number ,卻傳入 String。
1 2 3 4
| <!-- html --> <div id="app"> <counter :start="10"></counter> </div>
|
- 第 3 行 props 改傳以物件,其中物件的,key 為 props 的名稱,而 value 則使用 JaveScript 的資料型態,例:
start:Number
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Vue.component('counter', { props: { start: Number, }, data() { return { count: this.start, }; }, template: ` <div> <h1>{{count}}</h1> <button @click="count+=1">+1</button> </div> `, });
new Vue({ el: '#app', });
|
而當資料型別錯誤時,則會 log 出錯誤訊息

資料驗證及預設值
除了指定 props 型別,也可以去驗證 props 的範圍,此外,也可以在父階層尚未賦值之前給予預設值。
- 在第 3 行,props 中的 key pair 的 value 不直接傳入資料型態,而是改以傳入一個物件,例:
start:{...}
,物件中再去定義 type(型別) 、default(預設值)、validator(驗證)
- type 的值是 JavaScript 的資料型別
- default 的值可以是純值,也可以是函式
- validator 的值是函式
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 26 27 28 29
| Vue.component('counter', { props: { start: { type: Number, default() { return app.getSetting(); }, validator(value) { return value <= 10; }, }, }, data() { return { count: this.start, }; }, template: ` <div> <h1>{{count}}</h1> <button @click="count+=1">+1</button> </div> `, });
new Vue({ el: '#app', });
|
如果驗證後不符合,則會 log 出錯誤

props 驗證的時間點
props 的檢驗是發生在組件建立「之前」,所以裡面不能用 this.date 或 this.methods!