Vue組件化開發(fā)
- 組件化開發(fā)的思想
- 組件的注冊
- 組件間的數(shù)據(jù)交互
- 組件插槽的用法
- Vue調(diào)試工具的用法
組件開發(fā)思想
- 標(biāo)準(zhǔn)
- 分治
- 重用
- 組合
組件化規(guī)范:Web Components(并非所有的瀏覽器都支持)
- 我們希望盡可能多的重用代碼
- 自定義組件的方式不太容易(html、css和js)
- 多次使用組件可能導(dǎo)致沖突
Web Components通過創(chuàng)建封裝好功能的定制元素解決上述問題(Vue部分實(shí)現(xiàn)了上述規(guī)范)
組件注冊
Vue.component('組件名稱',{
// 組件內(nèi)容
data: '組件數(shù)據(jù)',
template: '組件模板內(nèi)容'
})
<!-- 組件使用 -->
<div id="app">
<h1>{{name}}</h1>
<button-count></button-counter>
<!-- 組件是可以重用的 -->
<button-count></button-counter>
<button-count></button-counter>
</div>
<script>
// 定義一個(gè)名為 button-counter 的新組件
Vue.component('button-counter', {
data: function() {
return {
count: 0
}
},
template: '<button v-on:click="count++">點(diǎn)擊{{count}}次</button>'
})
</script>
組件注冊注意事項(xiàng):
- data必須是一個(gè)函數(shù) => 分析函數(shù)和普通對(duì)象的對(duì)比
- 組件模板內(nèi)容必須是單個(gè)根元素 => 分析演示實(shí)例的效果
- 組件模板內(nèi)容可以是模板字符串 => 模板字符串需要瀏覽器提供支持(ES6語法)
- 組建的命名方式
- 短橫線方式
Vue.component('my-component',{ /*...*/ }
- 駝峰式
Vue.component('myComponent',{ /*...*/ }
- 如果使用駝峰式命名組件,那么在使用組件的時(shí)候坪蚁,只能在字符串模板中使用駝峰的方式命名組件,但是在普通的標(biāo)簽?zāi)0逯形偶仨毷褂枚虣M線的方式命名組件
局部組件注冊
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
new Vue({
el: '#app',
components: {
'component-a' :componentA,
'component-b' :componentB,
'component-c' :componentC
}
})
// 局部組件只能在其父組件中使用
Vue調(diào)試工具
- 克隆倉庫
- 安裝依賴包
- 構(gòu)建
- 打開Chrome擴(kuò)展頁面
- 選中開發(fā)者模式
- 加載已解壓的擴(kuò)展,選擇shells/chrome
組件間的數(shù)據(jù)交互
-
父組件向子組件傳值
-
組件內(nèi)部通過
props
接收傳遞過來的值Vue.component('menu-item', { props: ['title'], template: '<div>{{title}}</div>' })
-
父組件通過屬性將值傳遞給子組件
<menu-item title="來自父組件傳遞的數(shù)據(jù)"></menu-item> <menu-item :title="title"></menu-item>
-
props
屬性名規(guī)則- 在
props
中使用駝峰形式茂洒,模板中則需要使用短橫線的形式 - 字符串形式的模板中則沒有這個(gè)限制
<menu-item menu-title="hello"></menu-item> <script> Vue.component('menu-item', { // 在JavaScript中是駝峰式的 props: ['menuTitle'], template: `<div>{{menuTitle}}` }) </script>
<div id="app"> <h1>{{name}}</h1> <div>{{pmsg}}</div> <menu-item :menu-title="ptitle" content='hello'></menu-item> </div> <script> Vue.component('third-com', { props:['testTitle'], template:'<div>{{testTitle}}</div>' }); Vue.component('menu-item', { props:['menuTitle'], template:'<div>{{menuTitle}}<third-com testTitle="hello"></third-com></div>' }); let vm = new Vue({ el:'#app', data:{ name:"myVue", pmsg:'父組件的內(nèi)容', ptitle:'動(dòng)態(tài)綁定的屬性' }, methods: { } }); </script>
- 在
-
props
屬性值類型- 字符串 String
- 數(shù)值 Number
- 布爾值 Boolean
- 數(shù)組 Array
- 對(duì)象 Object
<div id="app"> <h1>{{name}}</h1> <div>{{pmsg}}</div> <!-- 不帶引號(hào)為字符串類型 --> <menu-item :pstr="pstr" :pnum="13" :pboo="true" :parr="parr" :pobj="pobj"></menu-item> </div> <script> Vue.component('menu-item', { props: ['pstr','pnum','pboo','parr','pobj'], template:` <div> <div>{{pstr}}</div> <div>{{12 + pnum}}</div> <div>{{pboo}}</div> <ul> <li :key="index" v-for="(item,index) in parr">{{item}}</li> </ul> <div> <span>{{pobj.name}}</span> <span>{{pobj.age}}</span> <span>{{pobj.sex}}</span> </div> </div>` }); let vm = new Vue({ el: '#app', data: { name: "myVue", pmsg: '父組件的內(nèi)容', pstr: 'hello', parr:['蘋果','香蕉','哈密瓜'], pobj:{ name:'張三', age:19, sex:'男' } }, methods: { } }); </script>
-
-
子組件向父組件傳值
子組件通過自定義事件向父組件傳遞消息
<button v-on:click='$emit("enlarge-text")'>擴(kuò)大字體</button>
-
父組件監(jiān)聽子組件事件
<menu-item v-on:enlarge-text='fontSize += 0.1'></menu-item>
<div id="app"> <h1>{{name}}</h1> <div :style="{fontSize: fontSize + 'px'}">{{pmsg}}</div> <menu-item @enlarge-text="handle"></menu-item> </div> <script> /* 子組件向父組件傳遞數(shù)據(jù)-基本用法 props傳遞數(shù)據(jù)原則:單項(xiàng)數(shù)據(jù)綁定 */ Vue.component('menu-item', { template:` <div> <button @click="$emit('enlarge-text')">擴(kuò)大字體</button> </div>` }); let vm = new Vue({ el: '#app', data: { name: "myVue", pmsg: '父組件的內(nèi)容', fontSize: 10 }, methods: { handle:function() { // 擴(kuò)大字體大小 this.fontSize+=10; } } }); </script>
子組件通過自定義事件向父組件傳遞信息
<button v-on:click='$emit("enlarge-text", 0.1)'>擴(kuò)大字體</button>
-
父組件監(jiān)聽子組件事件
<menu-item v-on:enlarge-text='fontSize += $event'></menu-item>
<div id="app"> <h1>{{name}}</h1> <div :style="{fontSize: fontSize + 'px'}">{{pmsg}}</div> <!-- 不帶引號(hào)為字符串類型 --> <menu-item @enlarge-text="handle($event)"></menu-item> </div> <script> /* 子組件向父組件傳遞數(shù)據(jù)-基本用法 props傳遞數(shù)據(jù)原則:單項(xiàng)數(shù)據(jù)綁定 */ Vue.component('menu-item', { template:` <div> <button @click="$emit('enlarge-text',5)">擴(kuò)大字體</button> <button @click="$emit('enlarge-text',-5)">減小字體</button> </div>` }); let vm = new Vue({ el: '#app', data: { name: "myVue", pmsg: '父組件的內(nèi)容', fontSize: 10 }, methods: { handle:function(val) { // 擴(kuò)大字體大小 this.fontSize+=val; } } }); </script>
-
非父子組件間傳值(兄弟間組件傳值)
單獨(dú)的事件中心管理組件間的通信
var eventHub = new Vue()
-
監(jiān)聽事件與銷毀事件
eventHub.$on('add-todo', addTab) eventHub.off('add-todo')
觸發(fā)事件
eventHub.$emit('add-todo', id)
<div id="app"> <h1>{{name}}</h1> <div> <button @click="handle">銷毀事件</button> </div> <text-tom></text-tom> <text-jerry></text-jerry> </div> <script type="text/javascript"> // 兄弟組件間數(shù)據(jù)傳遞 // 提供事件中心 var hub = new Vue(); Vue.component('text-tom', { data: function () { return { num: 0 } }, template: ` <div> <div>Tom:{{num}}</div> <div> <button @click="handle">點(diǎn)擊</button> </div> </div>`, methods: { handle: function () { hub.$emit('jerry-event', 2) } }, mounted: function () { // 監(jiān)聽事件 hub.$on('tom-event', (val) => { this.num += val; }) } }); Vue.component('text-jerry', { data: function () { return { num: 0 } }, template: ` <div> <div>Jerry:{{num}}</div> <div> <button @click="handle">點(diǎn)擊</button> </div> </div>`, methods: { handle: function () { // 觸發(fā)兄弟組件的事件 hub.$emit('tom-event', 1) } }, mounted: function () { // 監(jiān)聽事件 hub.$on('jerry-event', (val) => { this.num += val; }) } }); let vm = new Vue({ el: '#app', data: { name: "myVue" }, methods: { handle: function() { hub.$off('tom-event'); hub.$off('jerry-event'); } } }); </script>
組件插槽
- 父組件向子組件傳遞內(nèi)容
插槽基本用法
-
插槽位置
<div id="app"> <h1>{{name}}</h1> <alert-box>有bug!</alert-box> <alert-box>有一個(gè)警告!</alert-box> <alert-box></alert-box> </div> <script> Vue.component('alert-box', { template: ` <div class="demo-alert-box"> <strong>Error!</strong> <slot></slot> </div>` }) let vm = new Vue({ el: '#app', data: { name: "myVue" }, methods: { } }); </script>
-
具名插槽用法
<!-- 插槽定義 --> <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> <!-- 插槽內(nèi)容 --> <base-layout> <h1 slot="header">標(biāo)題內(nèi)容</h1> <p>主要內(nèi)容1</p> <p>主要內(nèi)容2</p> <p slot="footer">底部內(nèi)容</p> </base-layout>
<div id="app"> <h1>{{name}}</h1> <base-layout> <p slot="header">標(biāo)題信息</p> <p>主要內(nèi)容1</p> <p>主要內(nèi)容2</p> <p slot="footer">底部信息</p> </base-layout> <base-layout> <template slot="header"> <p slot="header">標(biāo)題信息</p> <p slot="header">標(biāo)題信息</p> </template> <p>主要內(nèi)容1</p> <p>主要內(nèi)容2</p> <template slot="footer"> <p slot="header">尾部信息1</p> <p slot="header">尾部信息2</p> </template> </base-layout> </div> <script type="text/javascript"> Vue.component('base-layout', { template: ` <div> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>` }); let vm = new Vue({ el: '#app', data: { name: "myVue" }, methods: { } }); </script>
作用域插槽
-
應(yīng)用場景:父組件對(duì)子組件的內(nèi)容進(jìn)行加工處理
<!-- 插槽定義 --> <ul> <li v-for="item in list" v-bind:key="item.id"> <slot v-bind:item="item"> {{item.name}} </slot> </li> </ul> <!-- 插槽內(nèi)容 --> <fruit-list v-bind:list="list"> <template slot-scope="slotProps"> <strong v-if="slotProps.item.current"> {{slotProps.item.text}} </strong> </template> </fruit-list>