组件通信的6种方式

news2025/1/21 15:45:40

什么是组件通信

vue组件中关系说明:
在这里插入图片描述
如上图所示, A与B、A与C、B与D、C与E组件之间是父子关系; B与C之间是兄弟关系;A与D、A与E之间是隔代关系; D与E是堂兄关系(非直系亲属)

针对以上关系我们归类为:

  • 父子组件之间通信
  • 非父子组件之间通信(兄弟组件、隔代关系组件等)

因此介绍在不同的场景下如何选择有效方式实现的组件间通信方式,以更好理解组件间的通信。

组件通信的方式有哪些

1、props:用于父=》子组件通信

  • 父组件通过props的方式向子组件传递数据,而子组件通过$emit 可以向父组件通信。
  • 举例:子组件的props选项能够接收来自父组件数据。没错,仅仅只能接收,props是单向绑定的,即只能父组件向子组件传递,不能反向。而传递的方式也分为两种:

1、静态传递

子组件通过props选项来声明一个自定义的属性,然后父组件就可以在嵌套标签的时候,通过这个属性往子组件传递数据了。
<!-- 父组件 -->

<template>
 <div>
 <h1>我是父组件!</h1>
 <child message="我是子组件一!"></child> //通过自定义属性传递数据
 </div>
</template>
 
<script>
import Child from '../components/child.vue'
export default {
 components: {Child},
}
</script>
<!-- 子组件 -->
 
<template>
 <h3>{{message}}</h3>
</template>
<script>
 export default {
 props: ['message'] //声明一个自定义的属性
 }
</script>

2、动态传递

我们已经知道了可以像上面那样给 props 传入一个静态的值,但是我们更多的情况需要动态的数据。这时候就可以用 v-bind 来实现。通过v-bind绑定props的自定义的属性,传递去过的就不是静态的字符串了,它可以是一个表达式、布尔值、对象等等任何类型的值。

 <!-- 父组件 -->

<template>
 <div>
 <h1>我是父组件!</h1>
 <child message="我是子组件一!"></child>

 <!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
 <child v-bind:message="a+b"></child>

 <!-- 用一个变量进行动态赋值。-->
 <child v-bind:message="msg"></child>
 </div>
</template>

<script>
import Child from '../components/child.vue'
export default {
 components: {Child},
 data() {
 return {
  a:'我是子组件二!',
  b:112233,
  msg: '我是子组件三!'+ Math.random()
 }
 }
}
</script>
 <!-- 子组件 -->

<template>
 <h3>{{message}}</h3>
</template>
<script>
 export default {
 props: ['message']
 }
</script>


效果:
在这里插入图片描述

总结: prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。

2、自定义事件:@on,@emit 可以实现子给父通信即vm.$emit( event, arg )

  • $emit绑定一个自定义事件event,当这个这个语句被执行到的时候,就会将参数arg传递给父组件,父组件通过@event监听并接收参数。
//父组件
<template>
 <div>
 <h1>{{title}}</h1>
 <child @getMessage="showMsg"></child>
 </div>
</template>

<script>
 import Child from '../components/child.vue'
 export default {
 components: {Child},
 data(){
  return{
  title:''
  }
 },
 methods:{
  showMsg(title){
  this.title=title;
  }
 }
 }
</script>
<template>
 <h3>我是子组件!</h3>
</template>
<script>
 export default {
 mounted: function () {
  this.$emit('getMessage', '我是父组件!')
 }
 }
</script>

3、全局事件总线eventBus:$bus 全能

  • 对于比较小型的项目,没有必要引入 vuex 的情况下,可以使用 eventBus。
  • 它的实现思想也很好理解,在要相互通信的两个组件中,都引入同一个新的vue实例,然后在两个组件中通过分别调用这个实例的事件触发和监听来实现通信。
//eventBus.js
import Vue from 'vue';
export default new Vue();


<!--组件A-->
<script>
import Bus from 'eventBus.js';
export default {
    methods: {
        sayHello() {
            Bus.$emit('sayHello', 'hello');
        }
    }
}
</script>


<!--组件B-->
<script>
import Bus from 'eventBus.js';
export default {
    created() {
        Bus.$on('sayHello', target => {
            console.log(target);  // => 'hello'
        });
    }
}
</script>

4、pubsub-js:vue当中几乎不用(因为vue中有全局事件总线和这个第三方提供的库功能重复) 但全能

  • 含义:消息订阅与发布
    -(由于原生js实现较困难,推荐用第三方库pubsub-js (npm i pubsub-js

  • 理解:需要消息的人=》订阅消息subscribe,
    发布消息的人=》发布消息publish

  • 实现:需要消息的人:import pubsub from "pubsub-js",并在mouted(){this.pubId=pubsub.subscribe('hello‘,function(msgName,data){console.log(‘有人发布了hello消息,hello消息的回调执行了’,msgName,data) })}
    发布消息的人:import pubsub from "pubsub-js",在事件函数里methods:{xxxx事件(){ pubsub.publish(‘hello’,666)}}
    效果:有人发布了hello消息,hello消息的回调执行了 hello 666

  • 取消订阅: pubsub.unsubscribe('this.pubId')(即需要指定哪个id的消息被取消订阅)

5、插槽

  • 插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。

1、以最简单插槽为例:在子组件中放一个占位符

//子组件
<template>
    <div>
        <h1>今天天气状况:</h1>
        <slot></slot>
    </div>
</template>
<script>
    export default {
        name: 'child'
    }
</script>

2、在父组件中给这个占位符填充内容

//父组件
<template>
    <div>
        <div>使用slot分发内容</div>
        <div>
            <child>
                <div style="margin-top: 30px">多云,最高气温34度,最低气温28度,微风</div>
            </child>
        </div>
    </div>
</template>
<script>
    import child from "./child.vue";
    export default {
        name: 'father',
        components:{
            child
        }
    }
</script>

3、展示效果:
在这里插入图片描述

  • 但如果没有用插槽,则数据传递不进来,没有多云那一行

总结:如果子组件没有使用插槽,父组件如果需要往子组件中填充模板或者html, 是没法做到的。

插槽使用 - 具名插槽

描述:具名插槽其实就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中。代码如下:

1、子组件的代码,设置了两个插槽(header和footer):

<template>
    <div>
        <div class="header">
            <h1>我是页头标题</h1>
            <div>
                <slot name="header"></slot>
            </div>
        </div>
        <div class="footer">
            <h1>我是页尾标题</h1>
            <div>
                <slot name="footer"></slot>
            </div>
        </div>
    </div>
</template>
 
<script>
    export default {
        name: "child1"
    }
</script>
 
<style scoped>
 
</style>

2、父组件填充内容, 父组件通过 v-slot:[name] 的方式指定到对应的插槽中

<template>
<div>
    <div>slot内容分发</div>
    <child1>
        <template slot="header">
            <p>我是页头的具体内容</p>
        </template>
        <template slot="footer">
            <p>我是页尾的具体内容</p>
        </template>
    </child1>
</div>
</template>
 
<script>
    import child1 from "./child1.vue";
 
    export default {
        name: "father1",
        components: {
            child1
        }
    }
</script>
 
<style scoped>
 
</style>

展示效果如下:
在这里插入图片描述

6、vuex

Vuex 核心

  • State:保存所有组件的共享状态
  • Getters:类似状态值的计算属性
  • Mutations:修改 State中状态值的唯一方法,里面包含状态变化监听器和记录器
  • Actions:用于异步处理 State中状态值,异步函数结束后调用Mutations
  • Modules:当一个 State 对象比较庞大时,可以将 State 分割成多个Modules 模块。

总结

1.可以实现任意组件的通信的方法有两个:事件总线Vuex,事件总线难维护数据但轻量,Vux维护数据方便但比较重量。
2.可以实现父与子孙跨越层级通信的方法也有两个:$attrs/$listenersprovide/inject$attrs/$listeners 具有响应性且可以双向通信, provide/inject 无响应性且只能单向通信(父传子)
3.只能实现父与子组件通信的方法有一个:props/emit,方法比较基础,适合只有父子组件通信的方法,若想跨层级通信需要中间组件做转发,比较麻烦。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端跨域解决方案

文章目录1.同源政策2.跨域解决方案2.1 CORS普通跨域请求&#xff1a;只需服务端设置Access-Control-Allow-Origin即可携带cookie跨域请求&#xff1a;前后端都需设置2.2 JSONP原理缺点数据格式jsonp跨域实现2.3 postMessage跨域2.4 WebSocket属性&#xff1a;事件&#xff1a;使…

vue3+vite:本地代理,配置proxy

一、项目&#xff1a;uniappvue3vitets 二、配置文件在vite.config.ts proxy: {/snow: { // 匹配请求路径&#xff0c;localhost:3000/snowtarget: https://www.snow.com/, // 代理的目标地址changeOrigin: true, // 开发模式&#xff0c;默认的origin是真实的 origin:localh…

压缩gltf/glb模型踩坑与解决 three.js DRACOLoader

前言 使用前端three.js加载3d模型过程中&#xff0c;往往会出现模型大小过大导致前端加载时间过长&#xff0c;降低用户体验。 本文所记录的是笔者在使用gltf-pipeline压缩3d模型中踩坑DRACOLoader与解决的一个过程。 所采用的three库版本为 ^0.138.2 解决方案与介绍 通过g…

31.JavaScript数组进阶,一网打尽数组操作函数slice、filter、map、reduce、some、every、find、splice

文章目录数组进阶元素删除&#xff08;对象方式&#xff09;splice()删除一个元素删除多个元素截断数组元素替换元素插入返回值负索引slice()concat()forEach()indexOf、lastIndexOf、includesfind、findIndexfiltermapsortreversestr.split()和arr.join()reduce、reduceRightA…

vue在html标签 {{}} 中调用函数的方法

目录 一、问题 1&#xff09;实现上述需求&#xff1a;有两种方式 2&#xff09;两种实现方式对比&#xff1a; 二、解决方法&#xff08;在html渲染时调用函数&#xff09; 三、总结 注&#xff1a;不想仔细看的&#xff0c;可以直接看有颜色的及代码哟 一、问题 1.在ht…

关于 HbuilderX 运行项目到手机,搜索不到手机解决

注意 本文内&#xff0c;我的 HbuilderX 安装目录都是在 D:\app 目录下&#xff0c;所有关于本文的操作文件都是在 HbuilderX 安装包内。 第一步&#xff1a;打开环境变量&#xff0c;找到系统变量&#xff0c;然后点击编辑。 第二部&#xff1a;配置 HbuilderX 的 adbs 目录…

JS中的位运算

目录 JS中的位运算 JS中的与运算 JS中的或运算 JS中的否&#xff08;非&#xff09;运算 计算机中负数的存储方式 JS中的异或运算 JS中位运算的应用场景 位的叠加&#xff08;开关&#xff09; JS中的位移运算 左位移 右位移 全右位移 首先了解一下什么是位运算 位…

Vite 配置篇:日常开发掌握这些配置就够了!

不知道有没有这样的兄弟&#xff0c;学习 Vite 的时候&#xff0c;官网上各种配置看的是眼花缭乱。不知道哪些需要掌握&#xff0c;哪些只用简单了解一下。为了提高大家的效率&#xff0c;我把项目中常用的配置梳理了一下分享给大家&#xff0c;希望对你上手 Vite 有所帮助。话…

若依框架前端切换TagView时刷新问题

若依框架点击顶部tag切换时&#xff0c;永远都是刷新的。刷新问题两种情况&#xff1a;普通view切换时刷新及iFrame切换刷新 一、普通view切换时刷新 原因是view的name与在菜单填写的大小写不一致&#xff0c;按若依框架规则&#xff0c;路由地址必须写为 camel 驼峰命名形式&…

前端:Tomcat服务器部署Web项目

文章目录1.1 C/S架构1.2 B/S架构2.1 服务器2.2 常见服务器3.1 Tomcat安装3.2 Tomcat使用3.3 Tomcat配置3.4 Tomcat项目部署4.1 Servlet技术4.2 Servlet配置4.3 配置测试4.4 Servlet部署5.1 IDEA部署1.1 C/S架构 Client / Server客户端/服务器 客户端作为独立程序 图形效果较好…

【面试题】面试官: Vue如何实现权限管理?

我正在参加「掘金启航计划」 一、权限管理 权限管理就是让不同的用户只能访问自己权限内的资源&#xff0c;有以下几种 路由权限&#xff0c;用户登录后只能看到自己权限内的导航菜单&#xff0c;且只能访问自己权限内的路由地址视图权限&#xff0c;用户只能看到自己权限内…

为你心仪的她做一个 “旋转木马“告白相册【零基础纯 CSS3 实现】

&#x1f4b3; 效果展示&#xff1a; 旋转相册效果里面就不放女朋友的美照了防止虐狗 &#x1f970;&#x1f970;&#x1f970;&#xff0c;就用个前端技能树的图片代替哈&#xff0c;有需要大家自行替换。 &#x1f4b3; 源码获取&#xff1a; 源码我已经上传到了资源里&…

Django web开发(二) - Mysql数据库

文章目录Mysql数据库Mysql的安装(CentOS7)下载修改配置文件Mysql强制重置密码远程可登录数据库管理数据表的管理常用数据类型数据管理添加数据查询数据删除数据修改数据员工管理Python管理数据库添加数据查询数据删除数据修改数据案例: Flask Mysql案例: 查询所有用户Mysql数据…

Three.js 渲染glb,gltf模型(保姆级教程)

1.准备工作 将下列文件在three.js的包中找到&#xff0c;注意的是我这里使用的是模块化版本的&#xff0c;这里不知道模块化的&#xff0c;可以先去看一下es6的模块化。 控制器&#xff1a; OrbitControls.js 加载器&#xff1a;GLTFLoader.js 材质&#xff1a; RoomEnviron…

echarts折线图流动特效的实现(非平滑曲线)

1.实现效果 2.实现原理 echarts官网&#xff1a;series-lines 注意&#xff1a;流动特效只支持非平滑曲线&#xff08;smooth&#xff1a;false&#xff09; series-lines路径图&#xff1a; 用于带有起点和终点信息的线数据的绘制&#xff0c;主要用于地图上的航线&#xff…

若依框架:前端登录组件与图像验证码

在上一篇《若依框架&#xff1a;前端项目结构与初始页面渲染流程》中&#xff0c;我们探讨了与“vue.config.js文件配置、.env模式和环境变量配置、vue-router全局导航守卫配置、vue-router路由配置简介”相关的内容&#xff0c;书接上回&#xff0c;我们继续探讨若依前端项目的…

前端实现在线预览Word文件

简介 在项目中遇到了个需求&#xff0c;大致需求这样的&#xff1a;用户在上传文件前需要先预览一下内容&#xff0c;确认内容是否正确&#xff0c;正确的情况下才可以上传&#xff1b; 那么这里面会涉及到一个在上传前的文档的预览操作&#xff0c;下面就记录一下踩坑记录 d…

uni-app ——使用uploadFile上传多张图片

前言&#xff1a;最近的工作中出现了一个功能点&#xff0c;具体写法我在前面的文章中已经阐述过&#xff0c;不过之前的情况是上传图片调用后端的一个接口&#xff0c;整个表单页面提交的时候调用的是另一个接口&#xff0c;我也从中学到了另外的一种方法&#xff0c;写到这里…

UniApp Scroll-View 设置占满下方剩余高度的方法小记

前言&#xff1a;点滴积累&#xff0c;贵在坚持一、布局描述&#xff1a;屏幕分为上下两部分&#xff0c;上面部分高度固定&#xff0c;比如 400rpx&#xff08;单位可以指定为其他的比如px、upx等&#xff0c;高度也可以自己设定&#xff09;&#xff0c;下面部分为 scroll-vi…

css渐变

1. 线性渐变&#xff08;是从一个方向到另一个方向的渐变&#xff09; 属性值&#xff1a;background&#xff1a;linear-gradient&#xff08;颜色&#xff09; ✍默认值&#xff1a;从上到下线性渐变&#xff1a; 代码&#xff1a; 结果&#xff1a; ✍ 属性延伸&#x…