发布时间:2023-09-13 11:00
vue组件中关系说明:
如上图所示, A与B、A与C、B与D、C与E组件之间是父子关系; B与C之间是兄弟关系;A与D、A与E之间是隔代关系; D与E是堂兄关系(非直系亲属)
针对以上关系我们归类为:
因此介绍在不同的场景下如何选择有效方式实现的组件间通信方式,以更好理解组件间的通信。
1、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 )
//父组件
<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 全能
//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 核心
1.可以实现任意组件的通信的方法有两个:事件总线
和 Vuex
,事件总线难维护数据但轻量,Vux维护数据方便但比较重量。
2.可以实现父与子孙跨越层级通信的方法也有两个:$attrs/$listeners
和 provide/inject
,$attrs/$listeners
具有响应性且可以双向通信, provide/inject
无响应性且只能单向通信(父传子)
3.只能实现父与子组件通信的方法有一个:props/emit
,方法比较基础,适合只有父子组件通信的方法,若想跨层级通信需要中间组件做转发,比较麻烦。