品牌的佛山网站建设价格,湖南省城乡和住房建设厅网站,雅安建设机械网站,如何在网站开发客户#x1f954;#xff1a;高度自律即自由 更多Vue知识请点击——Vue.js VUE2-Day9 全局事件总线1、安装全局事件总线2、使用事件总线#xff08;1#xff09;接收数据#xff08;2#xff09;提供数据#xff08;3#xff09;组件销毁前最好解绑 3、TodoList中的孙传父高度自律即自由 更多Vue知识请点击——Vue.js VUE2-Day9 全局事件总线1、安装全局事件总线2、使用事件总线1接收数据2提供数据3组件销毁前最好解绑 3、TodoList中的孙传父1首先在main.js中安装全局事件总线2在App.vue中绑定全局自定义事件并使用之前写好的回调3Item中触发事件并把数据id传过去 消息的订阅与发布1使用消息的订阅与发布2TodoList案例使用消息的订阅与发布 TodoList的编辑功能1、整体思路2、给标签添加事件3、点击编辑按钮切换span为input4、失去焦点传数据5、App收数据 $nextTick动画与过渡进入离开动画三种写法 全局事件总线
一种组件间通信的方式适用于任意组件间通信。通俗理解就是一个定义在所有组件之外的公共嘎达这个嘎达可以有vm或vc上的同款$on、$off、$emit也可以让所有组件都访问到。要想实现这个事情只能在Vue.prototype上添加一个属性值是vm或vc
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3OYNFD4-1692378989491)(D:\wxf\前端学习笔记\vue2vue3\笔记图片\全局事件总线.png)]
vm.$emit( event, arg ) //触发当前实例上的事件,arg是传递给父组件的参数
vm.$on( event, fn ) //监听event事件后运行 fn
$off(type, fn) //注销消息方法 type:消息名称 fn:消息回调函数1、安装全局事件总线
安装全局事件总线可以用vc也可以用vm写在main.js里面
用vc的话这么写
const Demo Vue.extend({});
const d new Demo();
Vue.prototype.$bus d;用vm的话这么写我们通常用vm
new Vue({el: #app,render: (h) h(App),//放这个函数里是因为模板还未解析这个函数在自定义事件定义之前是不会报错滴beforeCreate() {Vue.prototype.$bus this //安装全局事件总线},
})在这里我们使用vm安装全局事件总线。
2、使用事件总线
1接收数据
接收数据A组件想接收数据则在A组件中给$bus绑定自定义事件事件的回调留在A组件自身。
methods(){demo(data){......}
}
......
mounted() {this.$bus.$on(xxxx,this.demo)
}2提供数据
任意一个组件都可以给上面说的A组件传数据 methods:{sendStudentName(){this.$bus.$emit(xxxx,this.name)}
}3组件销毁前最好解绑
最好在beforeDestroy钩子中用$of去解绑当前组件所用到的事件。 因为接收数据的组件A中定义的回调函数和自定义事件是绑定的而这个用来接收数据的组件实例A都销毁了回调函数也没了那这个自定义事件也就没用了你留着会污染全局环境。
beforeDestroy() {this.$bus.$off(hello)
}3、TodoList中的孙传父
之前我们孙传父都是父亲传给儿子函数儿子传给孙子函数然后孙子再调用函数传值很麻烦但是现在我们可以用全局事件总线实现孙子给父亲传数据。此处只展示修改部分记得把之前方法的相关代码删掉或注释掉。
1首先在main.js中安装全局事件总线
new Vue({el: #app,render: h h(App),beforeCreate() {Vue.prototype.$bus this; //创建全局事件总线}
});2在App.vue中绑定全局自定义事件并使用之前写好的回调
mounted() {//挂载完成后给全局事件总线添加事件this.$bus.$on(changeTodo, this.changeTodo);this.$bus.$on(deleteTodo, this.deleteTodo);
},
beforeDestroy() {//最好在销毁前解绑this.$bus.$off([changeTodo, deleteTodo]);
},3Item中触发事件并把数据id传过去
handleChange(id) {//触发全局事件总线中的事件this.$bus.$emit(changeTodo, id);
},
handleDelete(id) {if (confirm(确定要删除吗?)) //点确定是true,取消是falsethis.$bus.$emit(deleteTodo, id);
}消息的订阅与发布
1使用消息的订阅与发布
消息的订阅与发布用的不多和全局事件总线写法差不多但是全局事件总线更好因为是在Vue身上操作但是这个的话要引入第三方库库有很多比如pubsub-js
安装pubsubnpm i pubsub-js 引入import pubsub from pubsub-js
接收数据A组件想接收数据则在A组件中订阅消息订阅的回调留在A组件自身。 接收两个参数第一个是消息名字第二个是传过来的数据
methods(){demo(msgName,data){......}
}
......
mounted() {//订阅消息this.pubsubId pubsub.subscribe(xxx,this.demo)
},
beforeDestroy() {//销毁时取消订阅pubsub.unsubscribe(this.pubsubId);
},提供数据
methods: {sendStudentName() {// this.$bus.$emit(hello, this.name);//发布消息并传数据pubsub.publish(hello, this.name); }
},可以对比一下前面的全局事件总线写法个人认为写法差别不大。
可以尝试把TodoList案例里孙传父使用全局事件总线的写法改成使用消息订阅与发布试试。
2TodoList案例使用消息的订阅与发布
这里把**deleteTodo改成消息订阅与发布changeTodo依旧使用全局事件总线**大家可以仔细对比他们的区别。
App.vue(订阅消息/接收数据) mounted() {//挂载完成后给全局事件总线添加事件this.$bus.$on(changeTodo, this.changeTodo)// this.$bus.$on(deleteTodo, this.deleteTodo)//deleteTodo换一种方法 用订阅消息写this.pubsubIs pubsub.subscribe(deleteTodo, this.deleteTodo)},beforeDestroy() {//最好在销毁前解绑// this.$bus.$off([changeTodo, deleteTodo])//使用全局事件总线解绑this.$bus.$off(changeTodo)//deleteTodo换一种方法 用订阅消息解绑pubsub.unsubscribe(this.pubsubId)},这里别忘了这个subscribe里的回调接收两个参数第一个是消息名后面才是数据所以deleTodo方法得加个参数
//虽然msgName没用上但是如果不加就会把id当第一个参数id就变成msgName所以这里必须要加或者直接拿一个下划线_占位也行
deleteTodo(msgName, id) {this.todos this.todos.filter(todo todo.id ! id);},Item.vue发布消息/提供数据
handleChange(id) {//使用全局事件总线//触发全局事件总线中的事件this.$bus.$emit(changeTodo, id);
},
handleDelete(id) {//confirm点确定是true,取消是falseif (confirm(确定要删除吗?)) //使用消息订阅与发布发布消息pubsub.publish(deleteTodo, id); //发布消息
}TodoList的编辑功能
1、整体思路
首先得有一个按钮点击之后出现input框框里是todo.title而且原来的span要隐藏。然后修改完之后失去焦点会自动更新数据并且span出现input框隐藏。 除此之外还有个细节那就是点击编辑要自动获取焦点要不然会有一个小问题点击编辑然后突然不想改了还得手动点一下input再点下别的地方才会变回span
想实现span和input的来回切换就要给todo添加新的属性用来标识这个变换这里起名叫isEdit
所以大致思路给标签添加事件 点击编辑按钮切换span为input 失去焦点传数据 App收数据 解决焦点bug
2、给标签添加事件
1isEdit一上来是没有的所以todo.isEdit false再加上默认上来显示的是span所以span加个v-show“!todo.isEdit”input加个v-show“todo.isEdit” button加v-show!todo.isEdit是因为我们一般编辑时这个按钮应该消失才对所以和span一致
2由于props接过来的数据不能改所以使用单向数据绑定:value“todo.title”
3ref“inputTitle” 是为了方便后面拿到input元素然后操作它写的nextTick
4blurhandleBlur(todo, $event)是失去焦点时触发的事件用来给App传值
span v-show!todo.isEdit{{ todo.title }}/span
input
typetext
v-showtodo.isEdit
:valuetodo.title
refinputTitle
blurhandleBlur(todo, $event)button classbtn btn-edit clickhandleEdit(todo) v-show!todo.isEdit编辑/button给这个编辑按钮加个样式
.btn-edit {color: #fff;background-color: rgb(13, 166, 13);border: 1px solid green;margin-right: 5px;
}.btn-edit:hover {color: #fff;background-color: green;
}3、点击编辑按钮切换span为input
点击编辑给todo追加属性用来切换span为input。这里考虑到给todo追加属性的问题如果想要让Vue监测到这个属性那么必须使用$set来添加isEdit且默认值为true因为编辑的时候显示的是input啊想想v-showtodo.isEdit。
但是这里边有点儿问题如果已经添加过了isEdit那每次点击编辑按钮都会添加一次isEdit属性这样是不太好的所以要加个判断添加过了就改成true没添加过就添加个true handleEdit(todo) {if (todo.isEdit ! undefined) {console.log(todo里有isEdit属性了)todo.isEdit true;} else {console.log(todo里没有isEdit属性)this.$set(todo, isEdit, true);}this.$nextTick(function () {this.$refs.inputTitle.focus();})},4、失去焦点传数据
失去焦点首先input得变回span然后使用全局事件总线传值传值一定要传当前input框的value值因为这才是你修改后的值使用事件对象获取。当然别忘了id也要传
handleBlur(todo, e) {todo.isEdit false;if (!e.target.value.trim()) return alert(值不能为空); //trim去掉空格this.$bus.$emit(updateTodo, todo.id, e.target.value);
}5、App收数据
把input框里你写的东西拿过来给对应的todo.title
//6.实现编辑todo
methods: {......updateTodo(id, title) {this.todos.forEach((todo) {if (todo.id id) { todo.title title }});}}
mounted() {......//实现编辑功能接收数据this.$bus.$on(updateTodo, this.editTodo);
},
beforeDestroy() {//最好在销毁前解绑this.$bus.$off(updateTodo);
},$nextTick
1、语法this.$nextTick(回调函数) 2、作用在下一次 DOM 更新结束v-for循环结束后执行其指定的回调。 3、什么时候用当改变数据后要基于更新后的新DOM进行某些操作时如input自动获取焦点要在nextTick所指定的回调函数中执行。
4、比如刚才点击编辑后input框没法自动获取焦点那么我就得先点一下再点别处儿才能切换回去如果直接this.$refs.inputTitle.focus();不行因为这个函数虽然动了isEdit的值但是模板重新解析也得等这个函数走完啊那input还没创建出来呢就focus了肯定是不行滴。 有个办法就是用异步也可以解决但是更好的办法是$nextTick
动画与过渡
1、作用在插入、更新或移除 DOM元素时在合适的时候给元素添加样式类名。 2、写法
准备好样式
元素进入的样式 v-enter进入的起点 v-enter-active进入过程中 v-enter-to进入的终点
元素离开的样式 v-leave离开的起点 v-leave-active离开过程中 v-leave-to离开的终点
使用transition包裹要过度的元素并配置name属性
transition namehelloh1 v-showisShow你好啊/h1
/transition3、备注若有多个元素需要过度则需要使用transition-group且每个元素都要指定key值。
进入离开动画三种写法
1、动画Test.vue
templatedivbutton clickisShow !isShow显示/隐藏/buttontransition namehello appearh1 v-showisShow你好呀!/h1/transition/div
/templatescript
export default {name: Test,data() {return {isShow: true,}},
}
/scriptstyle scoped
h1 {background-color: pink;
}.hello-enter-active {animation: potato 1s;
}
.hello-leave-active {animation: potato 1s reverse;
}keyframes potato {from {transform: translateX(-100%);}to {transform: translateX(0px);}
}
/style2、过渡动画Test2.vue
templatedivbutton clickisShow !isShow显示/隐藏/buttontransition-group namehello appearh1 v-showisShow key1你好呀!/h1h1 v-showisShow key2小土豆/h1/transition-group/div
/templatescript
export default {name: Test2,data() {return {isShow: true,}},
}
/scriptstyle scoped
h1 {background-color: skyblue;
}/* 进入的起点,离开的终点 */
.hello-enter,
.hello-leave-to {transform: translateX(-100%);
}
/* 进入的终点,离开的起点 */
.hello-enter-to,
.hello-leave {transform: translateX(0);
}
.hello-enter-active,
.hello-leave-active {transition: 0.5s linear;
}
/style3、集成第三方动画
templatedivbutton clickisShow !isShow显示/隐藏/buttontransition-groupnameanimate__animated animate__bounceappearenter-active-classanimate__swingleave-active-classanimate__backOutUph1 v-showisShow key1你好呀!/h1h1 v-showisShow key2小土豆/h1/transition-group/div
/templatescript
import animate.css
export default {name: Test3,data() {return {isShow: true,}},
}
/scriptstyle scoped
h1 {background-color: orange;
}
/styleApp.vue
templatediv idAppTest /Test2 /Test3 //div
/templatescript
import Test from ./components/Test
import Test2 from ./components/Test2
import Test3 from ./components/Test3
export default {name: App,components: { Test, Test2, Test3 },
}
/script效果从上往下分别是Test、Test2、Test3效果