Vue学习之--------消息订阅和发布、基础知识和实战应用(2022/8/24)

简介: 这篇文章介绍了Vue中消息订阅和发布的机制,作为组件间通信的一种方式,特别适用于任意组件间的通信。文章通过基础知识讲解和具体的代码实例,展示了如何使用`pubsub-js`库来安装、订阅、发布消息,并在组件销毁前取消订阅以避免内存泄漏。

文章目录

  • 1、基础知识
  • 2、代码实例
    • 2.1 main.js
    • 2.2 School.vue
    • 2.3 Student.vue
    • 2.4 App.vue
  • 3、全局事件总线通信改为消息的订阅和发布
    • 3.1 核心部分代码
    • 3.1.1 TheItem.vue(样式省略)、发布消息
    • 3.1.2 App.vue 订阅消息
  • 4、测试结果说明

1、基础知识

类别引用说明:订阅报纸。用户作为订阅者订购报纸,邮局派送报纸。

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

2、使用步骤:

  1. 安装pubsub:npm i pubsub-js(安装不成功、使用管理员权限运行)
    在这里插入图片描述

  2. 引入: import pubsub from 'pubsub-js'(订阅和发布都要引入)
    3.

3、接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
      }

4、提供数据:pubsub.publish('xxx',数据)(这里的传参传两个、第一个是订阅名、第二个是数据)

5、最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。

2、代码实例

实现的效果:student组件中的信息发送到School组件中。student作为信息的发布者,School组件订阅信息。

2.1 main.js

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false

//创建vm
new Vue({
    el:'#app',
    render: h => h(App),
})

2.2 School.vue

<template>
    <div class="school">
        <h2>学校名称:{
  
  {name}}</h2>
        <h2>学校地址:{
  
  {address}}</h2>
    </div>
</template>

<script>
    import pubsub from 'pubsub-js'
    export default {
        name:'School',
        data() {
            return {
                name:'尚硅谷',
                address:'北京',
            }
        },
        mounted() {
            // console.log('School',this)
            /* this.$bus.$on('hello',(data)=>{
                console.log('我是School组件,收到了数据',data)
            }) */
            this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
                console.log(this)
                // console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
            })
        },
        beforeDestroy() {
            // this.$bus.$off('hello')
            pubsub.unsubscribe(this.pubId)
        },
    }
</script>

<style scoped>
    .school{
        background-color: skyblue;
        padding: 5px;
    }
</style>

2.3 Student.vue

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

<script>
    import pubsub from 'pubsub-js'
    export default {
        name:'Student',
        data() {
            return {
                name:'张三',
                sex:'男',
            }
        },
        mounted() {
            // console.log('Student',this.x)
        },
        methods: {
            sendStudentName(){
                // this.$bus.$emit('hello',this.name)
                pubsub.publish('hello',666)
            }
        },
    }
</script>

<style lang="less" scoped>
    .student{
        background-color: pink;
        padding: 5px;
        margin-top: 30px;
    }
</style>

2.4 App.vue

<template>
    <div class="app">
        <h1>{
  
  {msg}}</h1>
        <School/>
        <Student/>
    </div>
</template>

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

    export default {
        name:'App',
        components:{School,Student},
        data() {
            return {
                msg:'你好啊!',
            }
        }
    }
</script>

<style scoped>
    .app{
        background-color: gray;
        padding: 5px;
    }
</style>

3、全局事件总线通信改为消息的订阅和发布

全局事件总线实现组件间通信:https://blog.csdn.net/weixin_43304253/article/details/126475369

3.1 核心部分代码

这里只修改一处、删除列表项的数据方式改为消息订阅和发布的形式

3.1.1 TheItem.vue(样式省略)、发布消息

消息发布、将要删除的id传递给App.vue

<template>
  <li>
    <label>
      <input
        type="checkbox"
        :checked="todo.done"
        @change="handleCheck(todo.id)"
      />
      <span>{
  
  { todo.title }}</span>
    </label>
    <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
  </li>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
  name: "MyItem",
  //声明接收todo、checkTodo、deleteTodo
  props: ["todo"],

  methods: {
    //勾选or取消勾选
    handleCheck(id) {
      //通知App组件将对应的todo对象的done值取反
    //   this.checkTodo(id);
      this.$bus.$emit('checkTodo',id)
    },
    //删除
    handleDelete(id) {
      if (confirm("确定删除吗?")) {
        //通知App组件将对应的todo对象删除
        // this.deleteTodo(id);
        // this.$bus.$emit('deleteTodo',id)
        // 消息发布
        pubsub.publish('deleteTodo',id)
      }
    },
  },
};
</script>

3.1.2 App.vue 订阅消息

<template>
  <div id="root">
    <div class="todo-container">
      <div class="todo-wrap">
        <TheHeader @addTodo="addTodo" />
        <TheList :todos="todos" />
        <TheFooter
          :todos="todos"
          @checkAllTodo="checkAllTodo"
          @clearAllTodo="clearAllTodo"
        />
      </div>
    </div>
  </div>
</template>

<script>
import TheHeader from "./components/TheHeader";
import TheList from "./components/TheList";
import TheFooter from "./components/TheFooter.vue";
import pubsub from "pubsub-js";
export default {
  name: "App",
  components: { TheHeader, TheList, TheFooter },
  data() {
    return {
      msg: "你好啊!",
      studentName: "",
      //由于todos是MyHeader组件和MyFooter组件都在使用,所以放在App中(状态提升)
      todos: JSON.parse(localStorage.getItem("todos")) || [],
      // todos: [
      //   { id: "001", title: "吃饭", done: true },
      //   { id: "002", title: "睡觉", done: false },
      //   { id: "003", title: "打豆豆", done: true },
      // ],
    };
  },
  methods: {
    //添加一个todo
    addTodo(todoObj) {
      this.todos.unshift(todoObj);
    },
    //勾选or取消勾选一个todo
    checkTodo(id) {
      this.todos.forEach((todo) => {
        if (todo.id === id) todo.done = !todo.done;
      });
    },

    //删除一个todo
    deleteTodo(_, id) {
      this.todos = this.todos.filter((todo) => todo.id !== id);
    },
    //全选or取消全选
    checkAllTodo(done) {
      this.todos.forEach((todo) => {
        todo.done = done;
      });
    },
    //清除所有已经完成的todo
    clearAllTodo() {
      this.todos = this.todos.filter((todo) => {
        return !todo.done;
      });
    },
  },

  watch: {
    todos: {
      deep: true,
      handler(value) {
        localStorage.setItem("todos", JSON.stringify(value));
      },
    },
  },
  mounted() {
    this.$bus.$on("checkTodo", this.checkTodo);
    // this.$bus.$on('deleteTodo',this.checkTodo)
    //订阅消息、调用方法里边的函数、参数两个。第一个订阅消息名称、第二个是数据。也可以直接写成箭头函数
    this.pubId = pubsub.subscribe("deleteTodo", this.deleteTodo);
  },
  beforeDestroy() {
    this.$bus.$off("checkTodo");
    //  this.$bus.$off('deleteTodo')
    // 取消订阅
    pubsub.unsubscribe(this.pubId);
  },
};
</script>

4、测试结果说明

在这里插入图片描述
在这里插入图片描述

相关文章
|
2月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
301 2
|
1月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
280 137
|
4月前
|
人工智能 JSON JavaScript
VTJ.PRO 首发 MasterGo 设计智能识别引擎,秒级生成 Vue 代码
VTJ.PRO发布「AI MasterGo设计稿识别引擎」,成为全球首个支持解析MasterGo原生JSON文件并自动生成Vue组件的AI工具。通过双引擎架构,实现设计到代码全流程自动化,效率提升300%,助力企业降本增效,引领“设计即生产”新时代。
403 1
|
4月前
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
259 0
|
5月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
778 0
|
7月前
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
1010 4
|
5月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
6月前
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
835 77
|
7月前
|
缓存 JavaScript 前端开发
Vue 基础语法介绍
Vue 基础语法介绍
|
5月前
|
JavaScript 前端开发 开发者
Vue 自定义进度条组件封装及使用方法详解
这是一篇关于自定义进度条组件的使用指南和开发文档。文章详细介绍了如何在Vue项目中引入、注册并使用该组件,包括基础与高级示例。组件支持分段配置(如颜色、文本)、动画效果及超出进度提示等功能。同时提供了完整的代码实现,支持全局注册,并提出了优化建议,如主题支持、响应式设计等,帮助开发者更灵活地集成和定制进度条组件。资源链接已提供,适合前端开发者参考学习。
465 17