Vue-组件间通信

组件间通信

  1. props 父组件向子组件传递数据
  2. $emit 自定义组件 ,子组件数据传递父组件
  3. slot 插槽分发内容

组件间通信规则

  1. 不要再子组件中修改父组件传递的数据
  2. 数据初始化时,应当看初始化的数据是否用于多个组件中, 如果需要被用于多个组件中, 则初始化在父组件中; 如果在一个组件中使用,则出现在该组件中
  3. 数据初始化在那个组件中, 更新就应当在那个组件中

声明组件对象中定义 props

  1. 在声明组件对象中使用props
    1
    2
    3
    4
    5
    6
    7
    const MyComponet {
    template: '<div></div>',
    props: 此处有三种方式,
    components: {

    }
    }

    方式一: 指定传递属性名, 数组形式

    1
    props: ['id','name','slary','author']

    方式二:指定传递数据对象和数据类型,对象像是

    1
    2
    3
    4
    5
    6
    7
    8
    9
    props: {
    id: Number,
    name: String,
    salary: Number,
    isPublish: Boolean,
    commentIds: Array,
    author: Objects,
    getEmp: Function
    }

    引用组件时动态赋值

    在引用组件时通过v-bind动态赋值
    1
    2
    3
    <my-componet v-bind:id="2" :name="Xiaoxin" :slary="9999">

    </my-componet>

    实例一

    AppHome.js
    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
    ;(function () {
    const template = `
    <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

    <!--右边上半区域-->
    <h1 class="page-header">Dashboard</h1>
    <!--通过属性绑定的形式传递数据-->
    <dashboard :hobbies="hobbies"></dashboard>
    <!--右边下半区域-->
    <h2 class="sub-header">Section title</h2>
    <home-list :empList="empList"></home-list>

    </div>`
    window.AppHome = {
    template,
    data(){
    return {
    hobbies:['eatting','sleep','gamming','coding'],
    empList: [
    { id:1, name:'xiaoxin1', slary:4000 },
    { id:2, name:'xiaoxin', slary:4000 },
    { id:3, name:'xiaoxin2', slary:4000 },
    { id:4, name:'xiaoxin3', slary:4000 },
    ]
    }
    },
    components: {
    Dashboard,
    homeList
    }
    }
    })()
    dashboard.sh
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ;(function () {
    window.Dashboard = {
    template: ` <div class="row placeholders">
    <div v-for="hobby in hobbies" class="col-xs-6 col-sm-3 placeholder">
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
    <h4>{{ hobby }}</h4>
    <span class="text-muted"></span>
    </div>
    </div>`,
    // 声明当前子组件接收父组件的属性列表
    props: ['hobbies']
    }
    })()

    传递数据注意

  2. props只适用于父组件向子组件传递
  3. 所有标签属性都会成为组件对象的属性, 模板页面可以直接饮用
  4. 如果需要向非子组件传递(孙代之后), 必须逐层传递
  5. 兄弟组件之间不能直接传递,必须通过父组件传递

实例二

子组件删除数据,根据传递数据使用原则,原数据定义在哪里就在那个组件中进行操作,所以这里删除的函数定义在了AppHome.js父组件中
AppHome.js

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
;(function () {
const template = `
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

<!--右边上半区域-->
<h1 class="page-header">Dashboard</h1>
<!--通过属性绑定的形式传递数据-->
<dashboard :hobbies="hobbies"></dashboard>
<!--右边下半区域-->
<h2 class="sub-header">Section title</h2>
<home-list :empList="empList" :delItem="delItem"></home-list>

</div>`
window.AppHome = {
template,
data(){
return {
hobbies:['eatting','sleep','gamming','coding'],
empList: [
{ id:1, name:'xiaoxin1', slary:4000 },
{ id:2, name:'xiaoxin', slary:4000 },
{ id:3, name:'xiaoxin2', slary:4000 },
{ id:4, name:'xiaoxin3', slary:4000 },
]
}
},
components: {
Dashboard,
homeList
},
methods: {// 删除元素函数
delItem(inx) {
this.empList.splice(inx, 1)
}
}
}
})()

homeList.js

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
;(function () {
const template = `<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Salary</th>
<th>Action</th>
</tr>
</thead>
<emp-list v-for="emp,inx in empList" :emp="emp" :inx="inx" :delItem="delItem" :key="emp.id"></emp-list>
<tbody>

</tbody>
</table>
</div>`
window.homeList = {
template,
components: {
empList
},
// 这里只声明delItem函数
props: ['empList', 'delItem']
}
})()

empList.js

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
;(function () {
const template = `<tr>
<td>{{emp.id}}</td>
<td>{{emp.name}}</td>
<td>{{emp.slary}}</td>
<td>
<a href="#" @click="delEmp">删除</a>
</td>
</tr>`
window.empList = {
template,
props: {
emp: { // 指定属性名称/数据类型/是否必须
type: Object,
request: true
},
inx: Number,
delItem: Function
},
methods: {
// 这里需要包裹一层才能使用传递过来的函数
delEmp(){
// 这里的inx是传递过来的属性,必须使用this.inx
this.delItem(this.inx)
}
}
}
})()

自定义传递数据 $emit

$emit主要用于子组件传递数据到父组件

实例

AppHome.js

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
;(function () {
const template = `
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

<!--右边上半区域-->
<h1 class="page-header">Dashboard</h1>
<!--通过属性绑定的形式传递数据
@自定义监听事件 = 监听函数
在子组件dashboard中触发了del_hobby事件调用delHobby函数
-->
<dashboard :hobbies="hobbies" @del_hobby="delHobby"></dashboard>
<!--右边下半区域-->
<h2 class="sub-header">Section title</h2>
<home-list :empList="empList" :delItem="delItem"></home-list>

</div>`
window.AppHome = {
template,
data(){
return {
hobbies:['eatting','sleep','gamming','coding'],
empList: [
{ id:1, name:'xiaoxin1', slary:4000 },
{ id:2, name:'xiaoxin', slary:4000 },
{ id:3, name:'xiaoxin2', slary:4000 },
{ id:4, name:'xiaoxin3', slary:4000 },
]
}
},
components: {
Dashboard,
homeList
},
methods: {
delItem(inx) {
this.empList.splice(inx, 1)
},
delHobby(inx) {
this.hobbies.splice(inx, 1)
}
}
}
})()

dashboard.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
;(function () {
window.Dashboard = {
template: ` <div class="row placeholders">
<div v-for="hobby,inx in hobbies" class="col-xs-6 col-sm-3 placeholder">
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
<h4>{{ hobby }}</h4>
<a href="#" @click="delHobby(inx)">del</a>
</div>
</div>`,
// 声明当前子组件接收父组件的属性列表
props: ['hobbies','del_hobby'],
methods: {
delHobby(inx){
// 通过emit自定义事向父组件传递数据
// del_hobby父组件中定义自定义事件
this.$emit('del_hobby', inx)
}
}
}
})()

注意事项

  1. 自定义事件只用于子组件想父组件传递数据
  2. 隔代组件或兄弟组件不适合这种方式

slot 插槽

实例
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
;(function () {
const template = ` <!--头部导航区域-->
<!--必须要有一个根元素, 有且仅有一个,下面添加div标签-->
<div>
<app-navbar></app-navbar>

<!--核心区域:分左右两边-->
<div class="container-fluid">
<div class="row">

<!--左边菜单栏区域-->
<app-left></app-left>

<!--右边主页面区域: 分上下两个区域-->
<app-home>
<!--这里定义slot的名称为"dashboard",当子组件引用这个slot时就会被替换为对应的html标签-->
<h1 slot="dashboard" class="page-header">{{title}}</h1>
</app-home>
</div>
</div>
</div>`
window.App = {
template,
components: {
AppNavbar, //等价于AppNavbar:AppNavbar ,AppNavbar在appNavBarr.js中引入
appLeft,
AppHome,
},
data(){
return {
title: 'Dashboard01'
}
}
}
})()

AppHome.js

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
;(function () {
const template = `
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

<!--右边上半区域-->
<!--<h1 class="page-header">Dashboard</h1>-->
<!--这里引用父组件中定义的slot为"dashboard"的元素-->
<slot name="dashboard"></slot>
<!--通过属性绑定的形式传递数据
@自定义监听事件 = 监听函数
在子组件dashboard中触发了del_hobby事件调用delHobby函数
-->
<dashboard :hobbies="hobbies" @del_hobby="delHobby"></dashboard>
<!--右边下半区域-->
<h2 class="sub-header">Section title</h2>
<home-list :empList="empList" :delItem="delItem"></home-list>

</div>`
window.AppHome = {
template,
data(){
return {
hobbies:['eatting','sleep','gamming','coding'],
empList: [
{ id:1, name:'xiaoxin1', slary:4000 },
{ id:2, name:'xiaoxin', slary:4000 },
{ id:3, name:'xiaoxin2', slary:4000 },
{ id:4, name:'xiaoxin3', slary:4000 },
]
}
},
components: {
Dashboard,
homeList
},
methods: {
delItem(inx) {
this.empList.splice(inx, 1)
},
delHobby(inx) {
this.hobbies.splice(inx, 1)
}
}
}
})()

注意事项

  1. 只能用于父组件想子组件传递数据
  2. 传递的插槽标签需要定义在父组件中

非父子组件之间进行通信 PubSubJs

理解: 订阅消息 ==== 绑定事件监听, 发布消息 ==== 触发事件
注意: 需要先执行订阅事件subscribe, 然后才能publish时间
安装: npm install pubsub-js

订阅消息(绑定监听事件)

先在create钩子函数中订阅消息

注意这里要使用箭头函数”=>”,这样this就是代表父函数对象Vue,否则代表pubsubJs

1
2
3
PubSub.subscribe('消息名称',(event, data) => {
// 处理回调函数
})
发布消息(触发时间)
1
PubSub.publish('消息名称',data)
实例

AppLeft.js(订阅方)

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
;(function () {
window.appLeft = {
template: `<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<!--<li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>-->
<li @click="currentActive(item)" :class="{active: current === item}" v-for="item in top">
<a :href="item.url">{{item.name}}<span>({{delNum}})</span></a>
</li>
</ul>
</div>`,
data(){
return {
top:[
{name:'Overview',url:'#'},
{name:'Reports',url:'#'},
{name:'Analytics',url:'#'},
{name:'Export',url:'#'},
],
current: top[1],
delNum:0,
}
},
methods:{
currentActive(item){
this.current = item
}
},
created() {
PubSub.subscribe('changeNum',(event, num) => { //这里必须用箭头函数,代表vue实例,否则将代表pubsub
// 事件回调处理
// 统计删除总数量
this.delNum = this.delNum + num
})
}
}
})()

AppHome.js(发布方)

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
;(function () {
const template = `
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">

<!--右边上半区域-->
<!--<h1 class="page-header">Dashboard</h1>-->
<!--这里引用父组件中定义的slot为"dashboard"的元素-->
<slot name="dashboard"></slot>
<!--通过属性绑定的形式传递数据
@自定义监听事件 = 监听函数
在子组件dashboard中触发了del_hobby事件调用delHobby函数
-->
<dashboard :hobbies="hobbies" @del_hobby="delHobby"></dashboard>
<!--右边下半区域-->
<h2 class="sub-header">Section title</h2>
<home-list :empList="empList" :delItem="delItem"></home-list>

</div>`
window.AppHome = {
template,
data(){
return {
hobbies:['eatting','sleep','gamming','coding'],
empList: [
{ id:1, name:'xiaoxin1', slary:4000 },
{ id:2, name:'xiaoxin', slary:4000 },
{ id:3, name:'xiaoxin2', slary:4000 },
{ id:4, name:'xiaoxin3', slary:4000 },
]
}
},
components: {
Dashboard,
homeList
},
methods: {
delItem(inx) {
this.empList.splice(inx, 1)
},
delHobby(inx) {
this.hobbies.splice(inx, 1)
// 通过订阅的方式记录删除数
PubSub.publish('changeNum', 1)
}
}
}
})()

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

文章标题:Vue-组件间通信

文章字数:2.6k

本文作者:Aaron

发布时间:2019-12-14, 10:09:23

最后更新:2019-12-14, 15:20:41

原始链接:http://blog.linuxerbulo.com/2019/12/14/Vue-%E7%BB%84%E4%BB%B6%E9%97%B4%E9%80%9A%E4%BF%A1/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏