Vue3 正式版快要发布了,扶我起来,我还能学 /(ㄒoㄒ)/~~
今天整理学习笔记,发现过去写的一篇Vue2.0组件传值文章还算工整。虽然有点过时了,但毕竟 Vue2 一时半会还是主流,组件通信也是vue2最常用的技术之一,对初学者多少有点帮助。放着也是放着,发出来刷刷存在感~
下面开始正文。
这里具体介绍三种组件通信场景:父子通信,子父通信,兄弟组件通信(中央事件总线)
父子通信
-
父组件里定义数据 users,并给导入的子组件绑定数据 users;
-
子组件里用 props 选项获取父组件绑定给子组件的数据 users,并在 template 中直接使用数据 users。
<!-- App.vue 父组件 -->
<template>
<div id="app">
<!-- 2. 导入子组件 Users.vue,并绑定 data 中的数据 users -->
<users v-bind:users='users'></users>
</div>
</template>
<script>
// 导入子组件
import Users from './components/Users'
export default {
name: 'app',
data () {
return{
// 1. 定义数据 users
users:[
{name:'zs',age:19,gender:'male'},
{name:'ls',age:21,gender:'male'},
{name:'ww',age:23,gender:'female'}
]
}
}
}
</script>
<!-- Users.vue 子组件 -->
<template>
<div id="users">
<h3>用户列表</h3>
<!-- 4. 直接使用数据 users -->
<ul v-for="user in users">
<li>用户名:{{user.name}},年龄:{{user.age}},性别:{{user.gender}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'users',
// 3. 用 props 选项获取父组件绑定给子组件的数据 users
props: {
users: {
type: Array,
required: true
}
}
}
</script>
子父通信
场景:在子组件里调用 changeTitle() 方法,改变父组件数据 title 的值,同时改变。
思路:使用事件从子组件向父组件传值。
- 在子组件中自定义函数 changeTitle,调用该函数会触发事件 titleChanged,该事件会传一个参数”新的标题“;
- 当点击子组件的 header 标签时,调用自定义函数 changeTitle,触发了 titleChanged;
- 父组件中自定义函数 updateTitle(newTitle),该函数的参数来自于子组件触发事件 titleChanged 传入的参数 “新的标题”,并把"新的标题" 赋值给父组件 data 里的数据 title;
- 父组件 template 里导入子组件,
- <app-header> 绑定子组件的 titleChanged($event) 事件,该事件调用父组件函数 updateTitle(newTitle);
- <app-header> 绑定父组件 data 里的数据 title,此时 title 已经变成了子组件传入的"新的标题"
<!-- App.vue 父组件 -->
<template>
<div id="app">
<!-- 3. 导入子组件 Header.vue,绑定子组件的自定义事件 titleChanged,该事件触发 updateTitle() 方法,该方法接收自定义事件 titleChanged 传入父组件的参数 "新的标题",用 $event 表示;
5. 子组件绑定父组件 data 中的数据 title,此时 title 的值已经是"新的标题" -->
<app-header @titleChanged="updateTitle($event)" :title='title'></app-header>
</div>
</template>
<script>
import Header = from './components/Header'
export default {
name: 'app',
data () {
return{
title:'旧的标题',
users:[
{name:'zs',age:19,gender:'male'},
{name:'ww',age:23,gender:'female'}
]
}
},
methods:{
// 4. 自定义 updateTitle() 方法,使旧的标题变成新的标题
updateTitle(newTitle){
// newTitle是子组件传到父组件的参数 "新的标题"
this.title = newTitle;
}
},
components:{
// 将 Header.vue 组件命名为 app-header
"app-header":Header
}
}
</script>
<!-- Header.vue 子组件 -->
<template>
<!-- 2. 点击子组件的 header 标签时,触发 changeTitle 方法 -->
<header @click="changeTitle">
<h1>{{title}}</h1>
</header>
</template>
<script>
export default {
name: 'app-header',
props:{
title:{
type: String
}
},
methods: {
// 1. 自定义 changeTitle 方法
changeTitle(){
// 自定义事件 titleChanged,该事件会传一个参数 "新的标题"
this.$emit("titleChanged","新的标题")
}
}
}
</script>
兄弟组件通信(中央事件总线)
- 创建中央事件总线
middleBus.js
import Vue from 'Vue'
export default new Vue;
- 创建组件一,引入中央事件总线,$emit实例方法触发自定义的addMsg方法,并传参
child1.js
<script>
import middleBus from '../middleBus.js';
export default {
methods: {
sendMsg: function(){
middleBus.$emit('addMsg','这条消息来自child1.js')
}
}
}
</script>
- 创建组件二,引入中央事件总线,$on实例方法监听自定义的addMsg方法,并把传过来的参数传递给 $on监听器的回调函数
child2.js
<script>
import middleBus from '../middleBus.js';
export default {
data(){
return {
msg:""
}
}
created: {
middleBus.$on('addMsg', function(e){
console.log('e') // 这条消息来自child1.js
this.msg = e
}
}
}
</script>
- 卸载页面前,移除事件监听器,$off(‘监听的事件名’)实例方法移除addMsg事件。否则会重复发射事件
child2.js
<script>
export default {
data(){
return {
msg:""
}
}
created:{
sendMsg: function(){
middleBus.$on('addMsg', function(e){
console.log('e') // 这条消息来自child1.js
this.msg = e
}
}
},
beforeDestroy(){
middleBus.$off('addMsg')
}
}
</script>
附注
其实用到中央事件总线,数据通信就已经有点复杂了,组件频繁加载的情况下,很容易造成事件重复注册。如果没有及时销毁事件,会造成很多意想不到的bug,所以更推荐用vuex进行全局状态管理。这就是 Vue2 另一个必知必会技能了,还没有掌握的小伙伴快去学习吧~