1. 程式人生 > >VUE快速入門新的——元件之間傳遞資料(1. Prop)

VUE快速入門新的——元件之間傳遞資料(1. Prop)

晚上好大家,元件我們在上邊文章中已經說過了,對大家還是有點幫助的應該。哈哈~~ 今天我們說一下關於元件之間資料是怎樣傳遞的?不難看出,其實元件之間的資料通訊,簡單的可以分為三類。

  1. 父元件向子元件傳遞
  2. 子元件向父元件傳遞
  3. 平級之間的元件資料傳遞

之前也有說到,父元件可以通過props向下傳遞資料給子元件,子元件可以通過events向上給父元件傳遞資料,下面我們就來詳細的看一下。
我們一步步來看

Prop

使用prop傳遞資料

其實通過不斷的學習,我們會發現,其實元件例項的作用域是孤立的。這意味著不能(同時也是不應該)在子元件的模板內直接引用父元件的資料。要讓子元件使用父元件的資料,我們需要通過子元件的props選項。
子元件要顯式地用props

選項宣告它所期待的資料:

Vue.component('child', {
  // 宣告 props
  props: ['message'],
  // 就像 data 一樣,prop 可以用在模板內
  // 同樣也可以在 vm 例項中像“this.message”這樣使用
  template: '<span>{{ message }}</span>'
})

然後我們就可以像下邊這樣向它傳入一個字串:

<child message="hello!"></child>

結果就是可想而知的輸出hello!

camelCase vs kebab-case

HTML特性是不區分大小寫的。所以,當使用的不是字串模板時,camelCase(駝峰式)命名的prop需要轉換為相對應的kebab-case(短橫線隔開式)命名:

Vue.component('child', {
  // camelCase in JavaScript
  props: ['myMessage'],
  template: '<span>{{ myMessage }}</span>'
})
<!-- kebab-case in HTML -->
<child my-message="hello!"></child>

如果我們使用的是字串模板,那麼就沒有了這些限制。

動態prop

在模板中,要動態的繫結父元件的資料到子元件的props,與繫結的任何普通的html特性相類似,就是使用v-bind。每當父元件的資料發生變化時,改變化也會傳遞給子元件:

<div>
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg"></child>
</div>

使用v-bind縮寫方法寫起來更簡單:

<child :my-message="parentMsg"></child>

此時,我們就做到了動態繫結

字面量法 VS 動態語法

我們剛接觸Vue經常犯一個錯誤,使用字面量語法傳遞資料:

<!-- 傳遞了一個字串 "1" -->
<comp some-prop="1"></comp>

因為它是一個字面 prop,它的值是字串 “1” 而不是 number。如果想傳遞一個實際的 number,需要使用v-bind ,從而讓它的值被當作 JavaScript 表示式計算:

<!-- 傳遞實際的 number -->
<comp v-bind:some-prop="1"></comp>

單向資料流

prop 是單向繫結的:當父元件的屬性變化時,將傳導給子元件,但是不會反過來。這是為了防止子元件無意修改了父元件的狀態——這會讓應用的資料流難以理解。

另外,每次父元件更新時,子元件的所有 prop 都會更新為最新值。這意味著你不應該在子元件內部改變 prop。如果你這麼做了,Vue 會在控制檯給出警告。

為什麼我們會有修改 prop 中資料的衝動呢?通常是這兩種原因:

  1. prop 作為初始值傳入後,子元件想把它當作區域性資料來用;
  2. prop 作為初始值傳入,由子元件處理成其它資料輸出。
    對於這兩種原因,正確的應對方式為:
    1.定義一個區域性變數,並用 prop 的值初始化它:
props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}
  1. 定義一個計算屬性,處理 prop 的值並返回。
props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

注意在 JavaScript 中物件和陣列是引用型別,指向同一個記憶體空間,如果 prop 是一個物件或陣列,在子元件內部改變它會影響父元件的狀態。

prop驗證

我們可以為元件的 props 指定驗證規格。如果傳入的資料不符合規格,Vue 會發出警告。當元件給其他人使用時,這很有用。

要指定驗證規格,需要用物件的形式,而不能用字串陣列:

Vue.component('example', {
  props: {
    // 基礎型別檢測 (`null` 意思是任何型別都可以)
    propA: Number,
    // 多種型別
    propB: [String, Number],
    // 必傳且是字串
    propC: {
      type: String,
      required: true
    },
    // 數字,有預設值
    propD: {
      type: Number,
      default: 100
    },
    // 陣列/物件的預設值應當由一個工廠函式返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函式
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
})

type可以使下面原生構造器:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
  • Symbol
    type也可以是一個自定義構造器函式,使用intaceof檢測。
    當 prop 驗證失敗,Vue 會在丟擲警告 (如果使用的是開發版本)。注意 props 會在元件例項建立之前進行校驗,所以在 defaultvalidator函式裡,諸如 datacomputedmethods 等例項屬性還無法使用。

非Prop屬性

所謂非prop 屬性,就是它可以直接傳入元件,而不需要定義相應的 prop

明確給元件定義prop 是傳參的推薦方式,但元件的作者並不總能預見到元件被使用的場景。所以,元件可以接收任意傳入的屬性,這些屬性都會被新增到元件的根元素上。

例如,第三方元件 bs-date-input,當它要和一個 Bootstrap 外掛互操作時,需要在這個第三方元件的 input上新增data-3d-date-picker 屬性,這時可以把屬性直接新增到元件上 (不需要事先定義 prop):

<bs-date-input data-3d-date-picker="true"></bs-date-input>

新增屬性 data-3d-date-picker="true" 之後,它會被自動新增到 bs-date-input 的根元素上

替換/覆蓋現有屬性

我們來想象一下這是 bs-date-input 的模板:

<input type="date" class="form-control">

為了給該日期選擇器外掛增加一個特殊的主題,我們可能需要增加一個特殊的 class,比如:

<bs-date-input
  data-3d-date-picker="true"
  class="date-picker-theme-dark"
></bs-date-input>

在這個 case 當中,我們定義了兩個不一樣的 class 的值:

  • form-control,來自元件的模板
  • date-picker-theme-dark,從父元件傳進來的

對於多數特性來說,傳遞給元件的值會覆蓋元件本身設定的值。即例如傳遞 type="large" 將會覆蓋 type="date" 且有可能破壞該元件!索性我們對待 classstyle 特性會更聰明一些,這兩個特性的值都會做合併 (merge) 操作,讓最終生成的值為:form-control date-picker-theme-dark

至此呢,父元件向子元件傳遞資料我們也說的差不多的了,後邊我們再來分析子元件向父元件傳遞資料以及兩個元件(平級元件)的資料是怎樣進行傳遞的。