目录

一.props传参

1.父组件 ==> 子组件

2.子组件 ==> 父组件

二.组件的自定义事件

三.全局事件总线

四.消息订阅和发布

五.vuex

六.插槽

1.默认插槽

2.具名插槽

3.作用域插槽

七.v-model

八.sync修饰符

九.$attrs和$listeners属性

十.$children和$parent属性


vue项目中大量采用组件化开发,组件之间的通信传递数据是必不可少的一个环节,并且随着需求的不同,需要进行不同关系的组件之间的值传递,从而出现各种组件通信的方式。

组件和组件之间的关系常见有父子组件,兄弟组件,两类关系的组件通信适用的方法是不同的,方法使用的不当,极有可能事倍功半;最常见的父子组件通信方式有props传参,常用的兄弟组件通信方式有自定义事件全局事件总线;较大型的项目,一般采用的是vuex统一管理数据;此外,在一些组件库中,也经常会使用到其它几种通信方式,比如element-ui中,当你需要在一个el-table-column中插入一张图片时,就需要使用作用域插槽,将要展现的页面结构传递给子组件;再比如,在el-dialog弹出框组件中,会使用sync修饰符,获取控制组件显示或隐藏的标志符等等。以下10种组件通信方式总结如下。

一.props传参

适用于父子组件之间传递参数

​ (1).父组件 ==> 子组件 通信

​ (2).子组件 ==> 父组件 通信(要求父先给子一个函数

1.父组件 ==> 子组件

传递数据:在子组件标签上写明传递的参数名=“参数”,若参数是js表达式,需要使用v-bind

<Demo :name="xxx"/>

接收数据:在子组件内部

1. 第一种方式(只接收)

props:['name'] 

2. 第二种方式(限制类型)

props:{name:String}

3. 第三种方式(限制类型、限制必要性、指定默认值):

props:{name:{type:String, //类型​  required:true, //必要性​  default:'老王' //默认值}
}

2.子组件 ==> 父组件

若使用props在父组件中获取子组件的数据:这里在父组件中将addTodo()方法传递给子组件

<template><div id="root"><MyHeader :addTodo="addTodo"/></div>
</template><script>import MyHeader from './components/MyHeader'export default {name:'App',components:{MyHeader},data() {return {todos:[{id:'001',title:'xx',done:true},]}},methods: {//添加一个todoaddTodo(todoObj){this.todos.unshift(todoObj)},}}
</script>

在子组件内部获取input输入框的输入后,将输入信息封装成一个对象todoObj,调用父组件传来的addTodo()方法 ,以实参的形式将对象todoObj传给父组件,实现子 --> 父传参

<template><div class="todo-header"><input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/></div>
</template><script>import {nanoid} from 'nanoid'export default {name:'MyHeader',//接收从App传递过来的addTodoprops:['addTodo'],data() {return {//收集用户输入的titletitle:''}},methods: {add(){//校验数据if(!this.title.trim()) return alert('输入不能为空')//将用户的输入包装成一个todo对象const todoObj = {id:nanoid(),title:this.title,done:false}//通知App组件去添加一个todo对象this.addTodo(todoObj)//清空输入this.title = ''}},}
</script>

props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。

二.组件的自定义事件

1.是一种组件间的通信方式,适用于:子组件 => 父组件

2.使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件。

3. 使用

绑定事件:在父组件中使用@自定义事件名 ,不用写形参,事件回调的形参会自动接收最组件传递的实参内容

<template><Demo @xxx="test">或<Demo v-on:xxx="test">
</template><script>export default {methods:{test(事件参数1,...事件参数2-n){}}}
</script>

或使用ref获取子组件实例对象,调用组件实例.$on('事件名',回调函数)用于监听子组件中定义的xxx事件;

    <template><Demo ref="demo"/></template><script>export defalut {mounted{this.$refs.demo.$on('xxx',this.test)},methods:{test(事件参数1,...事件参数2-n){}}}</script>

若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

触发事件:数据可以传递一个或多个,多个数据可以传递多个实参(第二个参数开始),或者写成一个对象

this.$emit('xxx',数据);

解绑事件

this.$off('xxx'); // 解绑指定事件
this.$off(['a','b']);  // 解绑多个
this.$off();  // 解绑全部

注意:通过this.$refs.xxx.$on('aaa',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题

销毁了当前的组件实例对象时,其身上的所有自定义事件全部销毁了;销毁了vue实例时,其所有的子组件全部销毁了,子组件的自定义世事件也被销毁了,但所有的原生事件不会销毁

三.全局事件总线

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

安装全局事件总线:

new Vue({......beforeCreate() {Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm},......
}) 

由于vc.prototype.__ proto __ = vm.prototype,所以组件实例是可以访问到vue实例上的属性的,可以访问到$bus

使用事件总线

1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身,事件的绑定一般在mounted钩子中进行,事件只需绑定一次即可,这和原生js中给DOM元素绑定事件的回调是一个道理。

methods(){demo(data){......}
},
......
mounted() {this.$bus.$on('xxxx',this.demo)
}

2. 提供数据

this.$bus.$emit('xxxx',数据)

最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

四.消息订阅和发布

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

订阅方是数据的获取方,而发布方是数据的提供方;

使用步骤:

1. 安装:pubsub:npm i pubsub-js

2. 引入:import pubsub from 'pubsub-js'

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

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

4.提供数据:

pubsub.publish('xxx',数据)

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

五.vuex

1.概念

在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

2.使用场景

多个组件需要共享数据时

原理图:vuex的核心主要是由Actions,Mutations和state三部分组成,vuex做的是状态管理,实际上就是存放多个组件可以共享的数据,这些数据存放在state中,一般存放的可以是服务器返回的信息。

在下图中,Vue Components 就是vue组件,在组件中使用this.$store.dispatch('xxxAction') 调用某个action执行,一般在action中请求服务器接口(Backend API),获取请求得到的异步结果,但action无法直接操作state存放数据,所以此时它会调用指定的mutation,在mutation的内就可以操作state修改数据,最后在各个组件内使用this.$store.state.xxx 拿到state存放的状态;

当然,如果没有额外的业务逻辑需要处理,组件无需派发actions,可以在组件内直接使用this.$store.commit('xxxmutation'),通知mutations修改状态。

3.搭建vuex环境

0. 安装:npm i vuex

1. 创建文件:src/store/index.js

必须得在store实例创建前使用Vuex插件,所以Vue.use(Vuex)必须写在index.js中,而不是main.js中。

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)//准备actions对象——响应组件中用户的动作
const actions = {}
//准备mutations对象——修改state中的数据
const mutations = {}
//准备state对象——保存具体的数据
const state = {}
// 准备getters 对state中的内容做二次处理,类似于计算属性
const getters = {}//创建并暴露store
export default new Vuex.Store({actions,mutations,state
})

2. 在main.js中创建vm时传入store配置项

//引入store
import store from './store'
......//创建vm
new Vue({el:'#app',render: h => h(App),store
})

这样就可以在vue实例和组件实例中看到$store属性了。

4.vuex的具体使用

1. 初始化数据、配置actions、配置mutations,操作文件store.js

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//引用Vuex
Vue.use(Vuex)const actions = {//响应组件中加的动作jia(context,value){// console.log('actions中的jia被调用了',miniStore,value)context.commit('JIA',value)},}const mutations = {//执行加IA(state,value){// console.log('mutations中的JIA被调用了',state,value)state.sum += value}
}//初始化数据
const state = {sum:0
}//创建并暴露store
export default new Vuex.Store({actions,mutations,state,
})

2.组件中读取vuex中的数据:

$store.state.sum

3.组件中修改vuex中的数据:

$store.dispatch('action中的方法名',数据)
或
$store.commit('mutations中的方法名',数据)

备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

action中的方法第一个参数context还包括dispatch属性,即当业务逻辑较多可以链式调用多个action方法处理一个业务

const actions = {//响应组件中加的动作jia(context,value){// console.log('actions中的jia被调用了',miniStore,value)value = value + 1;context.dispatch('jia1',value)},jia1(context,value) {value = value * 2;context.dispatch('jia2',value);},jia2(context,value) {value = value * 3;context.commit('JIA',value);},}

六.插槽

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

            父组件 ===> 子组件

分类:默认插槽、具名插槽、作用域插槽

使用方式:

1.默认插槽

父组件中:

<Category><div>html结构1</div>
</Category>

子组件中:

<template><div><!-- 定义插槽 --><slot>插槽默认内容...</slot></div>
</template>

2.具名插槽

一个组件多个插槽,给每个插槽命名加以区分,子组件name属性对应父组件的slot属性

父组件中:

<Category><template slot="center"><div>html结构1</div></template><template v-slot:footer><div>html结构2</div></template>
</Category>

子组件中:

 <template><div><!-- 定义插槽 --><slot name="center">插槽默认内容...</slot><slot name="footer">插槽默认内容...</slot></div></template>

3.作用域插槽

理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
具体编码:父组件通过scope属性值获取子组件的数据,作用域插槽和具名插槽可以结合使用。

父组件中:

<Category><template scope="scopeData"><!-- 生成的是ul列表 --><ul><li v-for="g in scopeData.games" :key="g">{{g}}</li></ul></template>
</Category><Category><template slot-scope="scopeData" slot="s1"><!-- 生成的是h4标题 --><h4 v-for="g in scopeData.games" :key="g">{{g}}</h4></template>
</Category>

子组件中:

<template><div><slot :games="games" name="s1"></slot></div>
</template><script>export default {name:'Category',props:['title'],//数据在子组件自身data() {return {games:['红色警戒','穿越火线','劲舞团','超级玛丽']}},}
</script>

七.v-model

v-model实现的是双向数据绑定,常用于表单元素;但也可以用于自定义组件标签上,实现父子组件的通信,父子组件间的数据同步

首先这里用v-bind和input事件实现一个v-model

</template><input type="text" :value="text" @input="text=$event.target.value">
</template><script>export default {data(){return{text:0}},
}

其能实现v-model一样的效果,这里的value是input表单元素的属性,@input是表单的输入事件;如果一样的写法,写在组件标签上那么value就是组件的props参数,而@input则是自定义事件,若依旧i将@input作为原生的输入事件需要添加事件修饰符,即@input.native

接下去创建一个Inputs组件,给其传递一个参数value,并给其绑定一个自定义事件input

</template><Inputs :value="text" @input="text=$event"/><Inputs v-model="text"/>
</template><script>export default {data(){return{text:0}},
}

在组件内部接收参数value,触发自定义时间内input,将表单的输入内容$event.target.value作为自定义事件的参数传递。

<template><div><span>input:</span><input type="text" :value="value" @input="$emit('input',$event.target.value)"></div>
</template><script>
export default {props:['value']
}
</script>

其同样可以实现上面一样的双向数据绑定的效果,并且使用v-model替换组件的:value和@input也是等价的。

八.sync修饰符

可以实现父子组件数据的同步

<template><Money :money.sync="money"/><!--等价于 --><Money :money="money" @update:money="money=$event">
</template><script>
import Money from './components/Money.vue'
export default {data(){return {money:10000}},components:{Money}
}
</script>

:money.async代表父组件给子组件传递字符串props[money],给当前子组件绑定一个自定义事件(update:money),子组件如下:

<template><div><span>花费了100元</span><button @click="$emit('update:money',money-100)">花钱</button><span>还剩{{money}}元</span></div>
</template><script>
export default {props:['money']
}
</script>

九.$attrs和$listeners属性

$attrs是组件实例的一个属性,可以获取父组件传递过来的props数据

$listeners是组件实例的属性,获取父组件给子组件传递的自定义事件;

如果子组件通过props接收的属性,在$attrs属性当中是获取不到的;

console.log(this.$attrs):

console.log(this.$listeners)

使用el-button封装一个组件,使其具有提示功能

父组件:

<template><ElButton type="success" icon="el-icon-delete" size="mini" title="按钮" @click="handler"/>
</template>
<script>
import ElButton from './components/elButton.vue'
export default {components:{ElButton},methods:{handler(){console.log('123')},}
}
</script>

子组件:可以采用type=”$attrs.type“ size="$attrs.size"......的写法,但像这样过于繁琐,如果传递的属性名和绑定标签的属性名是一致的,直接使用v-bind="$attrs"的形式,需要注意的是,不能写成:=''$attrs";

同理v-on不能用@进行替换

<template><a :title="title"><el-button v-bind="$attrs" v-on="$listeners"></el-button></a>
</template><script>
export default {props:['title'],mounted(){console.log(this.$attrs);}
}
</script>

十.$children和$parent属性

$children是组件实例的属性,可以获取到当前组件的全部子组件,返回的是一个数组

$parent属性获取到某一组件的父组件,可以操作父组件的数据和方法

现在有如下示例:

点击父组件按钮,父组件的存款要加100,同时子组件的存款要减100,父组件通过$children获取子组件的实例,由于只存在一个子组件,所以$children的索引0就是子组件的实例,从而可以让子组件的data中的money减少100。

<template><div><h2>爸爸有存款:{{money1}}</h2><button @click="borrowM(100)">找小明借钱100</button><Son/></div>
</template><script>
import Son from './components/Son.vue'
export default {data(){return{money1:1000}},methods:{borrowM(money){this.money1 += money;this.$children[0].money -= money;},},components:{Son}
}

如下,在子组件Son中,点击按钮,子组件中的存款减少50,同时父组件中的存款增加50,可以通过$parent获取父组件,从而操作父组件的data中的属性money1让其增加50. $parent返回的就是父组件实例对象。

<template><div><h3>儿子小明:现有存款:{{money}}</h3><button @click="giveMoney(50)">给爸爸50元</button></div>
</template><script>
export default {data(){return {money:1000}},methods:{giveMoney(money){this.money -= money;// 获取到父组件,让父组件的数据加50this.$parent.money1 += money;}}
}
</script>

【Vue.js】vue2组件间通信方式总结相关推荐

  1. Vue 组件间通信方式汇总,总有一款适合你( 附项目实战案例 )

    前言 前期分享的 200行纯前端Vue代码!教你写一个专属TodoList[零基础友好] 这个项目案例中使用的组件间通信方式是通过 事件绑定与props 接收来实现的,具体使用方式将在下面进行详细介绍 ...

  2. Vue 组件间通信方式:自定义事件

    前言 前期分享的测试开发系列!Vue 组件间通信方式汇总,总有一款适合你( 5分钟教程-附项目实战案例 )中介绍了 3 种组件间的通信方法,分别是: props 全局事件总线 消息订阅与发布 今天给大 ...

  3. 360奇舞团钟恒:选用Vue.js进行组件化开发,我们遇到了哪些坑?

    责编:陈秋歌,关注前端开发领域,寻求报道或者投稿请发邮件chenqg#csdn.net. 欢迎加入"CSDN前端开发者"微信群,参与热点.难点技术交流.请加群主微信「Rachel_ ...

  4. Vue.js教程-组件化开发

    Vue.js教程-组件化开发 前言 Vue组件化 什么是组件化 Vue单页面开发的解释 组件化思想 组件的使用 原理 实际开发中的使用-父子组件 父子组件传递数据 父传子-props用法 子传父-th ...

  5. Vue2组件间通信——父传子值props

    Vue2组件间通信--父传子值props Vue2中组件间通信系列,本篇是关于父组件向子组件传值的介绍,这里我会用通俗的语言帮助大家理解props配置项 功能: 子组件可以接收到父组件传递的数据信息, ...

  6. Vue.js 父子组件通信的十种方式;告诉世界前端也能做 AI;你可能不知道的14个JavaScript调试技巧...

    记得点击文章末尾的"阅读原文"查看哟~ 下面先一起看下本周的摘要吧~ 想了解老用户如何参与阿里云双十一1折拼团特惠主机的,可以看第二条推送,文中提供了两种方法~,一起看看本周有哪些 ...

  7. Vue.js 定义组件模板的七种方式

    转载自  Vue.js 定义组件模板的七种方式 在 Vue 中定义一个组件模板,至少有七种不同的方式(或许还有其它我不知道的方式): 字符串 模板字面量 x-template 内联模板 render ...

  8. Vue实现兄弟组件间的方法调用及回调

    Vue实现兄弟组件间的方法调用及回调 看兄弟间数据传递的看我写的这篇文章:vue实现兄弟组件间的实时通信 先说说我遇到的情况: 点击左侧树tree,需要调用右侧houseInfo组件中的新增方法,弹出 ...

  9. 两个读书笔记:springboot+vue.js分布式组件全栈开发训练营 + 大数据开发基础

    (springboot+vue.js分布式组件全栈开发训练营原文在notion中, 大数据开发在思维导图中, 这个博客只是保存, 无法阅读. ) what is different between s ...

最新文章

  1. 【python数据挖掘课程】二十.KNN最近邻分类算法分析详解及平衡秤TXT数据集读取
  2. 在VS中创建多个项目
  3. MongoDB 教程五: MongoDB固定集合和性能优化
  4. (四)Raspberry Pi上的人工智能人脸检测
  5. 如何在Mac OSX系统下安装Tomcat
  6. SQL Server-【知识与实战VIII】触发器(中)
  7. H3C CLI基础笔记(交换机,链路聚合-DHCP)
  8. 遗传算法MATLAB
  9. 某中学校校园网络方案设计(课程设计)
  10. 基于微信小程序的人脸识别
  11. 软件工程专业大学四年学什么
  12. Js、 replace 全部内容替换、替换全部匹配内容、替换第一个
  13. Android反编译工具与反编译步骤及常见问题
  14. 河南python培训班
  15. 【转】WPF自定义控件与样式(13)-自定义窗体Window 自适应内容大小消息框MessageBox...
  16. 用计算机看影碟是数字化过程,2012年上海市高中学业水平考试信息科技
  17. php 统计汉字,PHP 统计实时统计汉字个数和区别
  18. Win10 下报错 WerFault.exe -解决方法亲测有效
  19. Scrapy糗事百科爬虫实战代码分析
  20. asp生成带参数的二维码并合成推广海报图片,asp合并合成推广海报图片asp代码

热门文章

  1. Maven快速导出maven工程的依赖包
  2. Java设计模式(16)中介模式(Mediator模式)
  3. MasterPage事件使用
  4. 验证输入的是否数字的几种方法
  5. 读写xml节点的数据总结
  6. 设计模式总结 (1)模式分类
  7. 微众WeCross 跨链平台(8)TTM可信事务机制
  8. TEEC_AllocateSharedMemory()和 TEEC_RegisterSharedMemory()的总结
  9. 2022-03-19
  10. 2021-11-28