Vue.js 組件

2018-04-12 14:06 更新

組件

本節(jié)介紹 Vue.js 組件的使用。

組件是 Vue.js 最強大的功能之一,使用組件可以擴展 HTML 元素,封裝可重用的代碼。

使用組件

注冊

之前說過,我們可以用 Vue.extend() 創(chuàng)建一個組件構(gòu)造器:

var MyComponent = Vue.extend({
  // 選項...
})

要把這個構(gòu)造器用作組件,需要用 Vue.component(tag, constructor) 注冊

// 全局注冊組件,tag 為 my-component
Vue.component('my-component', MyComponent)

對于自定義標簽名字,Vue.js 不強制要求遵循 [W3C 規(guī)則](http://www.w3.org/TR/custom-elements/#concepts)(小寫,并且包含一個短杠),盡管遵循這個規(guī)則比較好。

在注冊之后,組件便可以用在父實例的模塊中,以自定義元素 <my-component> 的形式使用。要確保在初始化根實例之前注冊了組件:

<div id="example">
  <my-component></my-component>
</div>
// 定義
var MyComponent = Vue.extend({
  template: '<div>A custom component!</div>'
})

// 注冊
Vue.component('my-component', MyComponent)

// 創(chuàng)建根實例
new Vue({
  el: '#example'
})

渲染為:

<div id="example">
  <div>A custom component!</div>
</div>
{% raw %}
<div id="example" class="demo">
  <my-component></my-component>
</div>
<script>
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})
new Vue({ el: '#example' })
</script>
{% endraw %}

注意組件的模板替換了自定義元素,自定義元素的作用只是作為一個掛載點。這可以用實例選項 replace 改變。

局部注冊

不需要全局注冊每個組件。可以讓組件只能用在其它組件內(nèi),用實例選項 components 注冊:

var Child = Vue.extend({ /* ... */ })

var Parent = Vue.extend({
  template: '...',
  components: {
    // <my-component> 只能用在父組件模板內(nèi)
    'my-component': Child
  }
})

這種封裝也適用于其它資源,如指令、過濾器和過渡。

注冊語法糖

為了讓事件更簡單,可以直接傳入選項對象而不是構(gòu)造器給 Vue.component()component 選項。Vue.js 在背后自動調(diào)用 Vue.extend()

// 在一個步驟中擴展與注冊
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})

// 局部注冊也可以這么做
var Parent = Vue.extend({
  components: {
    'my-component': {
      template: '<div>A custom component!</div>'
    }
  }
})

組件選項問題

傳入 Vue 構(gòu)造器的多數(shù)選項也可以用在 Vue.extend() 中,不過有兩個特例: data and el。試想如果我們簡單地把一個對象作為 data 選項傳給 Vue.extend()

var data = { a: 1 }
var MyComponent = Vue.extend({
  data: data
})

這么做的問題是 MyComponent 所有的實例將共享同一個 data 對象!這基本不是我們想要的,因此我們應當使用一個函數(shù)作為 data 選項,函數(shù)返回一個新對象:

var MyComponent = Vue.extend({
  data: function () {
    return { a: 1 }
  }
})

同理,el 選項用在 Vue.extend() 中時也須是一個函數(shù)。

is 特性

一些 HTML 元素,如 <table>,限制什么元素可以放在它里面。自定義元素不在白名單上,將被放在元素的外面,因而渲染不正確。這時應當使用 is 特性,指示它是一個自定義元素:

<table>
  <tr is="my-component"></tr>
</table>

Props

使用 Props 傳遞數(shù)據(jù)

組件實例的作用域是孤立的。這意味著不能并且不應該在子組件的模板內(nèi)直接引用父組件的數(shù)據(jù)??梢允褂?props 把數(shù)據(jù)傳給子組件。

"prop" 是組件數(shù)據(jù)的一個字段,期望從父組件傳下來。子組件需要顯式地用 props 選項聲明 props:

Vue.component('child', {
  // 聲明 props
  props: ['msg'],
  // prop 可以用在模板內(nèi)
  // 可以用 `this.msg` 設(shè)置
  template: '<span>{{ msg }}</span>'
})

然后向它傳入一個普通字符串:

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

結(jié)果:

{% raw %}
<div id="prop-example-1" class="demo">
  <child msg="hello!"></child>
</div>
<script>
new Vue({
  el: '#prop-example-1',
  components: {
    child: {
      props: ['msg'],
      template: '<span>{{ msg }}</span>'
    }
  }
})
</script>
{% endraw %}

camelCase vs. kebab-case

HTML 特性不區(qū)分大小寫。名字形式為 camelCase 的 prop 用作特性時,需要轉(zhuǎn)為 kebab-case(短橫線隔開):

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

動態(tài) Props

類似于綁定一個普通的特性到一個表達式,也可以用 v-bind 綁定動態(tài) Props 到父組件的數(shù)據(jù)。每當父組件的數(shù)據(jù)變化時,也會傳導給子組件:

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

使用 v-bind 的縮寫語法通常更簡單:

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

結(jié)果:

{% raw %}
<div id="demo-2" class="demo">
  <input v-model="parentMsg">
  <br>
  <child v-bind:my-message="parentMsg"></child>
</div>
<script>
new Vue({
  el: '#demo-2',
  data: {
    parentMsg: 'Message from parent'
  },
  components: {
    child: {
      props: ['myMessage'],
      template: '<span>{{myMessage}}</span>'
    }
  }
})
</script>
{% endraw %}

字面量語法 vs. 動態(tài)語法

初學者常犯的一個錯誤是使用字面量語法傳遞數(shù)值:

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

因為它是一個字面 prop,它的值以字符串 "1" 而不是以實際的數(shù)字傳下去。如果想傳遞一個實際的 JavaScript 數(shù)字,需要使用動態(tài)語法,從而讓它的值被當作 JavaScript 表達式計算:

<!-- 傳遞實際的數(shù)字  -->
<comp :some-prop="1"></comp>

Prop 綁定類型

prop 默認是單向綁定:當父組件的屬性變化時,將傳導給子組件,但是反過來不會。這是為了防止子組件無意修改了父組件的狀態(tài)——這會讓應用的數(shù)據(jù)流難以理解。不過,也可以使用 .sync.once 綁定修飾符顯式地強制雙向或單次綁定:

比較語法:

<!-- 默認為單向綁定 -->
<child :msg="parentMsg"></child>

<!-- 雙向綁定 -->
<child :msg.sync="parentMsg"></child>

<!-- 單次綁定 -->
<child :msg.once="parentMsg"></child>

雙向綁定會把子組件的 msg 屬性同步回父組件的 parentMsg 屬性。單次綁定在建立之后不會同步之后的變化。

注意如果 prop 是一個對象或數(shù)組,是按引用傳遞。在子組件內(nèi)修改它**會**影響父組件的狀態(tài),不管是使用哪種綁定類型。

Prop 驗證

組件可以為 props 指定驗證要求。當組件給其他人使用時這很有用,因為這些驗證要求構(gòu)成了組件的 API,確保其他人正確地使用組件。此時 props 的值是一個對象,包含驗證要求:

Vue.component('example', {
  props: {
    // 基礎(chǔ)類型檢測 (`null` 意思是任何類型都可以)
    propA: Number,
    // 必需且是字符串
    propB: {
      type: String,
      required: true
    },
    // 數(shù)字,有默認值
    propC: {
      type: Number,
      default: 100
    },
    // 對象/數(shù)組的默認值應當由一個函數(shù)返回
    propD: {
      type: Object,
      default: function () {
        return { msg: 'hello' }
      }
    },
    // 指定這個 prop 為雙向綁定
    // 如果綁定類型不對將拋出一條警告
    propE: {
      twoWay: true
    },
    // 自定義驗證函數(shù)
    propF: {
      validator: function (value) {
        return value > 10
      }
    },
    // 轉(zhuǎn)換函數(shù)(1.0.12 新增)
    // 在設(shè)置值之前轉(zhuǎn)換值
    propG: {
      coerce: function (val) {
        return val + '' // 將值轉(zhuǎn)換為字符串
      }
    },
    propH: {
      coerce: function (val) {
        return JSON.parse(val) // 將 JSON 字符串轉(zhuǎn)換為對象
      }
    }
  }
})

type 可以是下面原生構(gòu)造器:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array

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

當 prop 驗證失敗了,Vue 將拒絕在子組件上設(shè)置此值,如果使用的是開發(fā)版本會拋出一條警告。

父子組件通信

父鏈

子組件可以用 this.$parent 訪問它的父組件。根實例的后代可以用 this.$root 訪問它。父組件有一個數(shù)組 this.$children,包含它所有的子元素。

盡管可以訪問父鏈上任意的實例,不過子組件應當避免直接依賴父組件的數(shù)據(jù),盡量顯式地使用 props 傳遞數(shù)據(jù)。另外,在子組件中修改父組件的狀態(tài)是非常糟糕的做法,因為:

  1. 這讓父組件與子組件緊密地耦合;

  2. 只看父組件,很難理解父組件的狀態(tài)。因為它可能被任意子組件修改!理想情況下,只有組件自己能修改它的狀態(tài)。

自定義事件

Vue 實例實現(xiàn)了一個自定義事件接口,用于在組件樹中通信。這個事件系統(tǒng)獨立于原生 DOM 事件,做法也不同。

每個 Vue 實例都是一個事件觸發(fā)器:

  • 使用 $on() 監(jiān)聽事件;

  • 使用 $emit() 在它上面觸發(fā)事件;

  • 使用 $dispatch() 派發(fā)事件,事件沿著父鏈冒泡;

  • 使用 $broadcast() 廣播事件,事件向下傳導給所有的后代。

不同于 DOM 事件,Vue 事件在冒泡過程中第一次觸發(fā)回調(diào)之后自動停止冒泡,除非回調(diào)明確返回 `true`。

簡單例子:

<!-- 子組件模板 -->
<template id="child-template">
  <input v-model="msg">
  <button v-on:click="notify">Dispatch Event</button>
</template>

<!-- 父組件模板 -->
<div id="events-example">
  <p>Messages: {{ messages | json }}</p>
  <child></child>
</div>
// 注冊子組件
// 將當前消息派發(fā)出去
Vue.component('child', {
  template: '#child-template',
  data: function () {
    return { msg: 'hello' }
  },
  methods: {
    notify: function () {
      if (this.msg.trim()) {
        this.$dispatch('child-msg', this.msg)
        this.msg = ''
      }
    }
  }
})

// 啟動父組件
// 將收到消息時將事件推入一個數(shù)組
var parent = new Vue({
  el: '#events-example',
  data: {
    messages: []
  },
  // 在創(chuàng)建實例時 `events` 選項簡單地調(diào)用 `$on`
  events: {
    'child-msg': function (msg) {
      // 事件回調(diào)內(nèi)的 `this` 自動綁定到注冊它的實例上
      this.messages.push(msg)
    }
  }
})
{% raw %}
<script type="x/template" id="child-template">
  <input v-model="msg">
  <button v-on:click="notify">Dispatch Event</button>
</script>

<div id="events-example" class="demo">
  <p>Messages: {{ messages | json }}</p>
  <child></child>
</div>
<script>
Vue.component('child', {
  template: '#child-template',
  data: function () {
    return { msg: 'hello' }
  },
  methods: {
    notify: function () {
      if (this.msg.trim()) {
        this.$dispatch('child-msg', this.msg)
        this.msg = ''
      }
    }
  }
})

var parent = new Vue({
  el: '#events-example',
  data: {
    messages: []
  },
  events: {
    'child-msg': function (msg) {
      this.messages.push(msg)
    }
  }
})
</script>
{% endraw %}

使用 v-on 綁定自定義事件

上例非常好,不過看著父組件的代碼, "child-msg" 事件來自哪里不直觀。如果我們在模板中子組件用到的地方聲明事件處理器會更好。為了做到這點,子組件可以用 v-on 監(jiān)聽自定義事件:

<child v-on:child-msg="handleIt"></child>

這讓事情非常清晰:當子組件觸發(fā)了 "child-msg" 事件,父組件的 handleIt 方法將被調(diào)用。所有影響父組件狀態(tài)的代碼放到父組件的 handleIt 方法中;子組件只關(guān)注觸發(fā)事件。

子組件索引

盡管有 props 和 events,但是有時仍然需要在 JavaScript 中直接訪問子組件。為此可以使用 v-ref 為子組件指定一個索引 ID。例如:

<div id="parent">
  <user-profile v-ref:profile></user-profile>
</div>
var parent = new Vue({ el: '#parent' })
// 訪問子組件
var child = parent.$refs.profile

v-refv-for 一起用時,ref 是一個數(shù)組或?qū)ο?,包含相應的子組件。

使用 Slot 分發(fā)內(nèi)容

在使用組件時,常常要像這樣組合它們:

<app>
  <app-header></app-header>
  <app-footer></app-footer>
</app>

注意兩點:

  1. <app> 組件不知道它的掛載點會有什么內(nèi)容,掛載點的內(nèi)容是由 <app> 的父組件決定的。

  2. <app> 組件很可能有它自己的模板。

為了讓組件可以組合,我們需要一種方式來混合父組件的內(nèi)容與子組件自己的模板。這個處理稱為內(nèi)容分發(fā)(或 "transclusion",如果你熟悉 Angular)。Vue.js 實現(xiàn)了一個內(nèi)容分發(fā) API,參照了當前 Web 組件規(guī)范草稿,使用特殊的 <slot> 元素作為原始內(nèi)容的插槽。

編譯作用域

在深入內(nèi)容分發(fā) API 之前,我們先明確內(nèi)容的編譯作用域。假定模板為:

<child>
  {{ msg }}
</child>

msg 應該綁定到父組件的數(shù)據(jù),還是綁定到子組件的數(shù)據(jù)?答案是父組件。組件作用域簡單地說是:

父組件模板的內(nèi)容在父組件作用域內(nèi)編譯;子組件模板的內(nèi)容在子組件作用域內(nèi)編譯

一個常見錯誤是試圖在父組件模板內(nèi)將一個指令綁定到子組件屬性/方法:

<!-- 無效 -->
<child v-show="someChildProperty"></child>

假定 someChildProperty 是子組件的屬性,上例不能如預期工作。父組件模板不知道子組件的狀態(tài)。

如果要綁定子組件內(nèi)的指令到一個組件的根節(jié)點,應當在它的模板內(nèi)這么做:

Vue.component('child-component', {
  // 有效,因為是在正確的作用域內(nèi)
  template: '<div v-show="someChildProperty">Child</div>',
  data: function () {
    return {
      someChildProperty: true
    }
  }
})

類似地,分發(fā)內(nèi)容是在父組件作用域內(nèi)編譯。

單個 Slot

父組件的內(nèi)容將被拋棄,除非子組件模板包含 <slot>。如果只有一個沒有特性的 slot,整個內(nèi)容將被插到它所在的地方,替換 slot。

<slot> 標簽的內(nèi)容視為回退內(nèi)容?;赝藘?nèi)容在子組件的作用域內(nèi)編譯,只有當宿主元素為空并且沒有內(nèi)容供插入時顯示。

假定 my-component 組件有下面模板:

<div>
  <h1>This is my component!</h1>
  <slot>
    This will only be displayed if there is no content
    to be distributed.
  </slot>
</div>

父組件模板:

<my-component>
  <p>This is some original content</p>
  <p>This is some more original content</p>
</my-component>

渲染結(jié)果:

<div>
  <h1>This is my component!</h1>
  <p>This is some original content</p>
  <p>This is some more original content</p>
</div>

命名 Slot

<slot> 元素有一個特殊特性 name,用于配置如何分發(fā)內(nèi)容。多個 slot 可以有不同的名字。命名 slot 將匹配有對應 slot 特性的內(nèi)容片斷。

也可以有一個未命名 slot,它是默認 slot,作為找不到匹配內(nèi)容的回退插槽。如果沒有默認的 slot,不匹配內(nèi)容將被拋棄。

例如,假定我們有一個 multi-insertion 組件,它的模板為:

<div>
  <slot name="one"></slot>
  <slot></slot>
  <slot name="two"></slot>
</div>

父組件模板:

<multi-insertion>
  <p slot="one">One</p>
  <p slot="two">Two</p>
  <p>Default A</p>
</multi-insertion>

渲染結(jié)果為:

<div>
  <p slot="one">One</p>
  <p>Default A</p>
  <p slot="two">Two</p>
</div>

在組合組件時,內(nèi)容分發(fā) API 是非常有用的機制。

動態(tài)組件

多個組件可以使用同一個掛載點,然后動態(tài)地在它們之間切換。使用保留的 <component> 元素,動態(tài)地綁定到它的 is 特性:

new Vue({
  el: 'body',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})
<component :is="currentView">
  <!-- 組件在 vm.currentview 變化時改變 -->
</component>

keep-alive

如果把切換出去的組件保留在內(nèi)存中,可以保留它的狀態(tài)或避免重新渲染。為此可以添加一個 keep-alive 指令參數(shù):

<component :is="currentView" keep-alive>
  <!-- 非活動組件將被緩存 -->
</component>

activate 鉤子

在切換組件時,切入組件在切入前可能需要進行一些異步操作。為了控制組件切換時長,給切入組件添加 activate 鉤子:

Vue.component('activate-example', {
  activate: function (done) {
    var self = this
    loadDataAsync(function (data) {
      self.someData = data
      done()
    })
  }
})

注意 activate 鉤子只作用于動態(tài)組件切換或靜態(tài)組件初始化渲染的過程中,不作用于使用實例方法手工插入的過程中。

transition-mode

transition-mode 特性用于指定兩個動態(tài)組件之間如何過渡。

在默認情況下,進入與離開平滑地過渡。這個特性可以指定另外兩種模式:

  • in-out:新組件先過渡進入,等它的過渡完成之后當前組件過渡出去。

  • out-in:當前組件先過渡出去,等它的過渡完成之后新組件過渡進入。

示例:

<!-- 先淡出再淡入 -->
<component
  :is="view"
  transition="fade"
  transition-mode="out-in">
</component>
.fade-transition {
  transition: opacity .3s ease;
}
.fade-enter, .fade-leave {
  opacity: 0;
}
{% raw %}
<div id="transition-mode-demo" class="demo">
  <input v-model="view" type="radio" value="v-a" id="a" name="view"><label for="a">A</label>
  <input v-model="view" type="radio" value="v-b" id="b" name="view"><label for="b">B</label>
  <component
    :is="view"
    transition="fade"
    transition-mode="out-in">
  </component>
</div>
<style>
  .fade-transition {
    transition: opacity .3s ease;
  }
  .fade-enter, .fade-leave {
    opacity: 0;
  }
</style>
<script>
new Vue({
  el: '#transition-mode-demo',
  data: {
    view: 'v-a'
  },
  components: {
    'v-a': {
      template: '<div>Component A</div>'
    },
    'v-b': {
      template: '<div>Component B</div>'
    }
  }
})
</script>
{% endraw %}

雜項

組件和 v-for

自定義組件可以像普通元素一樣直接使用 v-for

<my-component v-for="item in items"></my-component>

但是,不能傳遞數(shù)據(jù)給組件,因為組件的作用域是孤立的。為了傳遞數(shù)據(jù)給組件,應當使用 props:

<my-component
  v-for="item in items"
  :item="item"
  :index="$index">
</my-component>

不自動把 item 注入組件的原因是這會導致組件跟當前 v-for 緊密耦合。顯式聲明數(shù)據(jù)來自哪里可以讓組件復用在其它地方。

編寫可復用組件

在編寫組件時,記住是否要復用組件有好處。一次性組件跟其它組件緊密耦合沒關(guān)系,但是可復用組件應當定義一個清晰的公開接口。

Vue.js 組件 API 來自三部分——prop,事件和 slot:

  • prop 允許外部環(huán)境傳遞數(shù)據(jù)給組件;

  • 事件 允許組件觸發(fā)外部環(huán)境的 action;

  • slot 允許外部環(huán)境插入內(nèi)容到組件的視圖結(jié)構(gòu)內(nèi)。

使用 v-bindv-on 的簡寫語法,模板的縮進清楚且簡潔:

<my-component
  :foo="baz"
  :bar="qux"
  @event-a="doThis"
  @event-b="doThat">
  <!-- content -->
  <img slot="icon" src="...">
  <p slot="main-text">Hello!</p>
</my-component>

異步組件

在大型應用中,我們可能需要將應用拆分為小塊,只在需要時才從服務器下載。為了讓事情更簡單,Vue.js 允許將組件定義為一個工廠函數(shù),動態(tài)地解析組件的定義。Vue.js 只在組件需要渲染時觸發(fā)工廠函數(shù),并且把結(jié)果緩存起來,用于后面的再次渲染。例如:

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

工廠函數(shù)接收一個 resolve 回調(diào),在收到從服務器下載的組件定義時調(diào)用。也可以調(diào)用 reject(reason) 指示加載失敗。這里 setTimeout 只是為了演示。怎么獲取組件完全由你決定。推薦配合使用 Webpack 的代碼分割功能

Vue.component('async-webpack-example', function (resolve) {
  // 這個特殊的 require 語法告訴 webpack
  // 自動將編譯后的代碼分割成不同的塊,
  // 這些塊將通過 ajax 請求自動下載。
  require(['./my-async-component'], resolve)
})

資源命名約定

一些資源,如組件和指令,是以 HTML 特性或 HTML 自定義元素的形式出現(xiàn)在模板中。因為 HTML 特性的名字和標簽的名字不區(qū)分大小寫,所以資源的名字通常需使用 kebab-case 而不是 camelCase 的形式,這不大方便。

Vue.js 支持資源的名字使用 camelCase 或 PascalCase 的形式,并且在模板中自動將它們轉(zhuǎn)為 kebab-case(類似于 prop 的命名約定):

// 在組件定義中
components: {
  // 使用 camelCase 形式注冊
  myComponent: { /*... */ }
}
<!-- 在模板中使用 kebab-case 形式 -->
<my-component></my-component>

ES6 對象字面量縮寫 也沒問題:

// PascalCase
import TextBox from './components/text-box';
import DropdownMenu from './components/dropdown-menu';

export default {
  components: {
    // 在模板中寫作 <text-box> 和 <dropdown-menu>
    TextBox,
    DropdownMenu
  }
}

遞歸組件

組件在它的模板內(nèi)可以遞歸地調(diào)用自己,不過,只有當它有 name 選項時才可以:

var StackOverflow = Vue.extend({
  name: 'stack-overflow',
  template:
    '<div>' +
      // 遞歸地調(diào)用它自己
      '<stack-overflow></stack-overflow>' +
    '</div>'
})

上面組件會導致一個錯誤 "max stack size exceeded",所以要確保遞歸調(diào)用有終止條件。當使用 Vue.component() 全局注冊一個組件時,組件 ID 自動設(shè)置為組件的 name 選項。

片斷實例

在使用 template 選項時,模板的內(nèi)容將替換實例的掛載元素。因而推薦模板的頂級元素始終是單個元素。

不這么寫模板:

<div>root node 1</div>
<div>root node 2</div>

推薦這么寫:

<div>
  I have a single root node!
  <div>node 1</div>
  <div>node 2</div>
</div>

下面幾種情況會讓實例變成一個片斷實例

  1. 模板包含多個頂級元素。
  2. 模板只包含普通文本。
  3. 模板只包含其它組件(其它組件可能是一個片段實例)。
  4. 模板只包含一個元素指令,如 <partial> 或 vue-router 的 <router-view>。
  5. 模板根節(jié)點有一個流程控制指令,如 v-ifv-for

這些情況讓實例有未知數(shù)量的頂級元素,它將把它的 DOM 內(nèi)容當作片斷。片斷實例仍然會正確地渲染內(nèi)容。不過,它沒有一個根節(jié)點,它的 $el 指向一個錨節(jié)點,即一個空的文本節(jié)點(在開發(fā)模式下是一個注釋節(jié)點)。

但是更重要的是,組件元素上的非流程控制指令,非 prop 特性和過渡將被忽略,因為沒有根元素供綁定:

<!-- 不可以,因為沒有根元素 -->
<example v-show="ok" transition="fade"></example>

<!-- props 可以 -->
<example :prop="someData"></example>

<!-- 流程控制可以,但是不能有過渡 -->
<example v-if="ok"></example>

當然片斷實例有它的用處,不過通常給組件一個根節(jié)點比較好。它會保證組件元素上的指令和特性能正確地轉(zhuǎn)換,同時性能也稍微好些。

內(nèi)聯(lián)模板

如果子組件有 inline-template 特性,組件將把它的內(nèi)容當作它的模板,而不是把它當作分發(fā)內(nèi)容。這讓模板更靈活。

<my-component inline-template>
  <p>These are compiled as the component's own template</p>
  <p>Not parent's transclusion content.</p>
</my-component>

但是 inline-template 讓模板的作用域難以理解,并且不能緩存模板編譯結(jié)果。最佳實踐是使用 template 選項在組件內(nèi)定義模板。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號