Vue3 Script Setup(组合式API)如何复用useLink点击事件?
Vue3 多组件共享点击事件的解决方案
针对你在多个组件中重复编写useLink方法的问题,以下是几种适配Vue3组合式API(Script Setup)的共享方案:
方案一:自定义组合式函数(Hook)
这是最贴合Vue3组合式API理念的方案,将点击逻辑抽离为可复用的Hook:
- 在项目中创建
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 }; }
- 在需要使用的组件中导入并使用:
<template> <h1 @click="handleLinkClick">Header #</h1> </template> <script setup> import { useSectionLink } from '@/composables/useSectionLink'; const { handleLinkClick } = useSectionLink(); </script>
方案二:自定义全局指令
如果希望更简洁地在模板中使用,无需每次导入Hook,可以自定义全局指令:
- 在
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');
- 在组件模板中直接使用指令:
<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
相关产品推荐
相关产品推荐

