vue3 emit组件事件

再页面上嗲用自定义组件时,我们可以通过props给自定义组件传值,可以通过插槽slots给自定义组件传递模板内容,以上说的都是父向子的传递,那自定义组件能够通过emit组件事件给父组件传递值。

emit语法

@监听事件="$emit(自定义事件名称,传递的值)"

触发与监听

我们可以在子组件中用click点击事件或者change改变事件,来声明一个$emit方法的进行自定义方法的触发

触发

写法1

<button @click="$emit('number',1)">按钮</button>

 注意:这样的写法不能用引号,要用单引号,因为@click=""就用了引号了,里面就不能再用引号了

 写法2

<template>
	<view>
		<button @click="onClick">按钮</button>
	</view>
</template>

<script setup>
	const emit=defineEmits(["number"]);
	function onClick(){
		emit("number",123);
	}
</script>

监听 

在父组件中我们可以用v-on来监听子组件的emit的自定义方法的触发

<template>
	<view class="">
		<test-emit @number="onHave"></test-emit>
	</view>
</template>

<script setup>
	const onHave = function(e) {
		console.log(e);
	}
</script>

注意:@后面是我们要监听的子组件emit自定义方法名字,引号里面的是我们用于得到子组件传个我们值的方法

页面显示效果

 emit定义多个自定义方法

通过一个案例来展示

自定义组件代码

<template>
	<view>
		<button @click="onClik">点击按钮改变容器盒子颜色</button>
		<input class="inputStyle" type="text" placeholder="请输入显示的字体大小,单位:px"  @input="onInput"/>
	</view>
</template>

<script setup>
	const emit=defineEmits(['randomColor','fontSize']);
	function onClik(){
		emit('randomColor',Math.random());
		//传一个随机数给父组件
	}
	function onInput(e){
		emit("fontSize",e.detail.value);
		//把input框里面的值传给父组件
	}
</script>
<style lang="scss" scoped>
.inputStyle{
	height: 40px;
	border: 1px solid #ccc;
	margin: 10px 5px;
	padding: 0px 5px;
}
</style>

父组件所在的vue文件代码

<template>
	<view class="">
		<test-emit @randomColor="onHaveRandomColor" @fontSize="onChange"></test-emit>
        <!--绑定多个emit触发的自定义方法-->
		<view class="box" :style="{background:color,fontSize:size+'px'}">监听emit组件事件</view>
	</view>
</template>

<script setup>
	import {ref} from "vue";
	const color=ref("#cccacb");
	const size=ref(16);
	const onHaveRandomColor = function(e) {
		color.value="#"+String(e).substring(3,6);
//截取3位从子组件传过来的随机数,用于随机显示view容器盒子的颜色
	}
	const onChange=function(e){
		if(e==""){
			//如果input如果没有输入值,子组件传过来的是空字符串,就给文字设定一个默认值
			size.value=16;
		}else{
		size.value=e;
		//把子组件传过来的值赋给size响应式变量
		}
	}
</script>

<style lang="scss" scoped>
.box{
	width: 100%;
	height: 200px;
	color: white;
}
</style>

页面展示效果

emit组件事件示例

<think> 我们正在讨论Vue 3中多层组件事件传递的方法和实现。 根据引用内容,我们有几种方法可以实现跨多层组件事件传递: 1. 使用`$emit`和`$listeners`(在Vue 2中常用)但需要注意Vue 3中移除了`$listeners`对象,将其合并到了`$attrs`中。 2. 使用事件总线(Event Bus)模式,但引用[3]和[4]提到这不是最优解,容易导致维护困难。 3. 使用`provide/inject`机制,这是Vue官方推荐的跨层级通信方式之一。 4. 使用状态管理库如Vuex或Pinia,适合全局状态共享,但如果是事件传递(方法调用)可能过于重型。 根据引用[3]的优先级建议: - 优先使用`props/emit`(适用于直接父子组件) - 其次使用`provide/inject`(用于祖孙组件等跨层级通信) - 再次使用Pinia/Vuex(用于全局状态) - 避免使用事件总线(Event Bus)和全局变量。 然而,用户的问题是关于“事件传递”,即从一个深层子组件触发一个事件,让祖先组件能够监听到并执行方法。 在Vue 3中,多层组件事件传递的常见方法有: 1. **逐层传递事件(使用`$emit`)**:如果层级不是特别深,可以通过中间组件一层层使用`$emit`往上传递。但这样会导致中间组件需要处理自己不关心的事件。 2. **使用`provide/inject`传递方法**:在祖先组件使用`provide`提供一个方法,在深层子组件中`inject`该方法并调用,相当于子组件直接调用祖先组件的方法。 3. **使用事件总线(不推荐)**:创建一个全局事件总线,任何组件都可以发射和监听事件。但这样会使数据流难以追踪。 4. **使用状态管理库(如Pinia)**:将事件对应的状态和操作放在store中,但事件本身不是状态,所以可能不太自然。 根据引用[3]和引用[4]的示例,我们重点介绍`provide/inject`方法,因为它是Vue官方推荐的跨层级通信方式。 具体实现步骤(使用provide/inject): 1. 在祖先组件中,使用`provide`来提供一个函数(或者一个包含方法的对象),这个函数就是用来处理事件的。 2. 在深层子组件中,使用`inject`来获取这个函数,然后在需要触发事件的地方调用它。 示例代码: 祖先组件(Grandparent.vue): ```vue <template> <Parent /> </template> <script setup> import { provide } from &#39;vue&#39;; import Parent from &#39;./Parent.vue&#39;; // 定义一个事件处理函数 const handleEvent = (data) => { console.log(&#39;事件被触发,数据为:&#39;, data); // 这里可以执行祖先组件需要做的操作 }; // 提供这个函数给后代组件 provide(&#39;eventHandler&#39;, handleEvent); </script> ``` 深层子组件(Grandchild.vue): ```vue <template> <button @click="triggerEvent">触发事件</button> </template> <script setup> import { inject } from &#39;vue&#39;; // 注入祖先组件提供的事件处理函数 const handleEvent = inject(&#39;eventHandler&#39;); const triggerEvent = () => { // 调用祖先组件提供的方法,并传递数据 if (handleEvent) { handleEvent({ message: &#39;来自深层子组件的数据&#39; }); } }; </script> ``` 注意: - `provide`和`inject`只能在setup函数或`<script setup>`中使用。 - 为了确保依赖关系清晰,建议在项目中对注入的key使用Symbol,并统一管理。 另外,引用[4]中也提到了事件总线(Event Bus)的示例,但注意在Vue 3中,官方移除了`$on`、`$off`等方法,所以事件总线需要自己实现或者使用第三方库(例如mitt)。但引用[3]强烈建议避免使用这种方式。 总结: 在Vue 3中,多层组件事件传递推荐使用`provide/inject`来传递函数,这样可以避免逐层传递事件的繁琐,也避免了事件总线带来的维护困难。 相关问题: 1. Vue 3中`provide/inject`和事件总线(Event Bus)在性能上有何差异? 2. 如何确保通过`provide/inject`传递的事件处理函数的响应性? 3. 在大型Vue项目中,如何规范使用`provide/inject`以避免混乱? </think> ### Vue 3多层组件事件传递的方法与实现 在Vue 3中实现跨多层组件事件传递,主要推荐以下方法(按优先级排序): #### 1. **provide/inject + 函数传递(最优解)** **原理**:祖先组件通过`provide`提供回调函数,深层子组件通过`inject`注入并调用该函数 **实现步骤**: ```vue <!-- 祖先组件 --> <script setup> import { provide } from &#39;vue&#39; const handleEvent = (payload) => { console.log(&#39;收到事件&#39;, payload) } provide(&#39;eventHandler&#39;, handleEvent) // 提供事件处理函数 </script> ``` ```vue <!-- 深层子组件 --> <script setup> import { inject } from &#39;vue&#39; const eventHandler = inject(&#39;eventHandler&#39;) const emitEvent = () => { eventHandler({ data: &#39;来自深层组件&#39; }) // 调用祖先函数 } </script> ``` **优势**: - 精准投喂,无需中间组件转发 - 类型安全(结合TypeScript时) - 性能高效 **适用场景**:祖孙组件通信[^3] --- #### 2. **全局状态管理(Vuex/Pinia)** **原理**:通过共享store触发actions **示例(Pinia)**: ```javascript // store.js export const useEventStore = defineStore(&#39;events&#39;, { actions: { triggerGlobalEvent(payload) { // 处理事件逻辑 } } }) ``` ```vue <!-- 任意子组件 --> <script setup> import { useEventStore } from &#39;./store&#39; const eventStore = useEventStore() const emitEvent = () => { eventStore.triggerGlobalEvent({ data: &#39;跨组件事件&#39; }) } </script> ``` **适用场景**:全局事件或跨多模块通信[^3] --- #### 3. **事件总线(谨慎使用)** **原理**:创建全局事件发射器 **实现(使用mitt)**: ```javascript // eventBus.js import mitt from &#39;mitt&#39; export const emitter = mitt() ``` ```vue <!-- 发射组件 --> <script setup> import { emitter } from &#39;./eventBus&#39; emitter.emit(&#39;deep-event&#39;, { value: 123 }) </script> <!-- 接收组件 --> <script setup> import { onMounted } from &#39;vue&#39; import { emitter } from &#39;./eventBus&#39; onMounted(() => { emitter.on(&#39;deep-event&#39;, (payload) => { console.log(&#39;接收事件&#39;, payload) }) }) </script> ``` **注意**:需手动管理事件监听/移除,易导致内存泄漏[^4] --- #### 4. **逐层传递$emit(基础方案)** **原理**:通过中间组件接力传递事件 ```vue <!-- 子组件 --> <template> <button @click="$emit(&#39;custom-event&#39;)">触发</button> </template> <!-- 中间组件 --> <template> <Child @custom-event="() => $emit(&#39;custom-event&#39;)" /> </template> <!-- 祖先组件 --> <template> <MiddleLayer @custom-event="handleEvent" /> </template> ``` **缺点**:增加组件耦合度,维护成本高[^1] --- ### ⚠️ 注意事项 1. **性能影响**:跨层通信比父子通信多2-5倍性能开销,避免高频事件[^1] 2. **代码规范**:为provide/inject使用Symbol键名避免命名冲突 3. **响应性控制**:默认注入值非响应式,需显式使用`ref()`/`reactive()` 4. **通信层级**:超过3组件时才推荐使用跨层方案[^3] > 📌 最佳实践:优先尝试组件重构(如使用插槽降低层级),其次选择provide/inject,大型项目使用Pinia/Vuex管理跨组件事件[^3][^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值