一、組件各部分說明及互相引用
1.一個vue組件由三個部分組成
Template
只能存在一個根元素
2.Script
3.Style
scoped:樣式只在當前組件內生效
1.1 組件的基本引用代碼示例
重點:第1步,app.vue;第2步,father.vue
0、src/main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'//【重點1】引入vue.js
import App from './App'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({//【重點】創建vue組件實例
el: '#app', //[1]:在index.html里id為#app標簽里寫入組件內容
components: { App },//[2]:寫入的組件
template: '<App/>' //[3]:寫入的模板名(也可看成一個完整組件)
})
第1步,src/APP.vue引入子組件示例
<template>
<div id="app">
<img src="./assets/logo.png">
<Father /> <!-- 【2】第2步,調用子組件 -->
</div>
</template>
<script>
import Father from './components/father' //【1】第1步,引入子組件
export default {
name: 'App',
components: {
Father //【3】第3步,把組件寫到此處,目的是把它暴露出去
},
data () {//【data必須是一個函數】此為標准es6寫法,也可寫成data:function(),這樣才能對每個實例可以維護一份被返回對象的獨立的拷貝
return {
msg: 'hello',
}
},
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
第2步,src/components/father.vue
<template>
<div> <!-- 第一層只能有一個根標簽 -->
父組件
<Child /> <!-- 【2】第2步,調用子組件 -->
</div>
</template>
<script>
import Child from './child' //【1】第1步,引入子組件
export default{//需要暴露出去的內容都要寫在此處,這樣才能被其它組件使用用
name:'Father',//當前組件名
components:{//【3】第3步,把組件寫到此處,目的是把它暴露出去(其對應import xxx)中的xxx
Child,
},
data(){//data必須是一個函數】此為標准es6寫法,也可寫成data:function(),這樣每個實例可以維護一份被返回對象的獨立的拷貝
return{msg:'father'} //此處一定要記得return
},
}
</script>
<style scoped> /* [4]知識點4,此處寫的樣式只對當前father.vue組件生效 */
</style>
第3步,src/components/child.vue
<template>
<div>
子組件
</div>
</template>
<script>
export default{
name:'child',
data(){
return{ tit:'child'}
}
}
</script>
<style scoped>
</style>
效果:
父組件
子組件
二、父-->子組件通信(交互)props----父傳子
1.通過設置子組件的Props(道具)接收父組件的傳值代碼示例
father.vue
1、父組件設置一個屬性:(如name=xxx)
<template>
<div>
<h1>主題:父組件向子組件傳值</h1>
<Child title='父組件的數據' /> <!-- 【1】第1步,建一個屬性title=xx,寫入xx數據 -->
</div>
</template>
<script>
import Child from './child'
export default{
name:'Father',
components:{
Child,
},
data(){
return {msg:'father'}
},
}
</script>
<style scoped>
</style>
child.vue
2、子組件通過設置props接收父組件傳過來的內容:props:[ 'name' ]或 props:{name:{type:String,default:''}}
3、顯示父組件傳的內容:{{name}}
<template>
<div>
<!-- 【3】顯示父組件傳過來的值 -->
<h2>子組件:{{title}}</h2>
</div>
</template>
<script>
export default{
name:'child',
data(){
return{}
},
props:["title"] #【2】通過props接收父組件傳的數據
}
</script>
<style scoped>
</style>
效果:箭頭部分即父組件title=xxx,傳過來的值

2.向子組件傳data里的動態數據
father.vue
1、在data(){title:'title content'}
2、把<child title=xxx /> 中的xx換成data里的title
<template>
<div>
<h1>主題:父組件向子組件傳data里的動態值</h1>
<Child v-bind:title="msg" /> <!-- 【1】第1步,title=xx,的內容寫成data里的屬性名 -->
</div>
</template>
<script>
import Child from './child'
export default{
name:'Father',
components:{
Child,
},
data(){
return {
msg:"父組件data內的動態的數據",//【1】數據里寫一個屬性:值;
}
},
}
</script>
<style scoped>
</style>
child.vue
3、child里不變
<template>
<div>
<!-- 【2】顯示父組件傳過來的值 -->
<h2>子組件:{{title}}</h2>
</div>
</template>
<script>
export default{
name:'child',
data(){
return{tit:'child'}
},
props:["title"]//[1]接收父組件的屬性名(在father.vue里的<child title=xx /> )
}
</script>
<style scoped>
</style>

3.改變data里的msg,將自動傳給子組件示例
<template>
<div>
<h1>主題:父組件向子組件傳data里的動態值</h1>
<Child v-bind:title="msg" /> <!-- 【1】第1步,title=xx,的內容寫成data里的屬性名 -->
<button v-on:click="change_msg">改變一下</button>
</div>
</template>
<script>
import Child from './child'
export default{
name:'Father',
components:{
Child,
},
data(){
return {
msg:"父組件data內的動態的數據",//【1】數據里寫一個屬性:值;
}
},
methods:{
change_msg(event){//按鍵的處理函數
this.msg='改變一下msg消息'
}
}
}
</script>
<style scoped>
</style>
效果:

4.子組件通過props,父組件的v-model,隨時獲取表單數據示例
father.vue
【1】第1步,再定義一個數據,初始數據隨便設置
【2】第2步,再v-bind綁定第2個屬性msg(此可隨便設置,子組件的props對應即可)為data里的msg2
【3】第3步,在表單里綁定data里的msg2
<template>
<div>
<h1>主題:父組件通過v-model實時向子組件傳data里的值</h1>
<input v-model="msg2" /> <!-- 【3】第3步,在表單里綁定data里的msg2 -->
<Child v-bind:title="msg" v-bind:msg='msg2' /> <!-- 【2】第2步,再v-bind綁定第2個屬性msg(此可隨便設置,子組件的props對應即可)為data里的msg2 -->
<button v-on:click="change_msg">改變一下</button>
</div>
</template>
<script>
import Child from './child'
export default{
name:'Father',
components:{
Child,
},
data(){
return {
msg:"父組件data內的動態的數據",//數據里寫一個屬性:值;
msg2:'父向子組件傳遞的第2個數據'//【1】第1步,再定義一個數據,初始數據隨便設置
}
},
methods:{
change_msg(event){
this.msg='改變一下msg消息'
}
}
}
</script>
<style scoped>
</style>
child.vue
【1】接收父組件的屬性1、2的名字title,msg(在father.vue里的<child title= msg= />
【2】顯示父組件傳過來的屬性1,屬性2
<template>
<div>
<!-- 【2】顯示父組件傳過來的屬性1,屬性2 -->
<h2>子組件:{{title}}--{{msg}}</h2>
</div>
</template>
<script>
export default{
name:'child',
data(){
return{ tit:'child'}
},
props:["title","msg"]//[1]接收父組件的屬性1、2的名子(在father.vue里的<child title=xx msg=xxx /> )
}
</script>
<style scoped>
</style>
效果:輸入框值變動,子組件隨時跟着變動

5.通過子組件的props限制父組件傳過來的數據類型
father.vue
【1】再定義一個數據
【2】第2步,對子組件,再加個v-bind綁定第2個屬性age(此可隨便設置,子組件的props對應即可)為data里的num
<template>
<div>
<h1>主題:父組件通過v-model實時向子組件傳data里的值</h1>
<input v-model="msg2" />
<Child v-bind:title="msg" v-bind:msg='msg2' :age='num' /> <!-- 【2】第2步,再v-bind綁定第2個屬性age(此可隨便設置,子組件的props對應即可)為data里的num -->
<button v-on:click="change_msg">改變一下</button>
</div>
</template>
<script>
import Child from './child'
export default{
name:'Father',
components:{
Child,
},
data(){
return {
msg:"父組件data內的動態的數據",//數據里寫一個屬性:值;
msg2:'父向子組件傳遞的第2個數據',
num:'hello'//【1】再定義一個數據
}
},
methods:{
change_msg(event){
this.msg='改變一下msg消息'
}
}
}
</script>
<style scoped>
</style>
child.vue
【1】把props改成字典寫法,逐個對其屬性的數據類型進行限定,把age的數據類型限定為數字
【2】顯示父組件傳過來的屬性3:age
<template>
<div>
<!-- 【2】顯示父組件傳過來的屬性1,屬性2,屬性3:age -->
<h2>子組件:{{title}}--{{msg}}----{{age*2}}</h2>
</div>
</template>
<script>
export default{
name:'child',
data(){
return{tit:'child'}
},
props:{//【1】把props改成字典寫法,逐個對其屬性的數據類型進行限定
title:String,
msg:String,
age:Number //此處把age的數據類型限定為數字
}//["title","msg","age"]//[1]接收父組件的屬性1、2的名子(在father.vue里的<child title=xx msg=xxx /> )
}
</script>
<style scoped>
</style>
效果:
- 因為fahter.vue里的data的num數據類型為'hello'是字符串類型
- 又child.vue里的props限定了num必須為數字
- 所以控制台會報錯:Invalid prop: type check failed for prop "age". Expected Number with value NaN, got String with value "hello".
- 只有父組件里的數據為數字(如Num=10),此處才能正確運行顯示:20(num2=102)

5.2 子組件用props把父組件傳過來的數據[限定為多種數據類型]、[設置為必需選項]
【1】設置為支持多種數據類型 title:[String,Number],父組件傳的title值可以為字符串,或數字
【2】設置為是否必須選項,如果父組件沒有傳msg=xx這個屬性,就報錯
msg:{//【2】設置為是否必須選項
type:String,
required:true
}
原碼:
<template>
<div>
<!-- 顯示父組件傳過來的屬性1,屬性2,屬性3:age -->
<h2>子組件:{{title}}--{{msg}}----{{age*2}}</h2>
</div>
</template>
<script>
export default{
name:'child',
data(){
return {tit:'child'}
},
props:{
title:[String,Number],//【1】設置為支持多種數據類型
msg:{//【2】設置為是否必須選項
type:String,
required:true
},
age:Number,
}
}
</script>
<style scoped>
</style>
效果:父組件沒傳msg,警告信息

5.3在子組件props設置默認值(如果父不傳,則使用默認值)
child.vue
<template>
<div>
<!-- 【2】顯示父組件傳過來的屬性1,屬性2,屬性3:age -->
<h2>子組件:{{title}}--{{msg}}----{{age*2}}</h2>
</div>
</template>
<script>
export default{
name:'child',
data(){
return {tit:'child'}
},
props:{
title:[String,Number],
msg:{
type:String,
required:true
},
age:{//【1】設置默認值
type:Number,
default:5
}
}
}
</script>
<style scoped>
</style>
結果:父組件沒傳num,子組件用默認值5計算出來的值5*2=10

6.父組件data數據為字典時,向子組件props傳值
father.vue
【1】第1步,設置一個字典的數據
【2】第2步,再v-bind綁定ojbData為data里的fatherObj
<template>
<div>
<h1>主題:父組件通過v-model實時向子組件傳data里的【對象類型數據】值</h1>
<input v-model="msg2" />
<Child v-bind:title="msg" :msg="msg2" :objData="fatherObj" /> <!-- 【2】第2步,再v-bind綁定ojbData為data里的fatherObj -->
<button v-on:click="change_msg">改變一下</button>
</div>
</template>
<script>
import Child from './child'
export default{
name:'Father',
components:{
Child,
},
data(){
return {
msg:"父組件data內的動態的數據",
msg2:'父向子組件傳遞的第2個數據',
num:10,
fatherObj:{//【1】第1步,設置一個字典的數據
name:'flying',
age:22
}
}
},
methods:{
change_msg(event){
this.msg='改變一下msg消息'
}
}
}
</script>
<style scoped>
</style>
child.vue
【1】父組件傳值是字典時,props的特殊寫法
- 【1.1】此處數據類型必須設置為Object
- 【1.2】這里返回值"未知"、0等可隨意,目的是如果父組件沒有傳對應的值,就用此默認的值
【2】顯示父組件傳過來的字典類型數據
<template>
<div>
<h2>子組件:{{title}}--{{msg}}----{{age*2}}</h2>
<!-- 【2】顯示父組件傳過來的字典類型數據 -->
<h3>子組件:父組件傳的對象{{objData}}---名字是:{{objData.name}}</h3>
</div>
</template>
<script>
export default{
name:'child',
data(){
return {tit:'child'}
},
props:{
title:[String,Number],
msg:{
type:String,
required:true
},
age:{
type:Number,
default:5
},
objData:{//【1】父組件傳值是字典時,props的特殊寫法
type:Object, //【1.1】此處數據類型必須設置為Object
default:function(){
return{//【1.2】這里返回值"未知"、0等可隨意,目的是如果父組件沒有傳對應的值,就用此默認的值
name:"未知",
age:0,
}
}
}
}
}
</script>
<style scoped>
</style>
效果:
子組件:父組件傳的對象{ "name": "flying", "age": 22 }---名字是:flying
三、子 -> 父組件通信——子傳父
3.1簡單的子--->父通信
第1步:child.vue
【0】此處通過點擊鼠標觸發的函數向父組件發消息
【1】重點:傳數據給父組件:this.$emit(鍵名,鍵值); 鍵名隨便,父組件接收時要對應;鍵值此處用data里數據:this.msg
<template>
<div>
<!-- 【0】此處通過點擊鼠標觸發的函數向父組件發消息 -->
<button v-on:click="sendMsg">點此向父組件發消息</button>
</div>
</template>
<script>
export default{
name:'child',
data(){
return{
msg:'子組件發的消息'
}
},
methods:{
sendMsg(event){
/*【1】重點:固定寫法:this.$emit(鍵名,鍵值); 鍵名隨便。鍵值此處用data里數據:this.msg
父組件<child @sendmsg='處理函數'/>接收時@sendmsg處要對應;(把sendmsg當成一個自定義事件)
*/
this.$emit("sendmsg",this.msg)
}
}
}
</script>
<style>
</style>
第2步,parent.vue
【1】用監聽事件命令v-on(簡寫@sendmsg(此名隨便寫)),監聽到之后觸發一個函數getMsg,用它來測試子組件發來的消息
[2]定義一個空數據用來接收子組件傳來的消息
【3】把接收到的數據傳給data里的msg
【4】展示子組件傳過來的消息
<template>
<div>
父組件
<Child v-on:sendmsg='getMsg' /><!-- 【1】把sendmsg當自定義事件,所以要用監聽事件命令v-on(簡寫@sendmsg(此名隨便寫)),監聽到之后觸發一個函數getMsg,用它來測試子組件發來的消息 -->
{{msg}}<!-- 【4】展示子組件傳過來的消息 -->
</div>
</template>
<script>
import Child from './child';
export default{
name:'parent',
data(){
return{
msg:'' //[2]定義一個空數據用來接收子組件傳來的消息
}
},
components:{
Child,
},
methods:{
getMsg(data){//此處data可隨便寫,下面和其對應即可
console.log(data); //測試【3】把子組件傳的數據輸出到控制台
this.msg=data;//【3】把接收到的數據傳給data里的msg
}
}
}
</script>
<style>
</style>
效果:點擊按鈕之后,子組件即會發一個消息過來,父組件即接收,展示。

3.2父-->子-->父:父子組件的交互通信
parent.vue
【2.1】綁定data里的num(輸入變<==>data.num變)
【2.2】把data的數據轉換為Number類型,(this.num - 0,即是把此數據轉為數字類型)
【2.3】向子組件傳送的數據變為computed的toNum()函數處理后的值,即轉為數字再傳送給子組件
<template>
<div>
父組件
<!-- 【1】用監聽事件命令v-on(簡寫@sendmsg(此名隨便寫)),監聽到自定義事件sedmsg發生之后觸發一個函數getMsg,用它來接收子組件發來的消息;
v-bind為向子組件發送的數據; -->
<Child v-on:sendmsg='getMsg' v-bind:num='toNum' /> <!-- 【2.3】向子組件傳送的數據變為computed的toNum()函數處理后的值,即轉為數字再傳送給子組件 -->
<input type="text" v-model="num" /> <!-- 【2.1】綁定data里的num(輸入變<==>data.num變) -->
{{msg}}<!-- 【5】展示子組件傳過來的消息 -->
</div>
</template>
<script>
import Child from './child';
export default{
name:'parent',
data(){
return{
msg:'', //[3]定義一個空數據用來接收子組件傳來的消息
num:5,
}
},
components:{
Child,
},
computed:{
toNum(){//【2.2】把data的數據轉換為Number類型,(this.num -0,即是把此數據轉為數字類型)
return this.num - 0;
}
},
methods:{//【2】用函數來接收子組件消息輸出到控制台進行測試
getMsg(data){
console.log(data);
this.msg=data;//【4】把接收到的數據傳給data里的msg
}
}
}
</script>
<style>
</style>
child.vue
[2.1]接收父組件傳來的數據num(
【2.2】觸發發送函數,向父組件發送數據
【2.3】調用computed里的addNum對收到父組件的數據處理處理后,再發給父組件
【2.4】把props里收到的num進行處理的函數
<template>
<div>
<!-- 【0】此處通過點擊鼠標觸發的函數,sendMsg通過其向父組件發消息 -->
<button v-on:click="sendMsg">點此向父組件發消息</button> 【2.2】觸發
</div>
</template>
<script>
export default{
name:'child',
data(){
return{
msg:'子組件發的消息'
}
},
props:{//接收父組件數據道具
num:{//[2.1]接收父組件傳來的數據num(<child v-bind:num='toNum'/>)
type:Number,
default:8
}
},
computed:{
addNum(){//【2.4】把props里收到的num進行處理的函數
return this.num*10;
}
},
methods:{
sendMsg(event){
//【1】重點:固定寫法:this.$emit(鍵名,鍵值); 鍵名隨便,父組件接收時要對應;鍵值此處用data里數據:this.msg
this.$emit("sendmsg",this.addNum) //【2.3】調用computed里的addNum對收到父組件的數據處理處理后,再發給父組件
}
},
}
</script>
<style>
</style>
效果:在輸入框輸入數字,子組件接收,處理后,發回父組件顯示

