vue元件(二)--prop傳遞資料
元件組合
元件設計初衷就是要配合使用的,最常見的就是形成父子元件的關係:元件 A 在它的模板中使用了元件 B。它們之間必然需要相互通訊:父元件可能要給子元件下發資料,子元件則可能要將它內部發生的事情告知父元件。然而,通過一個良好定義的介面來儘可能將父子元件解耦也是很重要的。這保證了每個元件的程式碼可以在相對隔離的環境中書寫和理解,從而提高了其可維護性和複用性。
在 Vue 中,父子元件的關係可以總結為 prop 向下傳遞,事件向上傳遞。父元件通過 prop給子元件下發資料,子元件通過事件給父元件傳送訊息。看看它們是怎麼工作的。
Prop
prop 是父元件用來傳遞資料的一個自定義屬性。
父元件的資料需要通過 props 把資料傳給子元件,子元件需要顯式地用 props 選項宣告 "prop"
使用Prop傳遞資料
元件例項的作用域是孤立的。這意味著不能 (也不應該) 在子元件的模板內直接引用父元件的資料。父元件的資料需要通過 prop 才能下發到子元件中。
子元件要顯式地用 props
選項宣告它預期的資料:
傳遞靜態prop
<div id="app"> <child message="hello!"></child> </div> <script> // 註冊 Vue.component('child', { // 宣告 props props: ['message'], // 同樣也可以在 vm 例項中像 “this.message” 這樣使用 template: '<span>{{ message }}</span>' }) // 建立根例項 new Vue({ el: '#app'}) </script>
為了便於理解,你可以將這個Vue例項看作child的父元件。
動態prop
類似於用 v-bind 繫結 HTML 特性到一個表示式,也可以用 v-bind 動態繫結 props 的值到父元件的資料中。每當父元件的資料變化時,該變化也會傳導給子元件:
<div id="app"> <div> <input v-model="parentMsg"> <br> <child v-bind:message="parentMsg"></child> </div> </div> <script> // 註冊 Vue.component('child', { // 宣告 props props: ['message'], // 同樣也可以在 vm 例項中像 “this.message” 這樣使用 template: '<span>{{ message }}</span>' }) // 建立根例項 new Vue({ el: '#app', data: { parentMsg: '父元件內容' } }) </script>
# 傳入一個物件的所有屬性
如果你想要將一個物件的所有屬性都作為 prop 傳入,你可以使用不帶引數的 v-bind
(取代 v-bind:prop-name
)。例如,對於一個給定的物件 post
:
post: { id: 1, title: 'My Journey with Vue' } |
下面的模板:
<blog-post v-bind="post"></blog-post> |
等價於:
<blog-post v-bind:id="post.id" v-bind:title="post.title" ></blog-post> |
屬性值都繫結在這個模板上了。
#
<div id="app">
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>
</div>
<script>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{todo}}</li>'
})
new Vue({
el: '#app',
data: {
sites:{
name:'張三',
age:24
}
}
})
</script>
#
<div id="app">
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>
</div>
<script src="../js/lib/vue.min.js"></script>
<script>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{todo.name}}</li>'
})
new Vue({
el: '#app',
data: {
sites:[
{name:"pp"},
{name:"yy"},
{name:"haha"}
]
}
})
</script>
字面量語法vs動態語法
<comp some-prop="1"></comp>
定義prop時,要是不使用v-bind是字面量prop,傳遞了一個字串而不是數值1,如果想傳遞一個真正的 JavaScript 數值,則需要使用 v-bind
,從而讓它的值被當作 JavaScript表示式計算。
<div id="app">
<!-- 這裡傳遞是字串 -->
<child my-message="123+456"></child>
<!-- 這裡用了動態語法,傳遞的值會通過js的表示式計算,傳遞的是數字 -->
<child :my-message="123+456"></child>
</div>
<script>
Vue.component("child", {
props: ["myMessage"],
template: "<div>計算結果為: {{myMessage}}</div>",
});
new Vue({
el: "#app",
});
</script>
Prop的大小寫(camelCase vs kebab-case)
HTML 中的特性名是大小寫不敏感的,所以瀏覽器會把所有大寫字元解釋為小寫字元。這意味著當你使用 DOM 中的模板時,camelCase (駝峰命名法) 的 prop 名需要使用其等價的 kebab-case (短橫線分隔命名) 命名:
Vue.component('blog-post', { // 在 JavaScript 中是 camelCase 的 props: ['postTitle'], template: '<h3>{{ postTitle }}</h3>' }) |
<!-- 在 HTML 中是 kebab-case 的 --> <blog-post post-title="hello!"></blog-post> |
重申一次,如果你使用字串模板,那麼這個限制就不存在了。
單向資料流
父級 prop 的更新會向下流動到子元件中,但是反過來則不行。這樣會防止從子元件意外改變父級元件的狀態,從而導致你的應用的資料流向難以理解。
額外的,每次父級元件發生更新時,子元件中所有的 prop 都將會重新整理為最新的值。這意味著你不應該在一個子元件內部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制檯中發出警告。
這裡有兩種常見的試圖改變一個 prop 的情形:
-
這個 prop 用來傳遞一個初始值;這個子元件接下來希望將其作為一個本地的 prop 資料來使用。在這種情況下,最好定義一個本地的 data 屬性並將這個 prop 用作其初始值:
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } }
-
這個 prop 以一種原始的值傳入且需要進行轉換。在這種情況下,最好使用這個 prop 的值來定義一個計算屬性:
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }