Vue 學(xué)習(xí)筆記入門篇 可復(fù)用性的組件
7.1 使用組件的原因
作用:提高代碼的復(fù)用性
7.2 組件的使用方法
- 全局注冊(cè)
Vue.component('my-component',{
template:'<div>我是組件的內(nèi)容</div>'
})
優(yōu)點(diǎn):所有的vue實(shí)例都可以用
缺點(diǎn):權(quán)限太大嘿棘,容錯(cuò)率降低
- 局部注冊(cè)
var app = new Vue({
el:'#app',
components:{
'my-component':{
template: '<div>我是組件的內(nèi)容</div>'
}
}
})
- vue組件的模板在某些情況下會(huì)受到html標(biāo)簽的限制吼和,比如
<table>
中只能還有<tr> , <td>
這些元素蛹磺,所以直接在table中使用組件是無(wú)效的甘磨,此時(shí)可以使用is屬性來掛載組件
<table>
<tbody is="my-component"></tbody>
</table>
Demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<my-component></my-component>
<my-component2></my-component2>
<table>
<tbody is="my-component"></tbody>
</table>
</div>
<hr>
<div id="app2">
<my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('my-component', {
template: '<div>我是組件的內(nèi)容</div>'
})
var app = new Vue({
el: '#app',
components: {
'my-component2': {
template: '<div>我是局部注冊(cè)組件的內(nèi)容</div>'
}
}
})
var app2 = new Vue({
el:'#app2',
data:{}
})
</script>
</body>
</html>
7.3 組件使用的規(guī)則
- 推薦使用小寫字母加--進(jìn)行命名(必須) child, my--componnet命名組件
- template中的內(nèi)容必須被一個(gè)DOM元素包裹 ,也可以嵌套
- 在組件的定義中梯找,除了template之外的其他選項(xiàng)---data,computed,methods
- data必須是一個(gè)方法
7.3 Demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="app">
<my-component></my-component>
//點(diǎn)擊任何一個(gè)會(huì)同時(shí)增加
<button @click="plus">{{count}}</button>
<button @click="plus">{{count}}</button>
<hr>
//不會(huì)同時(shí)增加
<btn-component></btn-component>
<btn-component></btn-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
count: 1
},
components: {
'my-component': {
template: '<div>我是組件的內(nèi)容</div>'
},
'my-component2': {
template: '<div>我是局部注冊(cè)組件的內(nèi)容</div>'
},
'btn-component': {
template: '<button @click="count++">{{count}}</button>',
data: function() {
return {
count: 0
}
}
}
},
methods: {
plus: function() {
this.count++;
}
}
})
</script>
</body>
</html>
7.4 使用props傳遞數(shù)據(jù) 父親向兒子傳遞數(shù)據(jù)
- 在組件中使用props來從父親組件接收參數(shù)罗标,注意显沈,在props中定義的屬性,都可以在組件中直接使用
- props來自父級(jí)志电,而組件中data return的數(shù)據(jù)就是組件自己的數(shù)據(jù)曙咽,兩種情況作用域就是組件本身,可以在template挑辆,computed例朱,methods中直接使用.
- props的值有兩種,一種是字符串?dāng)?shù)組之拨,一種是對(duì)象.
- 可以使用v--bind動(dòng)態(tài)綁定父組件來的內(nèi)容
7.4 Demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
在父組件向子組件傳遞消息
<div id="app">
<h5 style="text-align: center;">我是父組件</h5>
<child-component msg="我是來自父組件的內(nèi)容"></child-component>
<child-component msg="[3,6,9]"></child-component> <!-- msg.length=7 -->
<child-component :msg="[3,6,9]"></child-component><!-- msg.length=3 -->
<hr>使用v-bind進(jìn)行數(shù)據(jù)的動(dòng)態(tài)綁定
<input type="text" v-model="parrentmsg">
<bind-component v-bind:msg="parrentmsg"></bind-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el:'#app',
data:{
parrentmsg:'111'
} ,
components:{
'child-component':{
props:['msg'],
template:'<div>{{msg}}</div>'
},
'bind-component':{
props:['msg'],
template:'<div>{{msg}}</div>',
data:function(){
return {
count: 1
}
}
}
}
})
</script>
</body>
</html>
7.5 單向數(shù)據(jù)流
-
解釋
: 通過props 傳遞數(shù)據(jù)
是單向的了茉继, 也就是父組件數(shù)據(jù)變化時(shí)會(huì)傳遞給子組件,但是反過來不行蚀乔。 -
目的
:是盡可能將父子組件解稿烁竭,避免子組件無(wú)意中修改了父組件的狀態(tài)。 -
應(yīng)用場(chǎng)景
: 業(yè)務(wù)中會(huì)經(jīng)常遇到兩種需要改變 props 的情況
一種是父組件傳遞初始值進(jìn)來吉挣,子組件將它作為初始值保存起來派撕,在自己的作用域下可以隨意使用和修改。這種情況可以在組件 data 內(nèi)再聲明一個(gè)數(shù)據(jù)睬魂,引用父組件的 props
步驟一:注冊(cè)組件
步驟二:將父組件的數(shù)據(jù)傳遞進(jìn)來终吼,并在子組件中用props接收
步驟三:將傳遞進(jìn)來的數(shù)據(jù)通過初始值保存起來
<div id="app">
<my-comp init-count=“666”></my-comp>
</div>
<script>
var app = new Vue({
el: '#app' ,
components: {‘
my - comp’: {
props: [‘init - count’],
template: '< div > {
{
init - count
}
} < /div>',
data: function() {
return {
count: this.initCount
}
}
}
}
})
</script>
另一種情況就是 prop 作為需要被轉(zhuǎn)變的原始值傳入。這種情況用計(jì)算屬性就可以了
步驟一:注冊(cè)組件
步驟二:將父組件的數(shù)據(jù)傳遞進(jìn)來氯哮,并在子組件中用props接收
步驟三:將傳遞進(jìn)來的數(shù)據(jù)通過計(jì)算屬性進(jìn)行重新計(jì)算
<body>
<div id="data">
<input type="text" v-model="width">
<my-conponent :width="width"></my-conponent>
</div>
<script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el:'#data',
data:{
width:''
},
components:{
'my-conponent':{
props:['width'],
template:'<div :style="style"></div>',
computed:{
style:function(){
return{
width:this.width+'px',
background:'red',
height:'30px'
}
}
}
}
}
})
</script>
</body>
7.6 數(shù)據(jù)驗(yàn)證
@ vue組件中camelCased (駝峰式) 命名與 kebab-case(短橫線命名)
@ 在html中,
myMessage和 mymessage
是一致的,,因此在組件中的html中使用必須使用kebab--case(短橫線)命名方式际跪。在html中不允許使用駝峰!!D反颉A寄贰!幔戏!@在組件中, 父組件給子組件傳遞數(shù)據(jù)必須用短橫線玛追。在template中,必須使用駝峰命名方式闲延,若為短橫線的命名方式痊剖。則會(huì)直接保錯(cuò)。
@ 在組件的data中,用this.XXX引用時(shí),只能是駝峰命名方式垒玲。若為短橫線的命名方式陆馁,則會(huì)報(bào)錯(cuò)。
驗(yàn)證的 type 類型可以是:
- String
- Number
- Boolean
- Object
- Array
- Function
Vue.component ( ’ my-compopent ’合愈, {
props : {
//必須是數(shù)字類型
propA : Number ,
//必須是字符串或數(shù)字類型
propB : [String , Number] ,
//布爾值氮惯,如果沒有定義,默認(rèn)值就是 true
propC: {
type : Boolean ,
default : true
},
//數(shù)字想暗,而且是必傳
propD: {
type: Number ,
required : true
},
//如果是數(shù)組或?qū)ο蟾竞梗J(rèn)值必須是一個(gè)函數(shù)來返回
propE: {
type : Array ,
default : function () {
return [] ;
}
},
//自定義一個(gè)驗(yàn)證函數(shù)
propF: {
validator : function (value) {
return value > 10;
}
}
}
});
7.7 組件通信
組件關(guān)系可分為父子組件通信、兄弟組件通信说莫、跨級(jí)組件通信
7.7.1 自定義事件—子組件給父組件傳遞數(shù)據(jù)
使用v--on 除了監(jiān)昕 DOM 事件外杨箭,還可以用于組件之間的自定義事件。
JavaScript 的設(shè)計(jì)模式 一一觀察者模式储狭, dispatchEvent
和addEventListener
這兩個(gè)方法互婿。 Vue 組件也有與之類似的一套模式,子組件用$emit()
來 觸發(fā)事件 辽狈,父組件用$on()
來 監(jiān)聽子組件的事件慈参。
直接來代碼
- 第一步:自定義事件
- 第二步: 在子組件中用$emit觸發(fā)事件,第一個(gè)參數(shù)是事件名刮萌,后邊的參數(shù)是要傳遞的數(shù)據(jù)
- 第三步:在自定義事件中用一個(gè)參數(shù)來接受
<body>
<div id="app">
<p>您好,您現(xiàn)在的銀行余額是{{total}}元</p>
<btn-compnent @change="handleTotal"></btn-compnent>
<!-- <button-component @change="money"></button-component> -->
</div>
<script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
total: 0
},
components: {
'btn-compnent': {
template: '<div>\
<button @click="handleincrease">+10000</button> \
<button @click="handlereduce">-10000</button>\
</div>',
data: function () {
return {
count: 0
}
},
methods: {
handleincrease: function () {
this.count = this.count + 10000;
this.$emit('change', this.count);
},
handlereduce: function () {
this.count = this.count - 10000;
this.$emit('change', this.count);
}
}
}
},
methods: {
handleTotal: function (total) {
this.total = total;
}
}
})
</script>
</body>
7.7.2 在組件中使用v--model
$emit
的代碼,這行代碼實(shí)際上會(huì)觸發(fā)一個(gè) input事件, ‘input’
后的參數(shù)就是傳遞給v--model綁定的屬性的值
v--model 其實(shí)是一個(gè)語(yǔ)法糖驮配,這背后其實(shí)做了兩個(gè)操作:
- v--bind 綁定一個(gè) value 屬性
- v--on 指令給當(dāng)前元素綁定 input 事件
要使用v--model,要做到:
- 接收一個(gè) value 屬性。
- 在有新的 value 時(shí)觸發(fā) input 事件
<body>
<div id="app">
<p>您好,您現(xiàn)在的銀行余額是{{total}}元</p>
<btn-compnent v-model="total"></btn-compnent>
</div>
<script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
//關(guān)于
var app = new Vue({
el: '#app',
data: {
total: 0
},
components: {
'btn-compnent': {
template: '<div>\
<button @click="handleincrease">+1</button> \
<button @click="handlereduce">-1</button>\
</div>',
data: function () {
return {
count: 0
}
},
methods: {
handleincrease: function () {
this.count++;
this.$emit('input', this.count);
},
handlereduce: function () {
if(this.count>0){
this.count--;
}else{
this.count = 0;
}
this.$emit('input', this.count);
}
}
}
},
methods: {
/* handleTotal:function (total) {
this.total = total;
}*/
}
})
</script>
</body>
7.7.3 非父組件之間的通信
官網(wǎng)描述:
[圖片上傳失敗...(image-7120bf-1563501977307)]
圖形實(shí)例:
[圖片上傳失敗...(image-60bec7-1563501977307)]
<div id="app">
<my-acomponent ref="a"></my-acomponent>
<my-bcomponent ref="b"></my-bcomponent>
<hr>
<child-component ref="c"></child-component>---{{msg}}
<br>
<button @click="getChildData">我是父組件的按鈕</button>
---{{fromchild}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js">
</script>
<script>
Vue.component('my-acomponent', {
template: '<div><button @click="handle">點(diǎn)擊我向B組件傳遞數(shù)據(jù)</button></div>',
data: function () {
return {
aaa: '我是來自A組件的內(nèi)容'
}
},
methods: {
handle: function () {
this.$root.bus.$emit('lala', this.aaa);
}
}
})
Vue.component('my-bcomponent', {
template: '<div></div>',
created: function () {
//A組件在實(shí)例創(chuàng)建的時(shí)候就監(jiān)聽事件---lala事件
this.$root.bus.$on('lala', function (value) {
alert(value)
});
}
})
</script>
父鏈:this.$parent
Vue.component('child-component', {
template: '<button @click="setFatherData">通過點(diǎn)擊我修改父親的數(shù)據(jù)</button>',
methods: {
setFatherData: function () {
this.$parent.msg = '數(shù)據(jù)已經(jīng)修改了'
}
}
})
子鏈:this.$refs
提供了為子組件提供索引的方法着茸,用特殊的屬性ref為其增加一個(gè)索引
var app = new Vue({
el: '#app',
data: {
//bus中介
bus: new Vue(),
msg: '數(shù)據(jù)還未修改',
formchild: '還未拿到'
},
methods: {
getChildData: function () {
//用來拿子組件中的內(nèi)容 ---- $refs
this.formchild = this.$refs.c.msg;
}
}
})
7.8使用slot分發(fā)內(nèi)容
7.8.1 什么是slot(插槽)
為了讓組件可以組合壮锻,我們需要一種方式來混合父組件的內(nèi)容與子組件自己的模板。這個(gè)過程被稱為 內(nèi)容分發(fā).Vue.js 實(shí)現(xiàn)了一個(gè)內(nèi)容分發(fā) API涮阔,使用特殊的 ‘slot’ 元素作為原始內(nèi)容的插槽猜绣。
7.8.2 編譯的作用域
在深入內(nèi)容分發(fā) API 之前,我們先明確內(nèi)容在哪個(gè)作用域里編譯敬特。假定模板為:
<child-component>
{{ message }}
</child-component>
message 應(yīng)該綁定到父組件的數(shù)據(jù)掰邢,還是綁定到子組件的數(shù)據(jù)牺陶?答案是父組件。組件作用域簡(jiǎn)單地說是:
- 父組件模板的內(nèi)容在父組件作用域內(nèi)編譯
- 子組件模板的內(nèi)容在子組件作用域內(nèi)編譯
7.8.3 插槽的用法
- 父組件的內(nèi)容與子組件相混合辣之,從而彌補(bǔ)了視圖的不足
- 混合父組件的內(nèi)容與子組件自己的模板
單個(gè)插槽:
<div id="app">
<my-component>
<p>我是父組件的內(nèi)容</p>
</my-component>
</div>
Vue.component('my-component',{ template:'
<div>\
<slot>\ 如果父組件沒有插入內(nèi)容义图,我就作為默認(rèn)出現(xiàn)\
</slot>\
</div>' })
具名插槽:
<div id="app">
<my-component>
<p>我是父組件的內(nèi)容</p>
</my-component>
<hr>
具名插槽
<name-component>
<h3 slot="header">我是標(biāo)題</h3>
<p>我是正文內(nèi)容</p>
<p>正文內(nèi)容有兩段</p>
<p slot="footer">我是底部信息</p>
</name-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('my-component', {
template: '<div>\
<slot>\ 如果父組件沒有插入內(nèi)容,我就作為默認(rèn)出現(xiàn)\
</slot>\
</div>'
})
Vue.component('name-component',{ template:'<div>\
<div class="header">\n' +
'<slot name="header">\n' + ' \n' + ' </slot>\n' +
'</div>\n' +
'<div class="contatiner">\n' +
'<slot>\n' + ' \n' + ' </slot>\n' +
'</div>\n' +
'<div class="footer">\n' +
'<slot name="footer">\n' + '\n' + ' </slot> \n' +
'</div>'+ '</div>' })
var app = new Vue({
el: '#app',
data: {},
components: {
}
})
</script>
7.8.4 作用域插槽
作用域插槽是一種特殊的slot召烂,使用一個(gè)可以復(fù)用的模板來替換已經(jīng)渲染的元素——從子組件獲取數(shù)據(jù)
--template模板是不會(huì)被渲染的
<div id="app">
<my-component>
<template slot="abc" slot-scope="props">
{{props.text}}
{{props.ss}}
</template>
</my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('my-component',{
template:'<div>\
<slot text="我是來自子組件的數(shù)據(jù)" ss="aaa" name="abc">\
</slot>\
</div>'
})
var app = new Vue({
el: '#app',
data: {}
})
</script>
7.8.5 訪問slot
通過this.$slots.(NAME)
mounted:function () {
//訪問插槽
var header = this.$slots.header;
var text = header[0].elm.innerText;
var html = header[0].elm.innerHTML;
console.log(header)
console.log(text)
console.log(html)
}
7.9 組件高級(jí)用法–動(dòng)態(tài)組件
VUE給我們提供 了一個(gè)元素叫component
- 作用是: 用來動(dòng)態(tài)的掛載不同的組件
- 實(shí)現(xiàn):使用is特性來進(jìn)行實(shí)現(xiàn)的
<div id="app">
<component :is="thisShow"></component>
<button @click="msg('a')">第一句</button>
<button @click="msg('b')">第二句</button>
<button @click="msg('c')">第三句</button>
<button @click="msg('d')">第四句</button>
</div>
<script src="http://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
Vue.component('msga', {
template: '<div>鋤禾日當(dāng)午</div>',
data: function() {
return {}
}
})
Vue.component('msgb', {
template: '<div>汗滴禾下土</div>',
data: function() {
return {}
}
})
Vue.component('msgc', {
template: '<div>誰(shuí)知盤中餐</div>',
data: function() {
return {}
}
})
Vue.component('msgd', {
template: '<div>粒粒堅(jiān)辛苦</div>',
data: function() {
return {}
}
})
var app = new Vue({
el: '#app',
data: {
thisShow: 'msga'
},
methods: {
msg: function(value) {
this.show = 'msg' + value
}
}
})
</script>