组件间通信

父传子:props

  1. 子组件代码: props

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    <template>
    <div class="infos">
    <h2>name:{{ name }}</h2>
    <h2>age:{{ age }}</h2>
    <h2>height:{{ height }}</h2>

    <h2>Message:{{showMessage}}</h2>
    </div>
    </template>

    <script>
    export default {
    name: "ShowInfo",
    // 数组语法:接收父组件传递过来的属性
    // 弊端:1.不能对类型进行验证 2.没有默认值
    // props: ["name", "age", "height"]

    props: {
    name:{
    type: String,
    default: "defaultName"
    },
    age: {
    type: Number,
    require: true,
    },
    height: {
    type: Number,
    default: 0
    },
    // 对象类型必须写函数
    friend:{
    type:Object,
    default(){
    return {
    message:"hello"
    }
    }
    },
    hobbies: {
    type:Array,
    default() {
    return ["bas", "rap", "dance"];
    }
    },
    showMessage:{
    type: String,
    default:"我是默认message"
    }

    }
    }
    </script>

    <style scoped>

    </style>
  2. 父组件:子组件注册并应用,传递值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <template>
    <div>APpContent</div>
    <ShowInfo name="lcy" :age=19 :height="198"></ShowInfo>
    <hr>
    <ShowInfo name="ct" :age=27 :height="166"></ShowInfo>
    <hr>
    <ShowInfo :age="18" show-message="hahhaaah"></ShowInfo>
    </template>

    <script>
    import ShowInfo from "@/02_组件通信-父传子/ShowInfo";
    export default {
    name: "App",
    components:{
    ShowInfo,
    }
    }
    </script>

    <style scoped>

    </style>

    非props的attribute

  3. 概念

    1. 如果当前的属性是一个非prop的attribute,那么改属性会默认添加到子组件的根元素上
    2. 当然可以禁用 inheritAttrs:false
    3. 禁用以后还想拿到,:class=”$attrs.禁用的属性”

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<template>
<div class="infos">
<h2 :v-text="$attrs.address">name:{{ name }}</h2>
<h2>age:{{ age }}</h2>
<h2>height:{{ height }}</h2>

<h2>Message:{{showMessage}}</h2>
</div>
</template>

<script>
export default {
name: "ShowInfo",
// 数组语法:接收父组件传递过来的属性
// 弊端:1.不能对类型进行验证 2.没有默认值
// props: ["name", "age", "height"]

props: {
name:{
type: String,
default: "defaultName"
},

showMessage:{
type: String,
default:"我是默认message"
}

}
}
</script>

<style scoped>

</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div>APpContent</div>
<!-- 如果当前的属性是一个非prop的attribute,那么改属性会默认添加到子组件的根元素上-->
<ShowInfo name="lcy" :age=19 :height="198"
address="广州市" at="ceshi"></ShowInfo>
<hr>
<ShowInfo name="ct" :age=27 :height="166"></ShowInfo>
<hr>
<ShowInfo :age="18" show-message="hahhaaah"></ShowInfo>
</template>

<script>
import ShowInfo from "@/02_组件通信-父传子/ShowInfo";
export default {
name: "App",
components:{
ShowInfo,
}
}
</script>

<style scoped>

</style>

image.png

  1. 当不禁用attribute时且有多个根节点时,要手动指定绑定,不然会警告

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <template>
    <div class="infos">
    <h2 :v-text="$attrs.address">name:{{ name }}</h2>
    <h2>age:{{ age }}</h2>
    <h2>height:{{ height }}</h2>

    <h2>Message:{{showMessage}}</h2>
    </div>
    <div class="other" v-bind="$attrs">1111</div>
    </template>

    <script>
    export default {
    name: "ShowInfo",
    // 数组语法:接收父组件传递过来的属性
    // 弊端:1.不能对类型进行验证 2.没有默认值
    // props: ["name", "age", "height"]
    // 不禁用且有多个根节点的时候,要手动指定绑定到节点上 v-bind
    // inheritAttrs:false,
    props: {
    name:{
    type: String,
    default: "defaultName"
    },

    showMessage:{
    type: String,
    default:"我是默认message"
    }

    }
    }
    </script>

    <style scoped>

    </style>

    子传父emit:

  2. 概念

image.png
image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div class="add">
<button @click="addBtn(1)">+1</button>
<button @click="addBtn(5)">+5</button>
<button @click="addBtn(10)">+10</button>
</div>
</template>

<script>
export default {
name: "AddCounter",
methods:{
// 监听按钮时间,然后发送出去
addBtn(count){
this.$emit("add", count)
},
},
}
</script>

<style scoped>

</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<template>
<div class="app">
<h2>计数:{{ counter}}</h2>
<!-- 接收来自子组件内部传过来的参数,在父组件内进行操作 -->
<add-counter @add="addBtnClick"></add-counter>
<sub-counter @sub="subBtnClick"></sub-counter>
</div>
</template>

<script>
import AddCounter from "@/03_组件通信-子传父/AddCounter";
import SubCounter from "@/03_组件通信-子传父/SubCounter";
export default {
name: "App",
components:{
AddCounter,
SubCounter
},
data(){
return {
counter: 0
}
},
methods:{
addBtnClick(count){
this.counter += count
},
subBtnClick(count){
this.counter -= count
},
}
}
</script>

<style scoped>

</style>

通信案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// App.vue
<template>
<div class="app">
<tab-control :titles="['衣服','鞋子','裤子']"
@table-item-click="tableItemClick">

</tab-control>
<hr>
<div class="content">{{pageContents[pageCurrentIndex]}}</div>
</div>
</template>

<script>
import TabControl from "@/04_组件通信案例/components/TabControl";
export default {
name: "App",
components:{
TabControl
},
data(){
return{
pageContents:["衣服页面","鞋子列表","裤子列表"],
pageCurrentIndex:0,
}
},
methods:{
tableItemClick(index){
console.log("app",index)
this.pageCurrentIndex = index
},
},
}
</script>

<style scoped>

</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// TabControl.vue
<template>

<div class="tab-control">
<template v-for="(item, index) in titles" :key="item">

<!-- 绑定class 改变点击所在位置的样式-->
<div class="tab-control-item"
@click="itemClick(index)"
:class="{active:index === currentIndex}">

<span>{{item}}</span>
</div>
</template>
</div>
</template>

<script>
export default {
props:{
titles:{
type:Array,
default(){
return []
}
}

},
data(){
return{
currentIndex:0
}
},
emits:['tableItemClick'],
methods:{

// 监听点击事件,获取点击位置索引
itemClick(index){
this.currentIndex = index
console.log(this.currentIndex)
// 给到父组件 是在第几个索引下
this.$emit('tableItemClick', index)
}
}
}
</script>

<style scoped>
.tab-control{
display: flex;
height: 44px;
line-height: 44px;
text-align: center;
}
.tab-control-item{
flex: 1;
}
.tab-control-item.active{
color: red;
font-weight: 777;
}
.tab-control-item.active span{
border-bottom: 3px solid red;
padding: 8px;
}

</style>