Tailwind UI Headless UI Menu点击外部关闭时添加自定义操作
Tailwind UI的Menu组件基于Headless UI构建,本身没有直接配置"点击外部关闭时执行操作"的选项,但可以通过以下几种方式实现需求:
方案一:利用Menu组件的onClose回调
Headless UI的Menu组件提供了onClose属性,当菜单关闭时(包括点击外部、按ESC键、点击关闭按钮等场景)会触发该回调,直接在其中编写自定义操作即可:
import { Fragment } from 'react'; import { Menu, Transition } from '@headlessui/react'; function FilterMenu() { const handleMenuClose = () => { // 这里编写点击外部关闭时需要执行的操作 console.log('菜单已关闭(点击外部或其他方式触发)'); // 示例:重置筛选条件、保存当前状态等 // resetFilters(); }; return ( <Menu as="div" className="relative inline-block text-left" onClose={handleMenuClose} // 添加onClose回调 > {({ open, close }) => ( <> <Menu.Button className="inline-flex w-full items-center justify-center gap-x-1.5 bg-white text-sm font-semibold text-gray-700 ring-1 ring-gray-200 py-1 px-3 rounded shadow-md"> Filter </Menu.Button> <Transition show={open} as={Fragment} enter="transition ease-out duration-100" enterFrom="transform opacity-0 scale-95" enterTo="transform opacity-100 scale-100" leave="transition ease-in duration-75" leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > <Menu.Items static className="absolute mt-1 right-0 z-10 w-48 origin-top-right rounded-md bg-white shadow-md focus:outline-none" > <p>Some action</p> </Menu.Items> </Transition> </> )} </Menu> ); }
方案二:监听open状态变化
通过监听Menu组件返回的open状态,当状态从true变为false时执行自定义操作,效果和方案一类似:
import { Fragment, useEffect } from 'react'; import { Menu, Transition } from '@headlessui/react'; function FilterMenu() { return ( <Menu as="div" className="relative inline-block text-left" > {({ open, close }) => { // 监听open状态变化 useEffect(() => { if (!open) { // 菜单关闭时执行操作 console.log('菜单已关闭'); // 你的自定义逻辑 } }, [open]); return ( <> <Menu.Button className="inline-flex w-full items-center justify-center gap-x-1.5 bg-white text-sm font-semibold text-gray-700 ring-1 ring-gray-200 py-1 px-3 rounded shadow-md"> Filter </Menu.Button> <Transition show={open} as={Fragment} enter="transition ease-out duration-100" enterFrom="transform opacity-0 scale-95" enterTo="transform opacity-100 scale-100" leave="transition ease-in duration-75" leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > <Menu.Items static className="absolute mt-1 right-0 z-10 w-48 origin-top-right rounded-md bg-white shadow-md focus:outline-none" > <p>Some action</p> </Menu.Items> </Transition> </> ); }} </Menu> ); }
仅在点击外部关闭时触发的进阶处理
如果需要仅在点击外部关闭时执行操作(排除点击按钮或ESC键的情况),可以通过监听全局点击事件,结合菜单的ref判断点击区域:
import { Fragment, useEffect, useRef } from 'react'; import { Menu, Transition } from '@headlessui/react'; function FilterMenu() { const menuRef = useRef(null); useEffect(() => { const handleClickOutside = (event) => { if (menuRef.current && !menuRef.current.contains(event.target)) { // 点击了菜单外部,执行操作 console.log('点击外部关闭菜单,执行自定义操作'); } }; document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, []); return ( <Menu as="div" className="relative inline-block text-left" ref={menuRef} > {({ open, close }) => ( <> <Menu.Button className="inline-flex w-full items-center justify-center gap-x-1.5 bg-white text-sm font-semibold text-gray-700 ring-1 ring-gray-200 py-1 px-3 rounded shadow-md"> Filter </Menu.Button> <Transition show={open} as={Fragment} enter="transition ease-out duration-100" enterFrom="transform opacity-0 scale-95" enterTo="transform opacity-100 scale-100" leave="transition ease-in duration-75" leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > <Menu.Items static className="absolute mt-1 right-0 z-10 w-48 origin-top-right rounded-md bg-white shadow-md focus:outline-none" > <p>Some action</p> </Menu.Items> </Transition> </> )} </Menu> ); }
注意:第三种方案需要确保菜单的ref正确包含所有菜单相关元素,避免误判。
内容的提问来源于stack exchange,提问作者A.S.Abir
相关产品推荐
相关产品推荐

