vue2的元件之slot
介面寫多了,大家應該都會想到一個問題:JS的模組寫好以後可以在多個地方重複使用,HTML有沒有辦法做到呢?Vue給了我們這個能力,使用元件,就可以輕鬆做到。
最簡單的元件
初始化Vue例項之前,使用`Vue.component`方法註冊一個簡單的template,在HTML中,就可以直接使用。因為這裡會舉一連串的例子,就直接用`one`、`two`、`three`來作為元件名稱了。
<body>
<div id="app">
<one></one>
</div>
</body>
Vue .component('one', {
template: '<li>這是一個item</li>'
})
var app = new Vue({
el: '#app'
})
元件名稱定義的時候有一點需要注意的,就是要使用中劃線分詞。比方說,我想新建一個叫list item的元件,元件的名稱就需要是`list-item`,在HTML中使用的時候也一樣:
<div id="app">
<list-item></list-item>
</div>
Vue.component('list-item' , {
template: '<li>這是一個item</li>'
})
元件的內容可以從資料獲取嗎?
可以。在元件的data方法裡面返回資料就可以了。跟Vue例項不一樣的是,元件的data對應一個function,在元件中想要用到的資料,需要從這個方法裡面返回(返回的資料型別是物件)。
<div id="app">
<two></two>
</div>
Vue.component('two', {
template: '<li>{{ listItem.name }}</li>' ,
data: function () {
return {
// 在html中引入gamesDB.js
listItem: window.games[0]
}
}
})
元件的內容可以在HTML裡面定義嗎?
可以。在元件中使用`<slot>`吧。在HTML的元件中間定義的內容,就會被插入到`<slot>` tag的位置中去。除了直接定義文字之外,當然也可以寫HTML。
<div id="app">
<three>item1</three>
<three>item2</three>
<three>item3</three>
</div>
Vue.component('three', {
template: '<li><slot></slot></li>'
})
在沒有定義元件內容的時候,可以有預設的內容嗎?
可以。在`<slot>` tag中間設定的內容,就是預設的內容。
<div id="app">
<four></four>
<four>這是自定義的內容</four>
</div>
Vue.component('three', {
template: '<li><slot>預設內容</slot></li>'
})
如果我想在不同的位置插入不同的內容呢?
使用具名`<slot>`吧。在template裡面設定好每個slot的名稱,在HTML中通過`slot`屬性指定內容要插入到哪個具名`<slot>`中。詳情請看下面的程式碼片段和註釋。
<div id="app">
<five>
<!-- 指定要插入header這個slot中 -->
<ul slot="header" class="nav nav-tabs">
<li class="active"><a href="#">Home</a></li>
<li><a href="#">Profile</a></li>
<li><a href="#">Messages</a></li>
</ul>
<!-- 指定要插入content這個slot中 -->
<div slot="content">this is my awesome website</div>
</five>
</div>
Vue.component('five', {
template:
'<div>' +
'<div class="top-nav">' +
// 設定slot的名稱為header
'<slot name="header"></slot>' +
'</div>' +
'<div class="main">' +
// 設定slot的名稱為content
'<slot name="content"></slot>' +
'</div>' +
'</div>'
})
圖片中選中的這一行,因為在HTML中指定slot的時候使用了`div` tag所以文字被它包了起來,如果希望直接插入文字,可以使用`template`這個tag:
<div id="app">
<five>
<ul slot="header" class="nav nav-tabs">
<!-- ... -->
</ul>
<!-- 改為使用template tag -->
<template slot="content">this is my awesome website</template>
</five>
</div>
既然元件相當於自定義了一個tag,那可以自定義tag的屬性嗎?
可以的。使用`component`的`props`來設定吧。這裡有一點千萬要記得,在`props`裡面,是駝峰式分詞,但是,在HTML裡面使用這個屬性的時候,需要用中劃線分詞,是中!劃!線!我最開始使用的時候,兩邊都習慣性地使用駝峰,結果死活沒有效果。最後才發現官方文件有說明……
<div id="app">
<six user-name="john"></six>
</div>
Vue.component('six', {
props: ['userName'],
template: '<li>{{ userName }}</li>'
})
從屬性傳入的資料,元件內可以進行處理嗎?
可以。我們用計算屬性做例子吧。把屬性設定的文字轉換為全大寫。
<div id="app">
<six user-name="john"></six>
</div>
Vue.component('six', {
props: ['userName'],
// 最後template中使用的是計算屬性
template: '<li>{{ uppercaseName }}</li>',
computed: {
uppercaseName: function() {
return this.userName.trim().toUpperCase()
}
}
})
這些自定義的屬性也可以用v-bind指令嗎?
YES!直接用官方的一個雙向資料繫結的例子吧:
<div id="app">
<input type="text" v-model="inputMsg" />
</br>
<six :user-name="inputMsg"></six>
</div>
Vue.component('six', {
props: ['userName'],
template: '<li>{{ uppercaseName }}</li>',
computed: {
uppercaseName: function() {
return this.userName.trim().toUpperCase()
}
}
})
var app = new Vue({
el: '#app',
data: {
inputMsg: ''
}
})
可以在元件裡面直接使用另外一個元件嗎?
當然可以。我們直接上例子吧:
<div id="app">
<game-list></game-list>
</div>
Vue.component('game-list', {
template:
'<ul>' +
// 直接使用第三個元件進行迴圈
'<three v-for="game in games">{{ game.name }}</three>' +
'</ul>',
data: function () {
return {
games: window.games
}
}
})
這期的基本上把元件的基礎都過了一遍,視訊裡面會附加套用boostrap的css做一個自己的元件的內容。敬請期待下一期,元件通訊。