使用組件的原因
提高代碼的復(fù)用性
組件的使用方法
- 全局注冊
Vue.component('my-component',{
template:'<div>我是組件的內(nèi)容</div>'
})
占內(nèi)存
- 局部注冊
var app = new Vue({
el: '#app',
data: {
},
components: {
'app-component': {
template: '<div>app-component</div>'
}
}
})
- 由于HTML標(biāo)簽的限制,如
table
中只能有tr
、td
典唇、tbody
偏化,要想在table
中使用組件就要用到is
,這樣一來毙石,tbody
在文檔中就會(huì)被組件替換掉
<table>
<tbody is="app-component"></tbody>
</table>
我們也可以利用這個(gè)屬性來干掉其他事,比如動(dòng)態(tài)組件,也就是點(diǎn)一個(gè)按鈕就切換一個(gè)組件
組件使用的奇淫巧技
- 必須用連字符命名叠艳,如:my-compoent
- template中的內(nèi)容必須要用DOM元素包裹
// 正確寫法
template: '<div>app-component</div>'
// 錯(cuò)誤寫法
template: 'app-component'
- 組件的定義中,還可以有data易阳,methods附较,computed
- data必須是一個(gè)方法
components: {
'plus-component': {
template: '<button @click="count111++">{{count111}}</button>',
data: function () {
return {
count111: 1
}
}
}
}
使用props傳遞數(shù)據(jù) 父親向兒子傳遞數(shù)據(jù)
- 在子組件上聲明屬性msg,然后在子組件處用props來接收
<div id="app">
我是爸爸
<child-component :msg="fatherMsg"></child-component>
</div>
<script>
var app = new Vue({
el: '#app',
components: {
'child-component': {
// 從父組件和本身data傳入的數(shù)據(jù)在methods潦俺、template中都可以使用
props: ['msg'],
data: function(){
return {
count:1
}
},
template: '<div id="child">{{msg}}</div>',
}
}
})
</script>
- 動(dòng)態(tài)向子組件傳入信息拒课,則用v-model
<div id="app">
我是爸爸
<input type="text" v-model="fatherMsg">
<child-component :msg="fatherMsg"></child-component>
</div>
<script src="../vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
count: 1,
fatherMsg: 'hello'
},
methods: {
plus: function () {
this.count++
}
},
components: {
'child-component': {
// 從父組件和本身data傳入的數(shù)據(jù)在methods、template中都可以使用
props: ['msg'],
data: function(){
return {
count:1
}
},
template: '<div id="child">{{msg}}</div>',
}
}
})
</script>
- ==在props中定義的屬性都可以在組件內(nèi)使用事示,可以在template早像、computed、methods中使用==
單向數(shù)據(jù)流
只能父組件向子組件傳遞信息肖爵,子組件不能向父組件傳遞信息
在組件中使用從props傳來的數(shù)據(jù)可以直接用this.xxx來獲取
'child-component': {
props: ['msg'],
template: '<div id="child" >{{count}}</div>',
data:function(){
// 組件中的data要返回一個(gè)函數(shù)
return {
count: this.msg
}
}
}
- 用v-bind來綁定style屬性的時(shí)候可以使用對象語法卢鹦,注意
<div :style="xxx" id="div1"></div>
computed:{
xxx: function () {
return {
//這是用到了v-bind綁定style的對象語法
width: this.ccc + 'px',
'background-color': 'red',
height: 10 + 'px'
}
}
}
數(shù)據(jù)驗(yàn)證
在HTML中絕對不允許使用駝峰,因?yàn)镠TML會(huì)把大寫全部轉(zhuǎn)化為小寫劝堪。在props中可以用駝峰或短橫線冀自,在template和data揉稚、this.xxx中只能使用駝峰,這是因?yàn)樵趘ue中短橫線會(huì)被誤認(rèn)為減號凡纳,會(huì)報(bào)錯(cuò)窃植。
==總結(jié):在HTML中使用短橫線,在vue中使用駝峰==
- 對傳入的數(shù)據(jù)進(jìn)行數(shù)據(jù)驗(yàn)證
注意props不能再返回一個(gè)數(shù)組荐糜,而是一個(gè)對象
<div id="app">
<child-component :a="a" :b="b" :c="c" :d="d" :e="e" :f="f"></child-component>
</div>
<script src="../vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
a: 'hello',
b: 123,
c: true,
d: 123,
e:[456],
f: 15
},
components: {
'child-component': {
props: {
a: String, // 驗(yàn)證字符串巷怜,如果不是字符串頁面會(huì)照常渲染但會(huì)報(bào)錯(cuò)
b: [String,Number], // 意思是傳入的數(shù)據(jù)是String或是Number類型
c: {
type: Boolean,
default: false // 默認(rèn)值為false
},
d: {
type: Number,
required: true // 表示d是必須要傳入的值
},
e:{
// 如果是數(shù)組或?qū)ο螅J(rèn)值要用函數(shù)來返回
type: Array,
default: function () {
return [789]
}
},
f:{
// 自定義一個(gè)驗(yàn)證函數(shù)
validator: function(value){
return value>10
}
}
},
template: '<div id="child" >{{a}}--{暴氏}--{{c}}--{7llww81}--{{e}}--{{f}}</div>',
data:function(){
// 組件中的data要返回一個(gè)函數(shù)
return {
count: this.msg
}
}
}
}
})
</script>
組件之間的通信
子組件給父組件傳遞信息
實(shí)現(xiàn)一個(gè)功能延塑,點(diǎn)擊子組件的按鈕,改變父組件的數(shù)據(jù)
<div id="app">
我的賬戶余額為:{{count}}
<child-component @xxx="changeCount"></child-component>
</div>
<script src="../vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
count: 2000
},
methods: {
changeCount: function (value) {
this.count = value
}
},
components: {
'child-component': {
// 注意這里template一定要有DOM元素包裹
template: `<div>
<button @click="handleIncrease">+1000</button>
<button @click="handleReduce">-1000</button>
</div>
`,
data:function(){
return {
count: 2000
}
},
methods: {
handleIncrease: function () {
this.count += 1000 // 這里的this.count是組件里面的count
this.$emit('xxx',this.count) // emit表示向父組件通信,第一個(gè)參數(shù)是自定義事件的名稱,后面是要傳入的值,可以寫無限個(gè)
},
handleReduce: function () {
this.count -= 1000
this.$emit('xxx',this.count)
}
}
}
}
})
</script>
子組件向父組件傳遞信息的步驟:
- 在父組件里寫入自定義事件名答渔,事件名后面跟著的是要執(zhí)行的方法
- 子組件通過$emit向父組件傳遞信息关带,第一個(gè)參數(shù)是自定義的事件名,后面是要傳遞的參數(shù)沼撕,可以接無限個(gè)
在組件中使用v-model
v-model其實(shí)也是一個(gè)語法糖:
- 它等于先用v-bind綁定一個(gè)值
- 監(jiān)聽v-on了一個(gè)input事件
上述代碼又可以簡化成
<div id="app">
我的賬戶余額為:{{total}}
<child-component v-model="total"></child-component>
</div>
<script src="../vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
total: 2000
},
components: {
'child-component': {
template: `<div>
<button @click="handleIncrease">+1000</button>
<button @click="handleReduce">-1000</button>
</div>
`,
data:function(){
return {
count: 2000
}
},
methods: {
handleIncrease: function () {
this.count += 1000 // 這里的this.count是組件里面的count
this.$emit('input',this.count) // emit表示向父組件通信,第一個(gè)參數(shù)是自定義事件的名稱,后面是要傳入的值,可以寫無限個(gè)
},
handleReduce: function () {
this.count -= 1000
this.$emit('input',this.count)
}
}
}
}
})
</script>
非父組件之間的通信
非父組件之間的通信需要一個(gè)bus作為中介
在父組件的data內(nèi)新建一個(gè)bus: new Vue()
對象宋雏。
然后在A組件內(nèi)用this.$parent.bus.$emit('事件名',參數(shù))
Vue.component('a-component',{
template: `
<div>
<input type="text" v-model="text">
</div>`,
data:function () {
return {
text: '我是A組件'
}
},
watch:{
//watch的用法,key代表要監(jiān)聽的數(shù)據(jù)务豺,后面接操作
text: function () {
this.$root.bus.$emit('xxx',this.text)
}
}
})
在B組件內(nèi),在對應(yīng)的鉤子事件中用this.$parent.bus.$on('事件名',參數(shù))
Vue.component('b-component',{
template: '<div>我是b組件---{{textb}}</div>',
data:function () {
return {
textb: 'bbbbb'
}
},
created: function () {
var _this = this
this.$root.bus.$on('xxx',function (value) {
// alert('created')
_this.textb = value
})
}
})
- 修改父組件的數(shù)據(jù)磨总,父鏈
this.$parent.xxxx
- 修改兒子組件的數(shù)據(jù),子鏈
在每個(gè)兒子組件上加上ref屬性
<a-component ref="a"></a-component>
<b-component ref="b"></b-component>
<c-component ref="c"></c-component>
然后在父組件上使用:
this.$refs.a.count = 'aaa' // 修改a組件的數(shù)據(jù)
使用slot分發(fā)內(nèi)容
編譯的作用域
<div id="app">
<child-component v-show="bool">
{{message}}
</child-component>
</div>
message屬于父組件的作用域
父組件模板內(nèi)的內(nèi)容在父組件內(nèi)編譯
子組件模板內(nèi)的內(nèi)容在子組件內(nèi)編譯
slot(插槽)的用法和作用
在下面這段代碼中
<child-component v-show="bool">
{{message}}
</child-component>
message其實(shí)是渲染不出來的笼沥,盡管message的作用域在父組件蚪燕,但我們想讓它子組件內(nèi)的template中渲染出來,這時(shí)我們就要使用到了slot功能奔浅。
slot的作用是混合父組件的內(nèi)容和子組件的模板馆纳,從而彌補(bǔ)視圖的不足
<div id="app">
<child-component >
<p>hello world</p>
</child-component>
</div>
......
Vue.component('child-component',{
template: `
<div style="border: 1px solid red;">
<slot>
如果父組件沒有內(nèi)容,我就是子組件的默認(rèn)內(nèi)容
</slot>
</div>
具名插槽
在要插入數(shù)據(jù)的標(biāo)簽使用slot屬性汹桦,在子組件的template處使用slot標(biāo)簽鲁驶,并且寫上對應(yīng)的name
<child-component >
<h1 slot="header">我是標(biāo)題</h1>
<p>hello world</p>
</child-component>
... ...
Vue.component('child-component',{
template: `
<div style="border: 1px solid red;">
<div style="color: red;">
<slot name="header">
這里是header的默認(rèn)內(nèi)容
</slot>
</div>
<slot>
如果父組件沒有內(nèi)容,我就是子組件的默認(rèn)內(nèi)容
</slot>
</div>
`,
作用域插槽
作用域插槽是一個(gè)特殊的插槽舞骆,可以從子組件的插槽中獲取數(shù)據(jù)灵嫌。使用一個(gè)可以復(fù)用的模板來替換已經(jīng)渲染的元素
用法:先在子組件的slot標(biāo)簽上name屬性和自定義的屬性
Vue.component('child-component',{
template: `
<div style="border: 1px solid red;">
<div style="color: red;">
<slot name="header" text="我是子組件的數(shù)據(jù)">
這里是header的默認(rèn)內(nèi)容
</slot>
</div>
</div>
`,
然后在父組件上,用slot對應(yīng)其中的name葛作,用slot-scope對應(yīng)的自定義名字來獲取從子組件傳來的數(shù)據(jù)
<child-component >
<template slot="header" slot-scope="props">
{{props.text}}
</template>
</child-component>
現(xiàn)在已經(jīng)可以不用template寿羞,可以直接使用標(biāo)簽如<p>
在子組件中訪問自己的slot
通過this.$slots.(NAME)
來訪問
<div id="app">
<child-component >
<h1 slot="header">我是父組件的內(nèi)容</h1>
</child-component>
</div>
Vue.component('child-component',{
template: `
<div style="border: 1px solid red;">
<div style="color: red;">
<slot name="header">
這里是header的默認(rèn)內(nèi)容
</slot>
</div>
</div>
`,
data:function () {
return {
message: '我是子組件的內(nèi)容',
bool: true
}
},
mounted:function () {
var header = this.$slots.header
console.log(header)
console.log(header[0].elm.innerText)
}
})
組件的高級用法-動(dòng)態(tài)組件
所謂的動(dòng)態(tài)組件就是通過is屬性來動(dòng)態(tài)切換組件
<div id="app">
<component-a :is="thisView"></component-a>
<button @click="changeToA">第一句</button>
<button @click="changeToB">第二句</button>
<button @click="changeToC">第三句</button>
<button @click="changeToD">第四句</button>
</div>
<script src="../vue.js"></script>
<script>
Vue.component('componentA',{
template: `<div>離離原上草</div>`
})
Vue.component('componentB',{
template: `<div>一歲一枯榮</div>`
})
Vue.component('componentC',{
template: `<div>野火燒不盡</div>`
})
Vue.component('componentD',{
template: `<div>春風(fēng)吹又生</div>`
})
var app = new Vue({
el: '#app',
data: {
thisView: 'componentA'
},
methods :{
changeToA: function () {
this.thisView = 'componentA'
},
changeToB: function () {
this.thisView = 'componentB'
},
changeToC: function () {
this.thisView = 'componentC'
},
changeToD: function () {
this.thisView = 'componentD'
}
}
})