Vue组件自定义事件、全局事件总线、消息订阅与发布(pubsub)、$nextTick

1. 组件自定义事件

  1. 一种组件间通信的方式,适用于子组件给父组件传递数据。在父组件中给子组件绑定自定义事件,事件的触发在子组件,事件的回调函数在父组件中
  2. 绑定自定义事件:
    1. 第一种方式,在父组件中:<School @myEvent.once="callBackFunc"/>(只能被触发一次)或<School v-on:myEvent="callBackFunc"/>

    2. 第二种方式,在父组件中:先用<School ref="school "/>给子组件注册引用信息,这样就能获取到Student的组件实例对象vc。然后再在父组件中通过生命周期函数mounted进行绑定自定义事件

		mounted() {
		    // this.$refs.student.$once(......)    // 只能被触发一次
		    // 直接在这里实现callBackFunc,如果是普通函数,则普通函数里面的this是Student组件实例对象vc
		    // 如果是箭头函数,箭头函数没有this,则向外找,箭头函数里面的this是父组件的实例对象
			this.$refs.student.$on('myEvent', this.callBackFunc)
		}
  1. 触发自定义事件:在子组件中:this.$emit('myEvent', 'param1', param2)

  2. 事件回调函数:在父组件中:callBackFunc(param1, param2) {…}

  3. 解绑自定义事件:在子组件中:this.$off('myEvent')(解绑一个)、this.$off(['myEvent'])(解绑多个)、this.$off()(解绑所有)

  4. 在父组件中给子组件上绑定原生DOM事件,使用<School @click.native="callBackFunc"/>

使用示例
App.vue:绑定student2App组件自定义事件,事件的回调函数是getStudentName

<template>
	<div>
		<h1>App组件接收Student组件的学生姓名是:{{studentName}}</h1>

		<!-- 父组件给子组件绑定一个自定义事件 -->
		<Student ref="student"/>
	</div>
</template>

<script>
	import Student from './components/Student'

	export default {
		name:'App',
		components:{Student},
		data() {
			return {
				studentName:''
			}
		},
		methods: {
            // 事件的回调函数
			getStudentName(name, ...params){
        console.log(params)
				this.studentName = name
			}
		},
		mounted() {
            // 绑定自定义事件
			this.$refs.student.$on('student2App',this.getStudentName)
		}
	}
</script>

Student.vue:通过两个函数分别进行student2App组件自定义事件的触发和解绑

<template>
	<div>
		<h2>学生姓名:{{name}}</h2>
		<button @click="sendStudentlName">点我把学生名给App</button>
		<button @click="unbind">点我解绑student2App事件</button>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			return {
				name:'张三'
			}
		},
		methods: {
			sendStudentlName(){
				// 触发Student组件实例的student2App事件
				this.$emit('student2App',this.name,'param1',666)
			},
			unbind(){
                // 解绑多个自定义事件
				this.$off(['student2App'])
			}
		}
	}
</script>

先【点击把学生名给App】的效果如下,再【点击解绑student2App事件】,最后【点击把学生名给App】控制台没有输出
组件自定义事件

可以通过浏览器的Vue插件,查看组件自定义事件的触发记录,如下所示:
自定义事件的触发记录

2. 全局事件总线(GlobalEventBus)

一种组件间通信的方式,适用于任意组件间通信

示例如下:
main.js:安装全局事件总线,$bus就是当前应用的vm

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false

new Vue({
	el:'#app',
	render: h => h(App),
	beforeCreate() {
		// 安装全局事件总线
		Vue.prototype.$bus = this
	}
})

App.vue

<template>
	<div>
		<School/>
		<Student/>
	</div>
</template>

<script>
	import Student from './components/Student'
	import School from './components/School'

	export default {
		name:'App',
		components:{School,Student}
	}
</script>

School.vue:

  1. 使用事件总线之接收数据:School组件想接收数据,则在School组件中给$bus绑定组件自定义事件,事件的回调函数在School组件中
  2. 在beforeDestroy回调函数中,用$bus.$off去解绑当前组件所用到的事件
<template>
	<div>
		<h2>学校名称:{{name}}</h2>
	</div>
</template>

<script>
	export default {
		name:'School',
		data() {
			return {
				name:'第一中学'
			}
		},
		mounted() {
      // 给$bus绑定自定义事件
      // 事件回调函数是School组件的。因为事件回调函数里面的this是School实例对象
			this.$bus.$on('student2School',(studentName)=>{
        console.log(this)
				console.log('我是School组件,收到了学生的名字: ', studentName)
			})
		},
		beforeDestroy() {
      // 销毁School组件前,解绑和该组件有关的组件自定义事件
			this.$bus.$off('student2School')
		}
	}
</script>

Student.vue:使用事件总线之提供数据。通过$bus.$emit触发指定的组件自定义事件并传递数据

<template>
	<div>
		<h2>学生姓名:{{name}}</h2>
		<button @click="sendStudentName">把学生名传递给School组件</button>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			return {
				name:'张三'
			}
		},
		methods: {
			sendStudentName(){
        // 触发$bus的组件自定义事件,同时传递值
				this.$bus.$emit('student2School',this.name)
			}
		}
	}
</script>

点击按钮,控制台输出如下:
全局事件总线

3. 消息订阅与发布(pubsub)

一种组件间通信的方式,适用于任意组件间通信

消息订阅与发布是一种思想,需要借助其它第三方库,这里选择pubsub-js,使用命令cnpm install pubsub-js进行项目包安装。因为浏览器的Vue插件不支持第三方的pubsub-js,所有在Vue的Timeline的Component-events看不到事件记录

School.vue:

  1. 接收数据:School组件想接收数据,则在School组件中订阅topic,订阅的回调函数在School组件中
  2. 取消订阅:最好在beforeDestroy钩子中,用PubSub.unsubscribe(subId)去取消订阅的topic
<template>
	<div>
		<h2>学校名称:{{name}}</h2>
	</div>
</template>

<script>
	import pubsub from 'pubsub-js'
	export default {
		name:'School',
		data() {
			return {
				name:'第一中学'
			}
		},
		mounted() {
			this.subId = pubsub.subscribe('student2SchoolTopic',(topicName, name)=>{
				console.log(this)
				console.log('收到Student发送的消息,学生名字是: ',name)
			})
		},
		beforeDestroy() {
			pubsub.unsubscribe(this.pubId)
		}
	}
</script>

Student.vue:提供数据:使用pubsub.publish('topicName',数据)

<template>
	<div>
		<h2>学生姓名:{{name}}</h2>
		<button @click="sendStudentName">把学生名给School组件</button>
	</div>
</template>

<script>
	import pubsub from 'pubsub-js'
	export default {
		name:'Student',
		data() {
			return {
				name:'张三'
			}
		},
		methods: {
			sendStudentName(){
				pubsub.publish('student2SchoolTopic',this.name)
			}
		}
	}
</script>

点击按钮,控制台输出如下:
消息订阅与发布

4. this.$nextTick

  • 作用:在下一次DOM更新结束后执行其指定的回调函数
  • 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,可以在nextTick所指定的回调函数中实现

App.vue:直接使用this.$refs.inputData.focus()是获取不到焦点的,因为此时input输入框还是隐藏的,等editInput函数执行完才会去重新加载新的DOM。所以使用this.$nextTick等DOM加载完毕后,再去调用this.$refs.inputData.focus()获取焦点

<template>
	<div>
    <span v-show="!isEdit">{{data}}</span>
    <input type="text" v-model="data" v-show="isEdit" @blur="handelBlur" ref="inputData">
    <button @click="editInput">点我编辑文字</button>
	</div>
</template>

<script>


	export default {
		name:'App',
    data() {
      return {
        data:'学习',
        isEdit:false
      }
    },
    methods:{
      editInput() {
        this.isEdit=true
        
        this.$nextTick(function() {
          this.$refs.inputData.focus()
        })
      },
      handelBlur() {
        this.isEdit=false
      }
    }
	}


</script>

点击按钮,input输入框就能自动获取焦点
nextTick

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值