目录
(一)组件自定义事件
1.介绍
2.组件自定义事件的绑定
(1)在组件标签绑定
(2)通过ref属性绑定
(3)绑定后只调用一次
(4)为组件绑定原生事件
3.组件自定义事件的解绑
(二)全局事件总线
1.介绍
2.结构
(1)安装全局事件总线
(2)实现组件间数据传输
(三)消息订阅与发布
1.介绍
2.具体操作
(1)订阅
(2)发布
(四)$nextTick API
(四)Vue封装的动画与过渡
1.动画
2.过渡
3.借助第三方库
在上个小案例了解到了子组件给父组件传递数据的一种方式:父组件传递函数给子组件,子组件通过props接收再用函数进行调用;上述方法较为繁琐,所以利用组件自定义事件可以更好的实现“子传父”的功能
组件自定义事件:
和绑定事件一样,绑定到组件标签:v-on:自定义事件名=“函数名” 或者 @自定义事件名="函数名"
自定义事件的触发函数在父组件编写,子组件在函数内写this.$emit.('自定义事件名',...数据)触发自定义事件,从而实现“子传父”的功能
!!!涉及到“子传父”的情况都可以使用组件自定义事件!孙传父、父传子等用不了
在App.vue中:
methods: {
getSchoolName(name) {
console.log("app拿到了学校名:" + name)
}
}
在school.vue中
methods: {
sendSchoolName() {
// 触发自定义事件
this.$emit('schoolName', this.name)
}
}
自定义事件创建绑定后实际是存在于vc的events属性中,通过$emit()激发
在App.vue中
mounted() {
// 在挂载时绑定自定义事件
this.$refs.Stu.$on('stuName', this.getStuName)
}
在这里函数this.getStuName可以直接写成一个函数体,注意:一定是箭头函数! (this指向问题)
this.$refs.Stu.$on('stuName', (name) => {
console.log("app拿到了学校名:" + name)
})
在student.vue中
methods: {
sendStuName() {
this.$emit('stuName', this.name)
}
}
通过ref绑定看起来麻烦了点,实际这样可以实现标签直接绑定不能实现的功能,即:延时绑定
mounted() {
// 延时3s绑定
setTimeout(() => {
// 在挂载时绑定自定义事件
this.$refs.Stu.$on('stuName', this.getStuName)
}, 3000);
}
在挂载后的前3秒点击按钮不会响应,3s后就绑定了
[1]在组件标签绑定:v-once:schoolName="getSchoolName" 或者
@schoolName.once="getSchoolName"
[2]ref绑定:this.$refs.Stu.$once('stuName',this.getStuName)
Vue2会默认组件标签上绑定的事件就是自定义事件(Vue3已废除),所以为组件绑定原生事件时有以下两种方法:
[1]在绑定的组件内使用$emit激发;例如:this.$emit('click')
[2]在组件标签上添加.native;例如:@click.native="函数名"
this.$off('stuName') //解绑单个自定义事件
this.$off(['stuName', 'demo']) // 解绑多个自定义事件
this.$off([]) // 解绑所有自定义事件
在之前的笔记里记录的生命周期的销毁流程中,销毁的自定义事件就是这里写的所有自定义事件
一旦销毁该组件,该组件绑定的所有自定义事件都会解绑,不再有效
可以实现任意组件相互交流 适用于兄弟之间通信、爷和孙之间通信
本质就是在Vue原型上创建一个属性$bus,它的值是vm或者vc实例(能够提供$on、$off、$emit功能),从而任意组件vc都能够在原型上找到该属性,实现数据的传输
在main.js中:
new Vue({
// 将App组件放入容器中
render: h => h(App),
beforeCreate() {
// 在Vue原型上创建一个全局事件总线$bus,其值为该vm实例
Vue.prototype.$bus = this
},
}).$mount('#app')
这是最最标准、基础的一种写法
在school中:
mounted() {
this.$bus.$on('stuName', (data) => {
console.log("school收到了学生姓名:", data)
})
},
beforeDestroy() {
// 在该组件弃用删除之后,解绑该事件,减轻$bus的负担
this.$bus.$off('stuName')
},
在$bus上绑定自定义事件stuName,stuName被触发后发送数据data给school组件
最好在组件销毁前将自定义事件解绑,减轻$bus的负担
在student中:
methods: {
sendStuName() {
this.$bus.$emit('stuName', this.name)
}
},
触发自定义事件stuName,发送数据
可以实现任意组件的通信,借助第三方库pubsub-js实现(该库可以在多种语言里使用)
组件订阅消息,另一个组件发布消息,向订阅的组件传输数据
引入第三方库:import pubsub from 'pubsub-js'
订阅:pubsub.subscribe('消息名',(msgname,data)=>{...}) 最好使用箭头函数(需要用到this指针)
发布:pubsub.publish('消息名',data)
在school.vue中
mounted() {
// 订阅消息时箭头函数要接收至少两个数据:消息名和数据
this.pubsubID = pubsub.subscribe('stuName', (msgName,data) => {
console.log("school收到了学生名:", data);
})
},
beforeDestroy() {
// 取消订阅
pubsub.unsubscribe(this.pubsubID)
},
订阅消息时箭头函数要接收至少两个数据:消息名和数据
pubsub设计类似于定时器,订阅消息后会返回一个id,当取消订阅的时候unsubscribe里的参数就是该id
在student.vue中
methods: {
sendStuName() {
pubsub.publish('stuName', this.name)
}
},
发布消息要传两个参数:消息名和数据
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
用法:this.$nextTick(function(){ //dom更新后再运行的代码 })
在todolist小案例里,点击编辑后自动获取输入框焦点有用到这个api
this.$nextTick(function () {
this.$refs.focusIpt.focus()
})
vue在所有处理完后才会开始编译模板,如果直接写聚焦,此时模板还未编译,输入框还未出现,执行聚焦也没有效果
$nextTick实现模板更新编译后再执行内部的代码
作用:在插入、更新、移除dom元素时,在合适的时候给元素添加样式类名
元素进入的样式:
1.V-enter:进入的起点
2.V-enter-active:进入过程中
3.V-enter-to:进入的终点
元素离开的样式
1.v-leave:离开的起点
2.v-leave-active: 离开过程中
3.v-leave-to:离开的终点
使用
备注:若有多个元素需要过渡,则需要使用:
我显示出来了
.comego-enter-active {
animation: comego 0.5s;
}
.comego-leave-active {
animation: comego 0.5s reverse;
}
@keyframes comego {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0)
}
}
我显示出来了
p {
background-color: cornflowerblue;
height: 50px;
width: 200px;
transition: 0.5s linear;
}
.comego-enter,
.comego-leave-to {
transform: translateX(-100%);
}
.comego-enter-to,
.comego-leave {
transform: translateX(0);
}
通过第三方库,例如animate.css
Animate.css | A cross-browser library of CSS animations.
网站内有用法的详细说明