You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue单文件组件间通过Emit触发函数执行失败问题

Vue3 子组件 emit 未触发父组件方法的问题解决

问题分析与修复步骤

1. 事件监听绑定位置错误

你把触发切换的事件监听@toggle-subheader绑定到了TopicBar组件上,但实际发出emit的是Header组件,需将监听移到Header标签上:

<header>
    <Header @toggle-subheader="subslide"/>
</header>

2. jQuery 方法名大小写错误

jQuery 的滑动方法是小写开头的slideUp()和slideDown(),你写的大写SlideUp()会导致方法不存在,修改subslide函数:

function subslide(){
  subheaderstate.value = !subheaderstate.value;
  if(subheaderstate.value){
    $('#topicbar').slideUp(); // 改为小写
  }
  else{
    $('#topicbar').slideDown(); // 改为小写
  }
}

3. Header 组件 emit 写法错误(Setup 与 Options API 混合冲突)

你在 Header 组件中混合使用了<script setup>和 Options API,这种情况下 Options API 里的this.$emit无法被 setup 语法正确识别,需统一用<script setup>的方式定义 emit:

替换 Header.vue 的脚本部分,删除 Options API 的<script>标签,改用defineEmits:

<script setup lang="ts">
import $ from 'jquery';

// 定义要触发的事件
const emit = defineEmits(['toggleSubheader']);

function flip(){
    const $arrow = $("#header_arrow");
    const isFlipped = $arrow.hasClass("flipp");

    if(isFlipped) {
        $arrow.removeClass("flipp");
        $arrow.css({"transform":"rotate(0deg)", "transition-duration":"1s"});
    } else{
        $arrow.addClass("flipp");
        $arrow.css({"transform":"rotate(180deg)", "transition-duration":"1s"});
    }
}

// 触发 emit 事件
function sub(){
    emit('toggleSubheader');
}
</script>

4. 父组件多余导入清理

父组件中import Child from './components/Header.vue';属于重复导入,直接删除即可。

修改后的完整代码

App.vue

<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router';
import Header from './components/Header.vue';
import TopicBar from './components/Topicbar.vue';
import $ from 'jquery';
import { ref } from 'vue';

const subheaderstate = ref(false);

function subslide(){
  subheaderstate.value = !subheaderstate.value;
  if(subheaderstate.value){
    $('#topicbar').slideUp();
  }
  else{
    $('#topicbar').slideDown();
  }
}
</script>

<template>
  <header>
      <Header @toggle-subheader="subslide"/>
  </header>
  <div id="topicbar">
    <TopicBar/>
  </div>
</template>

Header.vue

<script setup lang="ts">
import $ from 'jquery';

const emit = defineEmits(['toggleSubheader']);

function flip(){
    const $arrow = $("#header_arrow");
    const isFlipped = $arrow.hasClass("flipp");

    if(isFlipped) {
        $arrow.removeClass("flipp");
        $arrow.css({"transform":"rotate(0deg)", "transition-duration":"1s"});
    } else{
        $arrow.addClass("flipp");
        $arrow.css({"transform":"rotate(180deg)", "transition-duration":"1s"});
    }
}

function sub(){
    emit('toggleSubheader');
}
</script>

<template>
    <h1 id="header_icon">Limits</h1>
    <input type="text" id="header_search" placeholder="Search posts and communities..."/>
    <div id="header_contact">Contact</div>
    <div id="header_topics" @click="flip(); sub();">Topics<img id="header_arrow" class="arrow flipp" src="./assets/down.svg" alt="down"></div>
    <div id="header_about">About Us</div>
    <div id="header_login">Login</div>
    <div id="header_signup">Sign Up</div>
</template>

内容的提问来源于stack exchange,提问作者Cenek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 18:13:23