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

Vue3 Script Setup(组合式API)如何复用useLink点击事件?

Vue3 多组件共享点击事件的解决方案

针对你在多个组件中重复编写useLink方法的问题,以下是几种适配Vue3组合式API(Script Setup)的共享方案:

方案一:自定义组合式函数(Hook)

这是最贴合Vue3组合式API理念的方案,将点击逻辑抽离为可复用的Hook:

  1. 在项目中创建src/composables/useSectionLink.js文件,写入以下代码:
import { useRouter } from 'vue-router';

export function useSectionLink() {
  const router = useRouter();

  const handleLinkClick = (e) => {
    const section = e.target.closest('.section');
    if (!section) return; // 防止找不到对应元素时报错

    const targetHash = `#${section.id}`;
    if (router.currentRoute.value.hash !== targetHash) {
      router.push(targetHash);
    }
  };

  return { handleLinkClick };
}
  1. 在需要使用的组件中导入并使用:
<template>
  <h1 @click="handleLinkClick">Header #</h1>
</template>

<script setup>
import { useSectionLink } from '@/composables/useSectionLink';

const { handleLinkClick } = useSectionLink();
</script>

方案二:自定义全局指令

如果希望更简洁地在模板中使用,无需每次导入Hook,可以自定义全局指令:

  1. 在src/main.js中注册全局指令:
import { createApp } from 'vue';
import { createRouter, createWebHashHistory } from 'vue-router';
import App from './App.vue';

// 假设你的路由配置
const router = createRouter({
  history: createWebHashHistory(),
  routes: [/* 你的路由配置 */]
});

const app = createApp(App);

// 封装点击处理函数,方便移除监听
const handleSectionLinkClick = (e) => {
  const section = e.target.closest('.section');
  if (!section) return;

  const targetHash = `#${section.id}`;
  if (router.currentRoute.value.hash !== targetHash) {
    router.push(targetHash);
  }
};

app.directive('section-link', {
  mounted(el) {
    el.addEventListener('click', handleSectionLinkClick);
    el._sectionLinkHandler = handleSectionLinkClick;
  },
  unmounted(el) {
    // 清理事件监听,避免内存泄漏
    el.removeEventListener('click', el._sectionLinkHandler);
  }
});

app.use(router);
app.mount('#app');
  1. 在组件模板中直接使用指令:
<template>
  <h1 v-section-link>Header #</h1>
</template>

方案三:封装基础组件

如果多个组件中的h1结构和逻辑高度一致,可以封装成基础组件复用:

创建src/components/SectionHeader.vue:

<template>
  <h1 @click="handleLinkClick" v-bind="$attrs">
    <slot></slot>
  </h1>
</template>

<script setup>
import { useRouter } from 'vue-router';

const router = useRouter();

const handleLinkClick = (e) => {
  const section = e.target.closest('.section');
  if (!section) return;

  const targetHash = `#${section.id}`;
  if (router.currentRoute.value.hash !== targetHash) {
    router.push(targetHash);
  }
};

// 透传所有属性和事件
defineProps({});
defineEmits({});
</script>

然后在其他组件中使用:

<template>
  <SectionHeader>Header #</SectionHeader>
</template>

<script setup>
import SectionHeader from '@/components/SectionHeader.vue';
</script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:00:38