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、测试结果说明

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

相关文章
|
6天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
6天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
5天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
5天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
JavaScript 测试技术 容器
Vue2+VueRouter2+webpack 构建项目
1). 安装Node环境和npm包管理工具 检测版本 node -v npm -v 图1.png 2). 安装vue-cli(vue脚手架) npm install -g vue-cli --registry=https://registry.
1050 0
|
6天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
6天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
7天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
7天前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
12天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发