1. 程式人生 > >vue元件(二)--prop傳遞資料

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 的情形:

  1. 這個 prop 用來傳遞一個初始值;這個子元件接下來希望將其作為一個本地的 prop 資料來使用。在這種情況下,最好定義一個本地的 data 屬性並將這個 prop 用作其初始值:

    props: ['initialCounter'],
    data: function () {
      return {
        counter: this.initialCounter
      }
    }
    
  2. 這個 prop 以一種原始的值傳入且需要進行轉換。在這種情況下,最好使用這個 prop 的值來定義一個計算屬性:

    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }