当前位置: 首页 > news >正文

Vue 系列之:组件通讯

子组件调用父组件方法

1、直接在子组件中通过 this.$parent.event 来调用父组件的方法

父组件:

<template><p><child></child></p>
</template>
<script>import child from './child';export default {components: {child},methods: {fatherMethod() {console.log('测试');}}};
</script>

子组件:

<template><p><button @click="childMethod()">点击</button></p>
</template>
<script>export default {methods: {childMethod() {this.$parent.fatherMethod();}}};
</script>

2、父组件使用 v-on 监听事件,子组件使用 $emit 件触发事件

@ 是 v-on 的缩写

父组件:

<template><p><child @method1="fatherMethod"></child></p>
</template>
<script>import child from './child';export default {components: {child},methods: {fatherMethod(params) {console.log('测试', params);}}};
</script>

子组件:

<template><p><button @click="childMethod()">点击</button></p>
</template>
<script>export default {methods: {childMethod() {this.$emit('method1', params); // params 为参数,可不传 // this.$emit('method1');}}};
</script>

3、父组使用 v-bind 绑定事件,子组件用 props 接收事件

: 是 v-bind 的缩写

父组件:

<template><p><child :method1="fatherMethod"></child></p>
</template>
<script>import child from './child';export default {components: {child},methods: {fatherMethod() {console.log('测试');}}};
</script>

子组件:

<template><p><button @click="childMethod()">点击</button></p>
</template>
<script>export default {props: {method1: {type: Function,default: null}},methods: {childMethod() {if (this.method1) {this.method1();}}}};
</script>

父组件调用子组件方法

1、通过 ref 直接调用子组件的方法

父组件:

<template><div><Button @click="fatherMethod">点击调用子组件方法</Button><Child ref="child"/></div>
</template>    <script>
import Child from './child';
export default {methods: {fatherMethod() {this.$refs.child.childMethod();},},
}
</script>

子组件:

<template><div>我是子组件</div>
</template><script>
export default {methods: {childMethod() {console.log('我是子组件的方法');},},
};</script>

2、通过组件的$emit$on方法(可以,但是没必要)

父组件:

<template><div><Button @click="fatherMethod">点击调用子组件方法</Button><Child ref="child"/></div>
</template>    <script>
import Child from './child';
export default {methods: {fatherMethod() {this.$refs.child.$emit("getChildMethod")    //子组件$on中的名字},},
}
</script>

子组件:

<template><div>我是子组件</div>
</template><script>
export default {mounted() {this.$nextTick(function() {this.$on('getChildMethod', this.childMethod);});},methods: {childMethod() {console.log('我是子组件方法');}}
};
</script>

兄弟组件

  • 方法1:通过父组件作为中转

    • 通过 ref 和 $parent

    • 通过 provide 和 inject

  • 方法2:使用 EventBus 事件总线

  • 方法3:vuex,下一篇内容会讲

EventBus 使用方式

1、初始化——全局定义

可以将 eventBus 绑定到 vue 实例的原型上,也可以直接绑定到 window 对象上

//main.js//注册方式一
Vue.prototype.$EventBus = new Vue();//注册方式二
window.EventBus = new Vue();

2、监听事件

//使用方式一
this.$EventBus.$on('eventName', (param1, param2, ...) => {//需要执行的代码
})//使用方式二
EventBus.$on('eventName', (param1, param2, ...) => {//需要执行的代码
})

3、触发事件

//使用方式一
this.$EventBus.$emit('eventName', param1, param2,...)//使用方式二
EventBus.$emit('eventName', param1, param2,...)

4、移除监听事件

为了避免在监听时,事件被反复触发,通常需要在页面销毁时移除事件监听。或者在开发过程中,由于热更新,事件可能会被多次绑定监听,这时也需要移除事件监听。

//使用方式一
this.$EventBus.$off('eventName');//使用方式二
EventBus.$off('eventName');//移除所有
EventBus.$off();

5、示例

简单示例一:

<!--组件 A.vue-->
<script>
export default {  mounted() {  // 监听事件this.$EventBus.$on('custom-event', this.handleEvent)  },  methods: {  handleEvent(data) {  console.log(data)  }  }  
}
</script><!--组件 B.vue-->
<template>  <button @click="handleClick">触发事件</button>  
</template>  <script>
export default {data() {return {str: '我来自 B 组件'}}methods: {handleClick() {// 触发事件this.$EventBus.$emit('custom-event', this.str)  }  }  
}  
</script>

示例二:

假设兄弟组件有三个,分别是 A、B、C 组件,A 组件如何获取 B 或者 C 组件的数据

这时候就可以使用 EventBus。EventBus 是一种发布/订阅模式,用于在组件之间传递事件和数据。A 组件可以监听由 B 或 C 组件发布的事件,并在事件处理函数中获取传递的数据。

思路:
A 组件中使用 Event.$on 监听事件
B、C 组件中使用 Event.$emit 触发事件

// A.vue  
<template>  <div>A 接收到的数据: {{ receivedData }}</div>  
</template>  <script>  export default {  data() {  return {  receivedData: null  };  },  mounted() {  // 监听事件  EventBus.$on('custom-event', (data) => {  this.receivedData = data.message;  });  },  beforeDestroy() {  // 组件销毁前,移除事件监听器  EventBus.$off('custom-event');  }  
};  
</script>
// B.vue 和 C.vue
<template>  <button @click="sendData">发送数据</button>  
</template>  <script>  
export default {  methods: {sendData() {  const data = { message: 'I am from B' };// 触发事件EventBus.$emit('data-from-a', data);  }  }  
};  
</script>

多层组件(爷孙)

provide() 和 inject[]

用于将数据或方法暴露给组件树中的任何后代组件,哪怕是深层次的后代组件都可以访问到这些数据,而无需通过 props 层层传递。

注意:provide 和 inject 主要用于单向数据传递,即从祖先组件流向后代组件。虽然可以在后代组件中修改注入的数据,但这种做法会破坏单向数据流的原则,导致数据流向不清晰,难以调试,因此不建议这样做。

Vue2 用法:

<!--爷/父 组件-->
<template><div id="app"><Children></Children></div>
</template><script>
import Children from "./Children.vue";
export default {name: 'parent',components: { Children },provide() {return {parentEvent: this.myEvent,parentData: this.message,parentStr: '字符串数据'};},data() {return {message: 'data中的数据'}},methods: {myEvent(params1, params2) {console.log(params1, params2)},}
};
</script>
<!--子/孙 组件-->
<template><el-button @click="handleClick">测试</el-button>
</template><script>
export default {name: 'child',inject: ["parentEvent", "parentData", "parentStr"],methods: {handleClick() {this.parentEvent('参数1', '参数2');console.log(this.parentData)console.log(this.parentStr)}}
};
</script>

从上到下依次打印:

参数1 参数2
data中的数据
字符串数据

Vue3 用法:

<!--爷/父 组件-->
<template><div id="app"><Children></Children></div>
</template><script setup>
import { ref, provide } from "vue";
import Children from "./Children.vue";
const message = ref('data中的数据');
const str = '字符串数据'
function myEvent(params1, params2) {console.log(params1, params2)
}
provide('parentEvent', myEvent);
provide('parentData', message);
provide('parentStr', str);
</script>
<!--子/孙 组件-->
<template><el-button @click="handleClick">测试</el-button>
</template><script setup>
import { inject } from "vue";
const parentEvent = inject('parentEvent');
const parentData = inject('parentData');
const parentStr = inject('parentStr', '默认值');function handleClick() {parentEvent('参数1', '参数2')console.log(parentData.value)console.log(parentStr)
}
</script>

细心的朋友已经发现:在 Vue3 中,子组件打印的是 parentData.value,这说明 parentData 是一个响应式对象。

直接总结:

特性Vue2Vue3
响应式支持provide 提供的数据不是响应式provide 提供的数据是响应式
默认值支持不支持默认值支持默认值,inject 的第二个参数就是默认值

$attrs 和 $listeners

$attrs

$attrs 是一个对象,包含了父组件传递给子组件的所有非 prop 属性(即没有在 props 中定义的属性)。

当你希望将父组件传递的属性传递给子组件的子组件时,可以使用 $attrs。

父组件:

<!-- 父组件 -->
<template><div id="app"><Children :params1="params1" :params2="params2" /></div>
</template><script>
import Children from "./Children.vue";
export default {name: 'parent',components: { Children },data() {return {params1: '测试1',params2: '测试2',params3: '测试3',}},mounted() {setTimeout(() => {this.params2 += 'timeout'}, 5000);},
};
</script>

子组件:

<!-- 子组件 -->
<template><div><p>params1: {{ $attrs.params1 }}</p><p>params2: {{ $attrs.params2 }}</p><p>params3: {{ $attrs.params3 }}</p><Groundson v-bind="$attrs" :params4="params4"/></div>
</template><script>
import Groundson from "./Groundson.vue";
export default {name: 'children',components: { Groundson },props: {params1: {type: String,default: ""}},data() {return {params4: '测试4'}},mounted() {console.log("children $attrs:", this.$attrs);},
};
</script>

孙组件:

<!-- 孙组件 -->
<template><div></div>
</template>
<script>export default {name: 'groundson',mounted() {console.log("groundson $attrs:", this.$attrs);},
};
</script>

页面:

在这里插入图片描述

打印:

在这里插入图片描述
总结:

  • 没有通过 v-bind 传递给子组件的,子组件的 $attrs 中不会有该属性

  • 通过 v-bind 传递给了子组件,但是子组件使用了 props 接收的,子组件的 $attrs 中不会有该属性

  • $attrs 中的属性值是响应式的

  • 在子组件中使用 v-bind=“$attrs” 可以将子组件的 $attrs 中的所有属性都传递给孙子组件,孙子组件也是按同样的规则接收

inheritAttrs 的作用:

观察页面元素发现:

在这里插入图片描述
子组件的根元素和孙子组件的根元素都多了一些属性

官方解释:默认情况下,父组件传递的,但没有被子组件解析为 props 的 attributes 绑定会被“透传”。这意味着当我们有一个单根节点的子组件时,这些绑定会被作为一个常规的 HTML attribute 应用在子组件的根节点元素上。我们可以通过设置 inheritAttrs 为 false 来禁用这个默认行为。

例如在子组件中加上 inheritAttrs: false

在这里插入图片描述
子组件根节点的属性消失了,由于没有在孙子组件中设置,孙子组件的根节点还保留着属性

$listeners

$listeners 包含了父组件传递给子组件的所有事件监听器(即 v-on 绑定的事件)。

与 $attrs 类似, $attrs 是传递属性, $listeners 是传递方法。这里就不再举例了。

注意:在 Vue3 中,$listeners 已经被移除,其功能被合并到了 $attrs 中。


http://www.mrgr.cn/news/93463.html

相关文章:

  • 在线教育网站项目第二步 :学习roncoo-education,服务器为ubuntu22.04.05
  • react中的fiber和初次渲染
  • 树莓派3B+的初步使用
  • 【VBA】WPS/PPT设置标题字体
  • Java本地缓存深度实践:框架选型与一致性保障(下)
  • 【星云 Orbit•STM32F4】13. 探索定时器:基本定时器
  • 数据库的安装(mysql)
  • Flink深入浅出之02:编程模型、数据源、算子、connector
  • 【人工智能】数据挖掘与应用题库(501-600)
  • 算法·搜索
  • Spring提供的SPEL表达式
  • 算法之 前缀和
  • vue3 组合式API:插槽
  • C++智能指针`shared_ptr`详解
  • uploadlabs通关思路
  • LeetCode 解题思路 11(Hot 100)
  • docker-compose部署mongodb副本集集群
  • AI绘画软件Stable Diffusion详解教程(7):图生图基础篇(改变图像风格)
  • Oracle SQL优化实战要点解析(11)——索引、相关子查询及NL操作(1)
  • vue基本功