Vue2-全局事件总线、消息的订阅与发布、TodoList的编辑功能、$nextTick、动画与过渡

🥔:高度自律即自由

更多Vue知识请点击——Vue.js

VUE2-Day9

    • 全局事件总线
      • 1、安装全局事件总线
      • 2、使用事件总线
        • (1)接收数据
        • (2)提供数据
        • (3)组件销毁前最好解绑
      • 3、TodoList中的孙传父
        • (1)首先在main.js中安装全局事件总线
        • (2)在App.vue中绑定全局自定义事件,并使用之前写好的回调
        • (3)Item中触发事件,并把数据id传过去
    • 消息的订阅与发布
      • (1)使用消息的订阅与发布
      • (2)TodoList案例使用消息的订阅与发布
    • TodoList的编辑功能
      • 1、整体思路
      • 2、给标签添加事件
      • 3、点击编辑按钮切换span为input
      • 4、失去焦点传数据
      • 5、App收数据
    • $nextTick
    • 动画与过渡
      • 进入离开动画三种写法

全局事件总线

一种组件间通信的方式,适用于任意组件间通信。通俗理解就是一个定义在所有组件之外的公共嘎达,这个嘎达可以有vm或vc上的同款$on、$off、$emit,也可以让所有组件都访问到。要想实现这个事情,只能在Vue.prototype上添加一个属性,值是vm或vc

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3OYNFD4-1692378989491)(D:\wxf\前端学习笔记\vue2+vue3\笔记图片\全局事件总线.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']);
},

(3)Item中触发事件,并把数据id传过去

handleChange(id) {
    //触发全局事件总线中的事件
    this.$bus.$emit('changeTodo', id);
},
handleDelete(id) {
    if (confirm('确定要删除吗?'))  //点确定是true,取消是false
        this.$bus.$emit('deleteTodo', id);
}

消息的订阅与发布

(1)使用消息的订阅与发布

消息的订阅与发布用的不多,和全局事件总线写法差不多,但是全局事件总线更好,因为是在Vue身上操作,但是这个的话要引入第三方库,库有很多,比如pubsub-js

安装pubsub:npm 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案例里孙传父使用全局事件总线的写法改成使用消息订阅与发布试试。

(2)TodoList案例使用消息的订阅与发布

这里把**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,取消是false
    if (confirm('确定要删除吗?')) 
        //使用消息订阅与发布发布消息
        pubsub.publish('deleteTodo', id);  //发布消息
}

TodoList的编辑功能

1、整体思路

首先得有一个按钮,点击之后出现input框,框里是todo.title,而且原来的span要隐藏。然后修改完之后,失去焦点会自动更新数据,并且span出现,input框隐藏。
除此之外还有个细节,那就是点击编辑要自动获取焦点,要不然会有一个小问题(点击编辑,然后突然不想改了,还得手动点一下input,再点下别的地方,才会变回span)

想实现span和input的来回切换,就要给todo添加新的属性,用来标识这个变换,这里起名叫isEdit

所以大致思路:给标签添加事件 => 点击编辑按钮切换span为input => 失去焦点传数据 => App收数据 => 解决焦点bug

2、给标签添加事件

(1)isEdit一上来是没有的,所以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”

(3)ref=“inputTitle” 是为了方便后面拿到input元素然后操作它写的(nextTick)

(4)@blur="handleBlur(todo, $event)"是失去焦点时触发的事件,用来给App传值

<span v-show="!todo.isEdit">{{ todo.title }}</span>
<input 
type="text" 
v-show="todo.isEdit" 
:value="todo.title" 
ref="inputTitle" 
@blur="handleBlur(todo, $event)">
 <button class="btn btn-edit" @click="handleEdit(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-show="todo.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 name="hello">
	<h1 v-show="isShow">你好啊!</h1>
</transition>

3、备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。

进入离开动画三种写法

  • 1、动画(Test.vue)
<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <transition name="hello" appear>
      <h1 v-show="isShow">你好呀!</h1>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'Test',
  data() {
    return {
      isShow: true,
    }
  },
}
</script>

<style 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);
  }
}
</style>
  • 2、过渡动画(Test2.vue)
<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <transition-group name="hello" appear>
      <h1 v-show="isShow" key="1">你好呀!</h1>
      <h1 v-show="isShow" key="2">小土豆</h1>
    </transition-group>
  </div>
</template>

<script>
export default {
  name: 'Test2',
  data() {
    return {
      isShow: true,
    }
  },
}
</script>

<style 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;
}
</style>
  • 3、集成第三方动画
<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <transition-group
      name="animate__animated animate__bounce"
      appear
      enter-active-class="animate__swing"
      leave-active-class="animate__backOutUp"
    >
      <h1 v-show="isShow" key="1">你好呀!</h1>
      <h1 v-show="isShow" key="2">小土豆</h1>
    </transition-group>
  </div>
</template>

<script>
import 'animate.css'
export default {
  name: 'Test3',
  data() {
    return {
      isShow: true,
    }
  },
}
</script>

<style scoped>
h1 {
  background-color: orange;
}
</style>
  • App.vue
<template>
  <div id="App">
    <Test />
    <Test2 />
    <Test3 />
  </div>
</template>

<script>
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效果)
    请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/84607.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

乖宝宠物上市,能否打破外资承包中国宠物口粮的现实

近日&#xff0c;乖宝宠物上市了&#xff0c;这是中国宠物行业成功挂牌的第三家公司。同时&#xff0c;昨日&#xff0c;宠物行业最大的盛事“亚洲宠物展”时隔3年&#xff0c;于昨日在上海成功回归。 这两件事情的叠加可谓是双喜临门&#xff0c;行业能够走到今天实属不易&…

java网络编程

目录 1. 什么是网络编程? 2. 网络编程三要素 2.1 IP 2.1.1 常见CMD命令 2.1.2 InetAddress 2.2 端口号 2.3 协议 3. UDP通信程序 3.1 UDP的三种通信方式 4. TCP通信程序 4.1 三次握手四次挥手 1. 什么是网络编程? 在网络通信协议下&#xff0c;不同计算机上运行的程…

生成式AI和大语言模型 Generative AI LLMs

在“使用大型语言模型(LLMs)的生成性AI”中&#xff0c;您将学习生成性AI的基本工作原理&#xff0c;以及如何在实际应用中部署它。 通过参加这门课程&#xff0c;您将学会&#xff1a; 深入了解生成性AI&#xff0c;描述基于LLM的典型生成性AI生命周期中的关键步骤&#xff…

基于Java的ssm菜匣子优选系统源码和论文

基于Java的ssm菜匣子优选系统039 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&…

unity发布WebGL遇到的坑(持续更新)

1、unity默认字体在网页中不会显示 解决方法&#xff1a;自己新导入一个字体&#xff0c;使用导入的字体 2、之前打过包并运行过&#xff0c;后面又在unity中进行了修改&#xff0c;重新打包&#xff0c;运行发现还是修改之前的效果&#xff0c;虽然是新包&#xff0c; 解决方…

Linux下gdb调试

1.基本命令操作 2.调试方式启动运行无参程序 以下是linux下GDB调试的一个实例&#xff0c;先给出一个示例用的小程序&#xff0c;C语言代码&#xff1a; main.c #include <stdio.h>void Print(int i){printf("hello,程序猿编码 %d\n", i); }int main(int argc…

Python爬虫解析工具之xpath使用详解

文章目录 一、数据解析方式二、xpath介绍三、环境安装1. 插件安装2. 依赖库安装 四、xpath语法五、xpath语法在Python代码中的使用 一、数据解析方式 爬虫抓取到整个页面数据之后&#xff0c;我们需要从中提取出有价值的数据&#xff0c;无用的过滤掉。这个过程称为数据解析&a…

【实战】十一、看板页面及任务组页面开发(三) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十五)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…

GB28181国标平台测试软件NTV-GBC(包含服务器和模拟客户端)

GB28181国标平台测试软件NTV-GBC用于对GB28181国标平台进行测试(测试用例需要服务器软件&#xff0c;服务器软件可以是任何标准的国标平台&#xff0c;我们测试使用的是NTV-GBS&#xff09;&#xff0c;软件实现了设备注册、注销、目录查询&#xff0c;消息订阅、INVITE&#x…

剑指offer(C++)-JZ64:求1+2+3+...+n(算法-位运算)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&…

STL---list

目录 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用注意事项 2.list接口介绍及模拟实现 2.1构造​编辑 2.2容量 2.3修改 3.list迭代器 4.迭代器失效 5.模拟实现 6.vector和list的区别 1. list的介绍及使用 1.1 list的介绍 list的文档介绍 1. list是可以在常…

回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&a…

探索智能文字识别:技术、应用与发展前景

探索智能文字识别&#xff1a;技术、应用与发展前景 前言一张图全览大赛作品解读随心记你不对我对小结 智能文字识别体系化解读图像预处理文字定位和分割文字区域识别图像校正字体识别和匹配结果后处理小结 如何应对复杂场景下挑战复杂场景应对方法小结 人才时代对人才要求合合…

Facebook AI mBART:巴别塔的硅解

2018年&#xff0c;谷歌发布了BERT&#xff08;来自transformers的双向编码器表示&#xff09;&#xff0c;这是一种预训练的语言模型&#xff0c;在一系列自然语言处理&#xff08;NLP&#xff09;任务中对SOTA结果进行评分&#xff0c;并彻底改变了研究领域。类似的基于变压器…

Linux 上 离线部署GeoScene Server Py3 运行时环境

默认安装ArcGIS Pro的时候&#xff0c;会自动部署上Python3环境&#xff0c;所以在windows上不需要考虑这个问题&#xff0c;但是linux默认并不部署Py3&#xff0c;因此需要单独部署&#xff0c;具体部署可以参考Linux 上 ArcGIS Server 的 Python 3 运行时—ArcGIS Server | A…

亚马逊买家怎么留评

亚马逊买家可以按照以下步骤在购买后留下产品评价&#xff1a; 1、登录亚马逊账户&#xff1a;首先&#xff0c;在网页浏览器中打开亚马逊网站&#xff0c;登录你的亚马逊账户。 2、找到订单&#xff1a;在页面上找到并点击你购买过的商品的"我的订单"或"订单…

手机自动无人直播,实景无人直播真的有用吗?

继数字人直播之后&#xff0c;手机自动直播开始火热了起来&#xff0c;因为其门槛低&#xff0c;成本低&#xff0c;一部手机一个账号就可以实现直播&#xff0c;一时深受广大商家的好评。那么&#xff0c;手机自动无人直播究竟是如何实现自动直播的呢&#xff1f; 在传统的直…

Dockerfile快速搭建自己专属的LAMP环境

目录 编写Dockerfile 1.文件内容需求&#xff1a; 2.值得注意的是centos6官方源已下线&#xff0c;所以需要切换centos-vault源&#xff01; 3.Dockerfile内容 4.进入到 lamp 开始构建镜像 推送镜像到私有仓库 1.创建用户并添加到私有仓库&#xff1a;​编辑​编辑 2.推…

万宾科技22款产品入选《城市生命线安全工程监测技术产品名录》

2023年8月17日-18日&#xff0c;由北京市地下管线协会主办的2023首届城市生命线安全与发展大会在北京召开&#xff0c;本次大会汇聚中央及地方政府主管领导、院士专家、行业领袖、龙头代表、产业精英等。 大会聚焦安全监管智慧平台和燃气爆炸、城市内涝、地下管线交互风险、第三…

【云原生,k8s】Helm应用包管理器介绍

目录 一、为什么需要Helm&#xff1f; &#xff08;一&#xff09;Helm介绍 &#xff08;二&#xff09;Helm有3个重要概念&#xff1a; &#xff08;三&#xff09;Helm特点 二、Helm V3变化 &#xff08;一&#xff09;架构变化 &#xff08;二&#xff09;自动创建名…