Before
最近開始小程序開發(fā),細看一番,小程序開發(fā)也挺類似于vuejs開發(fā),也有了成型的小程序采用vuejs開發(fā)。便開始了學(xué)習
vue是最近討論的比較多的一個前端框架,其類似于ag的但是其學(xué)習成本遠低于ag,因此也是許多新手首選入門的框架之一。vue的核心之一應(yīng)當就是組件的使用與構(gòu)建。那么在此就先簡單的記錄下此次學(xué)習的收獲
如何創(chuàng)建
注冊組件就是利用Vue.component(name, options)方法,頭一個參數(shù)為組件名,后一個參數(shù)為json格式的組件配置。
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
如上我們注冊了一個組件,接下來就是在Vue實例掛載的Dom元素中使用它。、
<div id="example">
<my-component></my-component>
</div>
// 注冊
Vue.component(...) // 如上
// 創(chuàng)建根實例
new Vue({
el: '#example'
})
渲染為:
<div id="example">
<div>A custom component!</div>
</div>
上述方法為全局注冊,如果我們只希望在局部作用域中使用該組件,可以這樣做:
var c = {
template: '<div>A custom component!</div>'
}
new Vue({
// ...
components: {
// <my-component> 將只在父組件模板中可用
'my-component': c
}
})
data屬性
在這里有一個需要關(guān)注的點,那就是可能初學(xué)vue的時候,我們的data屬性基本都是使用的一個對象,但是在組件這里,data卻應(yīng)該作為一個函數(shù)。
// This code is error
Vue.component('my-component', {
template: '<span>{{ message }}</span>',
data: {
message: 'hello'
}
})
// Good
Vue.component('my-component', {
template: '<span>{{ message }}</span>',
data() {
return { message: 'hello'; }
}
})
為什么我們需要這樣做?首先我們應(yīng)當了解在js中,對象是引用類型。實際上說到引用類型大部分人就已經(jīng)明白了。如果我們在組件構(gòu)建中仍然采用之前的對象形式,那么多個復(fù)用組件就會使用同一個data對象,從而導(dǎo)致錯誤產(chǎn)生。而正確的方法則是如上采用了return一個新對象的形式,保證了組件復(fù)用的數(shù)據(jù)正確性。
slot分發(fā)
顯然,組件的嵌套是我們會經(jīng)常使用到的,而vue也提供了對應(yīng)的方法 => slot, 正如其中文意思,插槽,我們嵌入的內(nèi)容就相當于插入這個插槽中。
slot相當于子組件設(shè)置了一個地方,如果在調(diào)用它的時候,往它的開閉標簽之間放了東西,那么它就把這些東西放到slot中。
- 當子組件中沒有slot時,父組件放在子組件標簽內(nèi)的東西將被丟棄;
- 子組件的slot標簽內(nèi)可以放置內(nèi)容,當父組件沒有放置內(nèi)容在子組件標簽內(nèi)時,slot中的內(nèi)容會渲染出來;
- 當父組件在子組件標簽內(nèi)放置了內(nèi)容時,slot中的內(nèi)容被丟棄
e.g.
// Child
<div>
<h2>我是子組件的標題</h2>
<slot>
只有在沒有要分發(fā)的內(nèi)容時才會顯示。
</slot>
</div>
// Parent
<div>
<h1>我是父組件的標題</h1>
<my-component>
<p>這是一些初始內(nèi)容</p>
<p>這是更多的初始內(nèi)容</p>
</my-component>
</div>
// Result
<div>
<h1>我是父組件的標題</h1>
<div>
<h2>我是子組件的標題</h2>
<p>這是一些初始內(nèi)容</p>
<p>這是更多的初始內(nèi)容</p>
</div>
</div>
當我們使用了多個slot時,新的問題出現(xiàn),我們?nèi)绾未_保插入正確的槽?即如何分發(fā)內(nèi)容?vue提供了一種方案=>具名插槽:
// Child -> app-layout
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
// Parent
<app-layout>
<h1 slot="header">這里可能是一個頁面標題</h1>
<p>主要內(nèi)容的一個段落。</p>
<p>另一個主要段落。</p>
<p slot="footer">這里有一些聯(lián)系信息</p>
</app-layout>
// Result
<div class="container">
<header>
<h1>這里可能是一個頁面標題</h1>
</header>
<main>
<p>主要內(nèi)容的一個段落。</p>
<p>另一個主要段落。</p>
</main>
<footer>
<p>這里有一些聯(lián)系信息</p>
</footer>
</div>
組件間通信
組件間的通信通常分為父子組件與非父子組件通信。在父子組件通信中,采用vue提供的prop屬性。Prop 是單向綁定的:當父組件的屬性變化時,將傳導(dǎo)給子組件,但是反過來不會。這是為了防止子組件無意間修改了父組件的狀態(tài),來避免應(yīng)用的數(shù)據(jù)流變得難以理解。因此,
注意在 JavaScript 中對象和數(shù)組是引用類型,指向同一個內(nèi)存空間,如果 prop 是一個對象或數(shù)組,在子組件內(nèi)部改變它會影響父組件的狀態(tài)。
那如果我們希望信息能夠進行雙向的傳遞,那么可以采用emit
與on
,熟悉js事件的同學(xué)在這里其實就能很快明白在這里的原理其實在于我們在發(fā)送方自定義一個事件,事件參數(shù)為傳遞數(shù)據(jù),同時我們在接收方處監(jiān)聽該事件,以此實現(xiàn)信息的傳遞。借用此我們能很方便的實現(xiàn)雙向的數(shù)據(jù)傳遞,且可以避免由于某一方對數(shù)據(jù)的不當修改導(dǎo)致另一方的出錯。然而,盡管如此,其仍然不夠使用,因為在多組件通信中,這樣的寫法就顯得繁雜。因此vue提供了一個插件, vuex,其為一個狀態(tài)管理插件,正適用于這些需要組件間通信的場景。
這里給出使用prop與emit/on進行消息傳遞的例子,關(guān)于vuex再后面博客再補充。
// prop通信
Vue.component('child', {
// 聲明 props
props: ['message'],
// 就像 data 一樣,prop 也可以在模板中使用
// 同樣也可以在 vm 實例中通過 this.message 來使用
template: '<span>{{ message }}</span>'
})
<child message="hello!"></child>
// 事件通信
var bus = new Vue()
// 觸發(fā)組件 A 中的事件
bus.$emit('id-selected', 1)
// 在組件 B 創(chuàng)建的鉤子中監(jiān)聽事件
bus.$on('id-selected', function (id) {
// ...
})