1. 组件自定义事件
- 一种组件间通信的方式,适用于子组件给父组件传递数据。在父组件中给子组件绑定自定义事件,事件的触发在子组件,事件的回调函数在父组件中
- 绑定自定义事件:
-
第一种方式,在父组件中:
<School @myEvent.once="callBackFunc"/>
(只能被触发一次)或<School v-on:myEvent="callBackFunc"/>
-
第二种方式,在父组件中:先用
<School ref="school "/>
给子组件注册引用信息,这样就能获取到Student的组件实例对象vc。然后再在父组件中通过生命周期函数mounted进行绑定自定义事件
-
mounted() {
// this.$refs.student.$once(......) // 只能被触发一次
// 直接在这里实现callBackFunc,如果是普通函数,则普通函数里面的this是Student组件实例对象vc
// 如果是箭头函数,箭头函数没有this,则向外找,箭头函数里面的this是父组件的实例对象
this.$refs.student.$on('myEvent', this.callBackFunc)
}
-
触发自定义事件:在子组件中:
this.$emit('myEvent', 'param1', param2)
-
事件回调函数:在父组件中:callBackFunc(param1, param2) {…}
-
解绑自定义事件:在子组件中:
this.$off('myEvent')
(解绑一个)、this.$off(['myEvent'])
(解绑多个)、this.$off()
(解绑所有) -
在父组件中给子组件上绑定原生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:
- 使用事件总线之接收数据:School组件想接收数据,则在School组件中给$bus绑定组件自定义事件,事件的回调函数在School组件中
- 在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:
- 接收数据:School组件想接收数据,则在School组件中订阅topic,订阅的回调函数在School组件中
- 取消订阅:最好在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输入框就能自动获取焦点