Vue9:組件

Vue.js 組件

組件(Component)是 Vue.js 最強大的功能之一。

組件可以擴展 HTML 元素,封裝可重用的代碼。

組件系統讓我們可以用獨立可複用的小組件來構建大型應用,幾乎任意類型的應用的界面都可以抽象爲一個組件樹:

 註冊一個全局組件語法格式如下:

Vue.component(tagName, options)

tagName 爲組件名,options 爲配置選項。註冊後,我們可以使用以下方式來調用組件:

<tagName></tagName>

全局組件實例

註冊一個簡單的全局組件 runoob,並使用它:

<div id="app">
    <runoob></runoob>
</div>
 
<script>
// 註冊
Vue.component('runoob', {
  template: '<h1>自定義組件!</h1>'
})
// 創建根實例
new Vue({
  el: '#app'
})
</script>

局部組件

我們也可以在實例選項中註冊局部組件,這樣組件只能在這個實例中使用:

<div id="app">
    <runoob></runoob>
</div>
 
<script>
var Child = {
  template: '<h1>自定義組件!</h1>'
}
 
// 創建根實例
new Vue({
  el: '#app',
  components: {
    // <runoob> 將只在父模板可用
    'runoob': Child
  }
})
</script>

Prop

prop 是子組件用來接受父組件傳遞過來的數據的一個自定義屬性。

父組件的數據需要通過 props 把數據傳給子組件,子組件需要顯式地用 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>

動態 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>

以下實例中使用 v-bind 指令將 todo 傳到每一個重複的組件中:

<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.text }}</li>'
})
new Vue({
  el: '#app',
  data: {
    sites: [
      { text: 'Runoob' },
      { text: 'Google' },
      { text: 'Taobao' }
    ]
  }
})
</script>

注意: prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是不會反過來。

Prop 驗證

組件可以爲 props 指定驗證要求。

爲了定製 prop 的驗證方式,你可以爲 props 中的值提供一個帶有驗證需求的對象,而不是一個字符串數組。例如:

Vue.component('my-component', {
  props: {
    // 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
    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 ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

當 prop 驗證失敗的時候,(開發環境構建版本的) Vue 將會產生一個控制檯的警告。

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

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

type 也可以是一個自定義構造器,使用 instanceof 檢測。

自定義事件

父組件是使用 props 傳遞數據給子組件,但如果子組件要把數據傳遞回去,就需要使用自定義事件!

我們可以使用 v-on 綁定自定義事件, 每個 Vue 實例都實現了事件接口(Events interface),即:

  • 使用 $on(eventName) 監聽事件
  • 使用 $emit(eventName) 觸發事件

另外,父組件可以在使用子組件的地方直接用 v-on 來監聽子組件觸發的事件。

以下實例中子組件已經和它外部完全解耦了。它所做的只是觸發一個父組件關心的內部事件。

<div id="app">
    <div id="counter-event-example">
      <p>{{ total }}</p>
      <button-counter v-on:increment="incrementTotal"></button-counter>
      <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>
</div>
 
<script>
Vue.component('button-counter', {
  template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    incrementHandler: function () {
      this.counter += 1
      this.$emit('increment')
    }
  },
})
new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function () {
      this.total += 1
    }
  }
})
</script>

如果你想在某個組件的根元素上監聽一個原生事件。可以使用 .native 修飾 v-on 。例如:

<my-component v-on:click.native="doTheThing"></my-component>

data 必須是一個函數

上面例子中,可以看到 button-counter 組件中的 data 不是一個對象,而是一個函數:

data: function () {
  return {
    count: 0
  }
}

這樣的好處就是每個實例可以維護一份被返回對象的獨立的拷貝,如果 data 是一個對象則會影響到其他實例,如下所示:

實例

<div id="components-demo3" class="demo">
    <button-counter2></button-counter2>
    <button-counter2></button-counter2>
    <button-counter2></button-counter2>
</div>
 
<script>
var buttonCounter2Data = {
  count: 0
}
Vue.component('button-counter2', {
    /*
    data: function () {
        // data 選項是一個函數,組件不相互影響
        return {
            count: 0
        }
    },
    */
    data: function () {
        // data 選項是一個對象,會影響到其他實例
        return buttonCounter2Data
    },
    template: '<button v-on:click="count++">點擊了 {{ count }} 次。</button>'
})
new Vue({ el: '#components-demo3' })
</script>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章