vue 组件间通信方式

目录

1、props传递数据(父 → 子)

2、v-model(双向绑定)

3、.sync(双向绑定)

4、ref(使用 ref 属性获取子组件的实例或 DOM 元素)

5、$emit / v-on(子组件向父组件发送数据)

6、$attrs 和 $listeners(vue3废弃) (父组件向子组件传递非props数据与事件)

7、$children(vue3废弃) & $parent(通过父/子组件实例的引用进行通讯)

8、provide / inject (祖先组件向后代组件传送数据)

9、EventBus(使用 Vue 实例作为事件总线,在组件之间传递数据)

10、vuex(用于管理大型应用程序中的状态管理)

11、插槽 slot

默认插槽

具名插槽

作用域插槽

12、$root

13、Teleport:在DOM树中任意位置渲染组件


1、props传递数据(父 → 子)

在父组件子组件添加自定义属性,挂载需要传递的数据,子组件用 props 来接受,接收方式也可以是数组,也可以是对象,子组件接收到数据之后,不能直接修改父组件的数据。会报错,所以当父组件重新渲染时,数据会被覆盖。如果子组件内要修改的话推荐使用 $emit

// Parent.vue
<template><child :msg="msg"></child>
</template>
​
// Child.vue
export default {// 写法一 用数组接收props: ['msg'],// 写法二 用对象接收,可以限定接收的数据类型、设置默认值、验证等props: { msg: {type: String,default: '这是默认数据'}},mounted() {console.log(this.msg)},
}

2、v-model(双向绑定)

v-model 实际上是语法糖,它通过绑定 value 属性和监听 input 事件来实现双向绑定。当子组件的输入(即 value)发生变化时,触发 input 事件,父组件监听到这个事件后更新相应的数据,从而实现数据的双向同步。

// Parent.vue
<template><child v-model="msg"></child>
</template>
<script>
import Child from './Child.vue'
export default {components: { Child},data() {return {msg: ''}}
};
</script>
​
// Child.vue
<template><input :value="value" @input="$emit('input', $event)" />
</template>
<script>
export default {props: ["value"],
};
</script>

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 属性用于不同的目的。model 选项可以用来避免这样的冲突

// Parent.vue
<template><child v-model='count'></child>
</template>
<script>
import Child from './Child.vue'
export default {components: { Child},data() {return {count: 1}}
};
</script>
​
// Child.vue
<template><input :value="num" @input="$emit('change', $event)" />
</template>
<script>
export default {model: {prop: 'num',event: 'change'}props: ["num"],
};
</script>

3、.sync(双向绑定)

可以帮我们实现父组件向子组件传递的数据 的双向绑定,所以子组件接收到数据后可以直接修改,并且会同时修改父组件的数据

// Parent.vue
<template><child :msg.sync="msg"></child>
</template>
<script>
import Child from './Child.vue'
export default {components: { Child},data() {return {msg: ''}}
};
</script>
​
// Child.vue
<template><input :value="msg" @input="$emit('update:msg', $event)" />
</template>
<script>
export default {props: ["msg"],
};
</script>

4、ref(使用 ref 属性获取子组件的实例或 DOM 元素)

ref 如果在普通的 DOM 元素上,引用指向的就是该 DOM 元素;

如果在子组件上,引用的指向就是子组件实例,然后父组件就可以通过 ref 主动获取子组件的属性或者调用子组件的方法

// Parent.vue
<template><child ref='child'></child>
</template>
<script>
import Child from './Child.vue'
export default {components: { Child},data() {return {}},mounted() {const child = this.$refs.child;// 获取子组件的数据console.log(child.str); child.fn("调用子组件的方法");}
};
</script>
​
// Child.vue
<template><input type="text" />
</template>
<script>
export default {data() {return {str: "我是 Child",};},methods: {fn(str) {console.log(str);},},
};
</script>

5、$emit / v-on(子组件向父组件发送数据)

在父组件中给子组件绑定自定义事件,然后调用需要的方法,然后在子组件中用 this.$emit 触发父组件的事件,第一个是事件名,第二个是参数

// Parent.vue
<template><child @fn='fn'></child>
</template>
<script>
import Child from './Child.vue'
export default {components: { Child},data() {return {}},methods: {fn(e) {console.log("子传父" + e);},}};
</script>
​
// Child.vue
<template><input type="text" @blur="fn('我是子组件,可以传参数')" />
</template>
<script>
export default {data() {return {};},methods: {// 失去焦点发送fn(e) {this.$emit("fn", e);},},
};
</script>

6、$attrs 和 $listeners(vue3废弃) (父组件向子组件传递非props数据与事件

当要和一个嵌套很深的组件进行通信时,如果使用 prop 和 events 就会显的十分繁琐,中间的组件只起到了一个中转站的作用,像下面这样

<!--父组件-->
<template><child :name="name" :message="message" @eventOne='eventHandler' @click.native='clickHandler'></child>
</template>
data() {return {name: '父组件',message: 'Hi',}
},
methods: {eventHandler() {console.log('触发了Parent中的eventHandler s-z-h')},clickHandler() {console.log('触发了Parent中的clickHandler')}
}<!--子组件 Child.vue-->
<template><grand-child v-bind="$attrs" v-on="$listeners"></grand-child>
</template><!--孙子组件 grandChild.vue-->
<template><div></div>
</template>
created() {// 触发父组件的 send 函数this.$emit('send', 'hello') 
},
mounted() {// 可以拿到父组件传来的数据console.log(this.$attrs); // 父组件监听了两个事件,一个eventOne, 一个click,// 由于click被native修饰了,故$listerners 只有eventOne事件console.log(this.$listeners) 
}   

当要传递的数据很多时,就需要在中间的每个组件都重复写很多遍,反过来从后代组件向祖先组件使用 events 传递也会有同样的问题。使用 $attrs 和 $listeners 就可以简化这样的写法。
$ attrs 会包含父组件中没有被 prop 接收的所有属性(不包含class 和 style 属性),可以通过 v-bind=“$attrs” 直接将这些属性传入内部组件。
$ listeners 会包含所有父组件中的 v-on 事件监听器 (不包含 .native 修饰器的) ,可以通过 v-on=“$listeners” 传入内部组件。
这种方式的传值虽然说不常用,可读性不是很好。但其对于组件层级嵌套比较深,使用props会很繁琐,或者项目比较小,不太适合使用 Vuex 的时候,可以考虑用它$children / $parent的使用

7、$children(vue3废弃) & $parent(通过父/子组件实例的引用进行通讯

  • $children:获取到一个包含所有子组件(不包含孙子组件)的 VueComponent 对象数组,可以直接拿到子组件中所有数据和方法等
  • $parent:获取到一个父节点的 VueComponent 对象,同样包含父节点中所有数据和方法等
// 父组件
<template><div class=""><Child></Child></div>
</template>
<script>
import Child from "./Child.vue";
export default {data() {return {name: "父组件数据",};},mounted() {// 调用第一个子组件的方法this.$children[0].fn(); // 获取第一个子组件中的属性console.log(this.$children[0].name); },methods: {fn() {console.log("父组件里的方法 s-z-h");},},components: { Child },
};
</script>// 子组件
<template><div><input type="text" /></div>
</template>
<script>
export default {data() {return {name: "我是子里的数据",};},methods: {fn() {console.log("我是子组件方法");},},mounted() {// 调用父组件的方法this.$parent.fn(); // 获取父组件中的属性console.log(this.$parent.name); },
};
</script>

8、provide / inject (祖先组件向后代组件传送数据)

provide / inject 为依赖注入,说是不推荐直接用于应用程序代码中,但是在一些插件或组件库里却是被常用,所以我觉得用也没啥,还挺好用的

  • provide:可以让我们指定想要提供给后代组件的数据或方法
  • inject:在任何后代组件中接收想要添加在这个组件上的数据或方法,不管组件嵌套多深都可以直接拿来用

要注意的是 provide 和 inject 传递的数据不是响应式的,也就是说用 inject 接收来数据后,provide 里的数据改变了,后代组件中的数据不会改变,除非传入的就是一个可监听的对象

// 父组件 Home<template><div class=""><HelloWorld></HelloWorld></div>
</template>
<script>
import HelloWorld from "../components/HelloWorld.vue";
export default {data() {return {val: "父组件数据",};},provide() {return {name: this.val, // data 的数据someMethod: this.someMethod, // methods 中的方法};},methods: {someMethod() {console.log("这是注入的方法");},},components: { HelloWorld },
};
</script>
// 子组件 HelloWorld
<template><div><input type="text" /><SunChild></SunChild></div>
</template>
<script>
import SunChild from "./sun-child.vue";
export default {data() {return {};},inject: ["name", "someMethod"],mounted() {console.log(this.name);this.someMethod();},components: { SunChild },
};
</script>
// 孙组件SunChild 也可以拿数据
<script>
export default {data() {return {};},mounted() {},inject: ["name", "someMethod"],mounted() {console.log(this.name);this.someMethod();},
};
</script>

9、EventBus(使用 Vue 实例作为事件总线,在组件之间传递数据)

EventBus 是中央事件总线,不管是父子组件,兄弟组件,跨层级组件等都可以完成通信

// 找到main.js 加入一下代码  公共的$bus
Vue.prototype.$bus = new Vue()
// 父组件 也可以兄弟a
<template><div class=""><Child></Child></div>
</template>
<script>
import Childfrom "./Child.vue";
export default {data() {return {};},mounted() {this.$bus.$on("fn", (value) => {console.log(value);});},components: { Child },
};
</script>// 子组件 也可以兄弟b
<template><div><input type="text" @blur="fn" /></div>
</template>
<script>
export default {data() {return {};},methods: {fn() {this.$bus.$emit("fn", "可以父子通信,也可以兄弟通信,s-z-h");},},
};
</script>

10、vuex(用于管理大型应用程序中的状态管理)

可以定义共享的数据源,在哪里都可以访问 安装配置 使用即可

// vuex 里定义共享的数据,在哪个组件都可以访问
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import vuexPersist from "vuex-persist";
export default new Vuex.Store({// 定义数据state: {data: 'vuex 的数据',a: 1,b: 2,},// 定义修改数据的方法mutations: {},// 处理异步操作actions: {},modules: {},getters: {num(state) {return state.a + state.b}},
})
<template><div class="">{{ data }}{{ num }}</div>
</template>
<script>
import { mapState, mapGetters } from "vuex";
export default {data() {return {};},// 辅助函数computed: { ...mapState(["data"]), ...mapGetters(["num"]) },// 第二种 希望你会举一反三// computed: {//   data() {//     return this.$store.state.data;//   },// },components: {},
};
</script>

11、插槽 slot

作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,

适用于父组件 ===> 子组件

  • 默认插槽
    // Parent.vue
    <Child><div>html结构1</div>
    </Child>// Child.vue
    <template><div><!-- 定义插槽 此处将被渲染成  <div>html结构1</div> --><slot>插槽默认内容...</slot></div>
    </template>
  • 具名插槽

在父组件中通过 slot 属性,给插槽命名,在子组件中通过 slot 标签,根据定义好的名字填充到对应的位置

// Parent.vue
<Child><template slot="center"><div>html结构1</div></template><template v-slot:footer><div>html结构2</div></template>
</Child>// Child.vue<template><div><!-- 定义插槽 --><!-- 此处渲染 <div>html结构1</div> --><slot name="center">插槽默认内容...</slot><!-- 此处渲染 <div>html结构2</div> --><slot name="footer">插槽默认内容...</slot></div></template>
  • 作用域插槽

带数据的插槽,子组件提供给父组件的参数,父组件根据子组件传过来的插槽数据来进行不同的展现和填充内容。在标签中通过 v-slot="value" 来接受数据。作用域插槽和具名插槽可以结合使用

// Parent.vue
"<Child><template scope="scopeData"><!-- 生成的是ul列表 --><ul><li v-for="g in scopeData.games" :key="g">{{g}}</li></ul></template>
</Child><Child><template slot-scope="scopeData" slot="s1"><!-- 生成的是h4标题 --><h4 v-for="g in scopeData.games" :key="g">{{g}}</h4></template>
</Child>// Child.vue
<template><div><slot :games="games" name="s1"></slot></div>
</template><script>export default {name:'Child',props:['title'],//数据在子组件自身data() {return {games:['红色警戒','穿越火线','劲舞团','超级玛丽']}},}
</script>

作用域插槽和具名插槽可以结合使用

12、$root

$root 可以拿到 根组件 App.vue 里的数据和方法

// Home 父组件访问数据
<template><div class=""><Child></Child></div>
</template>
<script>
import Child from "./Child.vue";
export default {data() {return {};},mounted() {// 获取根组件的数据console.log(this.$root.foo);},components: { Child }
};
</script>// Child 子组件添加数据
<template><div></div>
</template>
<script>
export default {data() {return {};},mounted() {// 写入根组件的数据this.$root.foo = 2;},methods: {},
};
</script>

13、Teleport:在DOM树中任意位置渲染组件

Teleport 是 Vue 3 中新增的特性,用于在组件的模板中将内容渲染到 DOM 树中的任意位置,而不受组件层次结构的限制。它适用于需要在组件之外渲染内容的场景,比如弹出框、对话框等。
 
以下演示如何使用 Teleport 渲染一个弹出框:

<template><div><button @click="showModal = true">Show Modal</button><Teleport to="body"><Modal v-if="showModal" @close="showModal = false"><!-- Modal Content --></Modal></Teleport></div>
</template><script>
import { ref } from 'vue';
import Modal from './Modal.vue';export default {components: {Modal,},setup() {const showModal = ref(false);return {showModal,};},
};
</script>

在这个示例中,当点击 "Show Modal" 按钮时,Teleport 将 <Modal> 组件的内容渲染到 <body> 元素下,而不受组件层次结构的影响。这样可以确保弹出框的样式和行为在不同层次的组件中都是一致的。
 
需要注意的是,Teleport 在渲染内容时仍然会受到 CSS 层叠上下文和层次结构的影响,因此需要在使用时注意样式的调整。
 
总结起来,Teleport 是一个很有用的特性,可以方便地将组件的内容渲染到任意位置,增强了 Vue 在处理 UI 布局和渲染方面的灵活性。

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

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

相关文章

【Python系列】查看虚拟环境信息和包大小

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Java基于SpringBoot+Vue的蜗牛兼职网系统的研究与实现

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

CSS-布局

display display 属性是用于控制 布局 的最重要的 CSS 属性。display 属性规定是否/如何显示元素。 每个 HTML 元素都有一个默认的 display 值&#xff0c;具体取决于它的元素类型。大多数元素的默认 display 值为 block 或 inline。 block block&#xff1a;块级元素。块级…

越来越多服务区安装智慧公厕是什么原因

随着社会的不断发展&#xff0c;人们对生活质量的要求也越来越高。在这种背景下&#xff0c;越来越多的服务区开始安装智慧公厕&#xff0c;以满足人们在出行过程中的生活需求。那么&#xff0c;为什么越来越多的服务区选择安装智慧公厕呢&#xff1f;这其中究竟有哪些原因呢&a…

你信不信,五分钟快速学习Nginx

Nginx是什么&#xff1f; Nginx 是一个高性能的HTTP和反向代理服务器。它是由俄罗斯程序员Igor Sysoev开发的&#xff0c;最初是为了解决俄罗斯大型的门户网站的高流量问题。 说到反向代理&#xff0c;那么有没有正向代理呢&#xff1f; 正向代理&#xff1a;客户端非常明确要…

Swift Publisher 5 for mac:打造精美版面

Swift Publisher 5 for mac&#xff1a;打造精美版面 Swift Publisher 5是一款专业的版面设计和编辑工具&#xff0c;为Mac用户提供了强大的设计功能和直观的操作界面。以下是关于Swift Publisher 5的功能介绍&#xff1a; 直观易用的界面&#xff1a;用户能够轻松地使用Swift …

每日两题 / 189. 轮转数组 560. 和为 K 的子数组(LeetCode热题100)

189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; 向右轮转将使尾部k个元素顶到头部 将整个数组反转&#xff0c;再分别反转前k个元素和剩下的元素即可 class Solution { public:void rotate(vector<int>& nums, int k) {k % nums.size();reverse(nums.begi…

C# 自动填充文字内容到指定图片

目录 需求 开发运行环境 方法设计 实现代码 AddText方法 图片转Base64 调用示例 小结 需求 在我们的一些发布系统项目应用中&#xff0c;会经常发布一些链接图标&#xff0c;该图标基本上以模板背景为主&#xff0c;并填充项目文字内容。解决方式一般会让美工进行制作…

Qt 拖放功能详解:理论与实践并举的深度指南

拖放&#xff08;Drag and Drop&#xff09;作为一种直观且高效的用户交互方式&#xff0c;在现代图形用户界面中扮演着重要角色。Qt 框架提供了完善的拖放支持&#xff0c;允许开发者在应用程序中轻松实现这一功能。本篇博文将详细阐述Qt拖放机制的工作原理&#xff0c;结合详…

代码随想录阅读笔记-回溯【N皇后】

题目 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案&#xff0c;该方案中 Q 和 . 分别代表…

【2024】使用Rancher管理k8s集群和创建k8s集群

Rancher管理k8s集群及创建k8s集群。 Rancher版本为:2.8.2目录 rancher管理k8s集群rancher创建k8s集群rancher管理k8s集群 使用rancher管理已经存在的k8s集群。 本部分内容需要自行准备好k8s集群及rancher平台,部署请看本人其他文章 。 登录到rancher平台后,点击集群管理,…

部署wordpress

查看别名type ll ll 是 ls -l --colorauto 的别名 设置别名alias alias ymyum install -y 使用别名ym nginx 取消别名unalias ym 基于LNMP做一个wordpress nginx mysql 5.7 PHP 7.4 1、linux基本环境 修改主机名 hostnamectl set-hostname $name 关闭防火墙及selinux …

113 如何排查 cpu 过高的业务进程

前言 又是一个面试问题, 呵呵 之前碰到的 一个 java 进程 cpu 占用率过高, 应该如何排查? 对于这种问题, 第一反应就是 jstack, pstack, 然后仔细观察多次堆栈信息结果的 重复率较高的代码 因此 我给出的思路是, 写脚本 多次 jstack 目标进程, 然后 再统计分析一下 出现频…

Stable Diffusion 模型分享:CyberRealistic XL(真实)cyberrealisticXL_v11VAE.safetensors

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八下载地址模型介绍

mybatisPlus数据字段填充

这里用到的时实体类User import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.…

压缩感知的概述梳理(1)

参考文献 An efficient visually meaningful image compression and encryption scheme based on compressive sensing and dynamic LSB embedding 基本内容 基本关系梳理 压缩感知核心元素 信号 x 长度&#xff1a;N动态稀疏或可用变换表示&#xff1a;x &#x1d74d;s …

如何将低分辨率的视频变高清,使用AI工具分辨率画质增强至1080P、4K或者8K(附工具)

环境&#xff1a; Topaz Video AI 5.0 问题描述&#xff1a; 如何将低分辨率的视频变高清&#xff0c;使用AI工具分辨率画质增强至1080P、4K或者8K 原视频 增强1080P 解决方案&#xff1a; 1.打开软件&#xff0c;导入要处理的视频&#xff08;工具在本文最后附上&#xf…

C 排序算法

冒泡排序 冒泡排序&#xff08;英语&#xff1a;Bubble Sort&#xff09;是一种简单的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序&#xff08;如从大到小、首字母从A到Z&#xff09;错误就把他们交换过来。 过程演示&…

学习笔记------时序约束之时钟周期约束

本文摘自《VIVADO从此开始》高亚军 主时钟周期约束 主时钟&#xff0c;即从FPGA的全局时钟引脚进入的时钟或者由高速收发器输出的时钟。 对于时钟约束&#xff0c;有三个要素描述&#xff1a;时钟源&#xff0c;占空比和时钟周期。 单端时钟输入 这里我们新建一个工程&#x…