核心目標(biāo)
為了可重用性高昼激,減少重復(fù)性開發(fā),我們可以按照template抹恳、style员凝、script的拆分方式,放置到對應(yīng)的.vue文件中奋献。
組件概括
vue組件可以理解為預(yù)先定義好的ViewModel類健霹。一個組件可以預(yù)定義很多選項,最核心的有:
- 模板template:模板反映了數(shù)據(jù)和最終展現(xiàn)給用戶的DOM之間的映射關(guān)系瓶蚂,
- 初始數(shù)據(jù)data:一個組件的初始數(shù)據(jù)狀態(tài)糖埋,對于可重復(fù)的組件來說,通常是私有的狀態(tài)窃这。
- 接收的外部的參數(shù)(props):組件之間通過參數(shù)來進行數(shù)據(jù)的傳遞和共享瞳别,參數(shù)默認是單項綁定,但也可以顯示聲明為雙向綁定杭攻。
- 方法(methods):對數(shù)據(jù)的改動操作一般都在組件內(nèi)進行祟敛。可以通過v-on指令將用戶輸入事件和組件方法進行綁定兆解。
- 生命周期函數(shù)(鉤子函數(shù)):一個組件會觸發(fā)多個生命周期函數(shù)馆铁,在這些鉤子函數(shù)中可以封裝一些自定義邏輯』驹祝可以理解為controller的邏輯被分散到了這些鉤子函數(shù)中叼架。
注冊組件
注冊組件就是利用Vue.component()方法,先傳入一個自定義組件的名字衣撬,然后傳入這個組件的配置乖订。
(組件名不要帶有大寫字母,多個單詞使用中劃線my-dom)
-
全局組件
(直接使用Vue.component()創(chuàng)建的組件具练,所有的Vue實例都可以使用乍构。)
(一般寫插件的時候全局組件使用多一些)
Vue.component('mycomponent',{ //自定義組件名mycomponent
template: `<div>這是一個自定義組件</div>`,
data () {
return {
message: 'hello world'
}
}
})
-
局部注冊組件
使用三部曲1.創(chuàng)建這個組件;2.注冊這個組件;3.使用這個組件哥遮;
<div id="app">
<mycomponent></mycomponent> //3.組件的使用
<my-component></my-component> //3.組件的使用
</div>
<script>
//1.創(chuàng)建這個組件
let mycomponent={
template: `<div>這是一個局部的自定義組件岂丘,只能在當(dāng)前Vue實例中使用{{aa}}</div>`,
data(){
return {'aa':'hello'}
}
};
let app = new Vue({
el: '#app',
data: {
},
components: {
mycomponent,//2.注冊這個組件
}
}
})
</script>
- 模板的要求:組件的模板只能有一個根元素眠饮。
template: `<div>
元素1.....
元素2.....
元素3.....
</div>`,
- 組件中的data必須是函數(shù)奥帘。
data:function(){
return {'aaa':'bbb'}//template中可以使用aaa
},
- 組件的屬性props。
Vue組件通過props屬性來聲明一個自己的屬性仪召,然后父組件就可以往里面?zhèn)鬟f數(shù)據(jù)寨蹋。
<div id="app1">
動態(tài)操作屬性:name是變量(讀取實例中data的值)
<hello :n="name"></hello>
</div>
<div id="app2">
靜態(tài)的屬性:name是常量(就是name)
<hello n="name"></hello>
</div>
<script>
Vue.component('hello',{
props:['n'],//通過父組件傳過來的數(shù)據(jù) name變量
data:function(){
return {'aaa':'bbb'}
},
template:'<p>{{aaa}} {{n}}</p>'
})
var app1=new Vue({
el:'#app1',
data:{
name:'haha'
}
})
var app2=new Vue({
el:'#app2',
data:{
name:'haha'
}
})
</script>
渲染結(jié)果
props.png
- props的驗證。
組件之間的通信
子組件給父組件傳遞數(shù)據(jù)扔茅,利用事件的訂閱發(fā)布模式
- 1.給子組件的template上的元素綁定事件(如click)已旧,執(zhí)行子組件的方法(如changeData),子組件的方法中發(fā)射一個事件(如s)召娜,傳一個數(shù)據(jù)(如lalala)运褪;
- 2.父組件中,定義一個方法(如getData)用來拿到子組件的數(shù)據(jù)玖瘸。
- 3.在自定義的組件上綁定子組件傳過去的事件(s)秸讹,執(zhí)行事件(s)執(zhí)行的是getData函數(shù),getData函數(shù)中拿到數(shù)據(jù)(data店读,就是子組件傳過去的lalala)嗦枢。
<div id="app">
<parent></parent>
</div>
<template id="parent">
<div>
<p>父組件{{msg}}</p>//點擊子組件觸發(fā)getData獲取到子組件轉(zhuǎn)來的msg數(shù)據(jù)攀芯,綁定到父組件上
<children @s="getData"></children>
</div>
</template>
<script>
var app=new Vue({
el:'#app',
components:{
parent:{
template:'#parent',
data(){
return {msg:'aaa'};
},
methods:{
getData(data){
alert(data);//子組件傳過來的數(shù)據(jù)
this.msg=data;
}
},
components:{
children:{
template:'<p @click="changeData">子組件</p>',
methods:{
changeData(){
this.$emit('s','lalala');//傳遞給父組件
}
}
}
}
}
}
})
</script>
父組件給子組件傳遞數(shù)據(jù)(利用props屬性)
<div id="app">
<parent></parent>
</div>
<script>
var app=new Vue({
el:'#app',
components:{//一個父組件里邊可以包含多個子組件
parent:{
template:'<h1 >{{msg}},父組件<children :n="msg"></children></h1>',
data:function(){//父組件的數(shù)據(jù) 傳給子組件
return {msg:'hello'}
},
components:{
children:{
props:['n'],//根據(jù)props拿到父組件中寫的動態(tài)屬性拿到數(shù)據(jù)
template:'<h2>{{n}},子組件</h2>',
}
}
}
}
})
兄弟組件之間傳遞數(shù)據(jù) (事件車---原理也是事件的訂閱發(fā)布模式)
注意:
- 每一個vue的實例都是獨立的屯断;相互之間不能直接進行改變數(shù)據(jù);
- 給兩個不同的組件找一個載體侣诺;把共同的方法放在這個載體上殖演;
- 這個載體就是 let eventBus = new Vue; // 創(chuàng)建一個新的vue實例;
- 在這個新的實例上年鸳,有 $on: 訂閱 $emit: 發(fā)布;
- $on的綁定要基于鉤子函數(shù)趴久,一般放在created或者mounted上
<div id="app">
<tmp1></tmp1>
<tmp2></tmp2>
</div>
<script>
var eventBus=new Vue();
var app = new Vue({
el: '#app',
data: {},
components: {
tmp1: {
template: "<h1>組件1{{msg}}</h1>",
data(){
return {msg:""}
},
mounted(){//鉤子函數(shù),頁面一加載進來的時候就已經(jīng)綁定好了
eventBus.$on('aaa',(data)=>{
this.msg=data;
})
}
},
tmp2: {
template: "<h1 @click='sendData'>組件2{{msg}}</h1>",
data(){
return {msg: 'hello'}
},
methods:{
sendData(){
//發(fā)布數(shù)據(jù)
eventBus.$emit('aaa',this.msg)
}
}
}
}
})
</script>
數(shù)據(jù)同步(子組件的數(shù)據(jù)和父組件保持一致)
數(shù)據(jù)同步的核心:父組件給子組件傳遞“引用數(shù)據(jù)類型的數(shù)據(jù)”搔确;
<div id="app">
<parent></parent>
</div>
<template id="parent">
<div>
<h1>父組件 <mark>{{msg.name}}</mark></h1>
<children :n="msg"></children>
</div>
</template>
<template id="children">
<h2 @click="changeData">子組件 {{n.name}}</h2>
</template>
<script>
//數(shù)據(jù)同步的核心:父組件給子組件傳遞“引用數(shù)據(jù)類型的數(shù)據(jù)”彼棍;
var app=new Vue({
el:'#app',
components:{
parent:{
template:'#parent',
data(){
return {msg:{name:'hahha'}}
},
components:{
children:{
props:['n'],
template:'#children',
methods:{
changeData(){
this.n.name='lallala'
},
}
}
}
}
}
})
</script>
數(shù)據(jù)不同步(不直接使用父組件傳的值,用data屬性再自己的組件內(nèi)做一個中間變量膳算,防止報錯)
<parent></parent>
</div>
<template id="parent">
<div>
<h1>父組件 <mark>{{msg}}</mark></h1>
<children :n="msg"></children>
</div>
</template>
<script>
//數(shù)據(jù)不同步的核心:中間變量接收避免報錯座硕;
var app=new Vue({
el:'#app',
components:{
parent:{
template:'#parent',
data(){
return {msg:'hahha'}
},
components:{
children:{
props:['n'],
template:'<h2 @click="changeData">子組件 {}</h2>',
data(){
return {b:this.n}
},
methods:{
changeData(){
this.b='lallala'
},
}
}
}
}
}
})
</script>
組件切換
js動態(tài)控制template(也可以用is屬性控制)
<div id="app">
<div class="container">
<div @click="comp='zujian1'">顯示組件1</div>
<div @click="comp='zujian2'">顯示組件2</div>
</div>
<!--aaa標(biāo)簽是核心涕蜂,必須得寫华匾,通過is決定顯示那個組件-->
<aaa :is="comp"></aaa>
</div>
<script>
var app=new Vue({
el:'#app',
data:{
comp:'zujian2',
},
components:{
zujian1:{
template:'<h1>組件1</h1>'
},
zujian2:{
template:'<h1>組件2</h1>'
}
}
})
</script>
插槽(slot官網(wǎng)有詳細介紹)
slot相當(dāng)于子組件設(shè)置了一個地方,如果在調(diào)用它的時候机隙,往它的開閉標(biāo)簽之間放了東西蜘拉,那么它就把這些東西放到slot中萨西。
- 當(dāng)子組件中沒有slot時,父組件放在子組件標(biāo)簽內(nèi)的東西將被丟棄旭旭;
- 子組件的slot標(biāo)簽內(nèi)可以放置內(nèi)容谎脯,當(dāng)父組件沒有放置內(nèi)容在子組件標(biāo)簽內(nèi)時,slot中的內(nèi)容會渲染出來持寄;
- 當(dāng)父組件在子組件標(biāo)簽內(nèi)放置了內(nèi)容時穿肄,slot中的內(nèi)容被丟棄
實例:
<div id="app">
<hello>//使用組件
lalalala
<!--給插槽起好名字-->
<div slot="div1">1111111111111</div>
<div slot="div2">2222222222222</div>
</hello>
</div>
<template id="temp1">//模板
<h1>
hello
<!--無名插槽-->
<slot></slot>
<!--有名插槽 可以根據(jù)插槽切換順序-->
<slot name="div2"></slot>
<slot name="div1"></slot>
</h1>
</template>
<script>
var app=new Vue({
el:'#app',
data:{
},
components:{
hello:{
template:"#temp1"
}
}
})
組件文件示例
父組件.vue
<template>
<div class="">
<div class="home-container">
<Banner></Banner>
<quick-link :allAmount="allAmount"> </quick-link>
<Recommended></Recommended>
</div>
<m-footer></m-footer>
</div>
</template>
<script>
import axios from 'axios'
import MFooter from '../footer.vue'
import Banner from './banner.vue'
import QuickLink from './quickLink.vue'
import Recommended from './recommended.vue'
import {setSession} from '../../common/userCenter'
import {loadAppHomeAct,loadStatisticalData} from '../../api/api'
export default {
data(){
return{
allAmount:[]
}
},
components:{
MFooter,
Banner,
QuickLink,
Recommended
},
created(){
this.fetchCookies();
},
methods:{
getQueryString: function (name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var url=decodeURIComponent(window.location.search);
var r = url.substr(1).match(reg);
if (r != null) return (r[2]);
return "";
}
}
}
</script>
<style>
@import "home.css";
</style>