Vue-(十二)Props

上層傳來的 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>
`,
});
1
2
3
<div id='app'>

</div>

動態綁定 props

  1. 先使用v-bind:date='today'語法,讓 tag 中的 prop 值可以綁定到 data 中的資料,所以此時的 date的值是 ‘20180606’(如果沒有使用v-bind:,直接寫 date='today',則 date的值是 ‘today’)
  2. 接著在 component ,props 屬性定義傳入的資要有 ‘date’,此時,component 即已經接到上層傳來的資料
  3. 接著在 component 中的 template 就可以引出 date 的值

陣列資料

如果是資料是陣列,在 tag 中可以用 v-for 將 data 中的 users 一個個以 text 叫出來,並用 v-bind:userusers中的值綁定給 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:0,
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!

© 2020 Leah's Blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero