NextUI Drawer侧边栏打开时输入框无法获取焦点的问题求助
NextUI Drawer侧边栏打开时输入框无法获取焦点的问题求助
我在开发React应用时,使用@nextui-org/react库的Drawer组件实现了侧边栏,但遇到了一个头疼的问题:当侧边栏打开时,点击主内容区的输入框,输入框没法获得焦点,反而侧边栏导航列表里的某个项会被聚焦。这直接导致用户在侧边栏显示时没法和输入框交互。
我发现如果把Sidebar实现里的DrawerContent组件去掉,问题就解决了,说明问题出在这个组件或者它和Drawer的交互上。打开侧边栏时,页面里会出现<span data-focus-scope-start="true" hidden="" aria-hidden="true"></span>这个元素,我怀疑这和焦点管理的错误有关。
一开始我以为是portalContainer属性影响了事件处理,就把它去掉了,但问题还是存在。我还用浏览器开发者工具检查了相关元素的z-index,排除了层级堆叠的问题。
经过测试,我确定问题就出在DrawerContent组件上。我的预期是侧边栏打开时点击输入框,输入框能获得焦点让用户输入,但实际情况是输入框没焦点,侧边栏的导航项反而被聚焦。那个带data-focus-scope-start的span元素看起来就是罪魁祸首,它应该是在错误地管理焦点。
LayoutPanel.js:
import React from "react"; import { Outlet, useLocation, useNavigate } from "react-router"; import Sidebar from "../components/Sidebar"; import { Button, Card, CardBody, CardHeader, Divider, useDisclosure, } from "@nextui-org/react"; import { Icon } from "@iconify/react"; import { images } from "../utils/images"; const LayoutPanel = () => { const { isOpen, onOpen, onOpenChange } = useDisclosure(); const navigate = useNavigate(); const location = useLocation(); return ( <div> {/* <HeaderNavigation /> */} <div className="flex w-full"> <Sidebar isOpen={isOpen} onOpenChange={onOpenChange} /> <Card className="flex-1 m-3 min-h-[calc(100vh-24px)]"> <CardHeader className="h-[76px]"> <div className="flex items-center gap-2"> {!isOpen && ( <Button isIconOnly variant="light" onPress={onOpenChange}> <Icon icon="solar:siderbar-outline" width={24} /> </Button> )} <img src={images.logo} alt="logo" className="object-contain h-6 dark:invert" /> </div> </CardHeader> <Divider /> <CardBody className="container mx-auto max-w-7xl text-start"> <Outlet /> </CardBody> </Card> </div> {/* <Footer /> */} </div> ); }; export default LayoutPanel;
Sidebar.js:
import React from "react"; import { Drawer, DrawerContent, DrawerHeader, DrawerBody, Listbox, ListboxItem, Accordion, Button, AccordionItem, cn, Divider, } from "@nextui-org/react"; import sidebarNavigation from "../utils/sidebarNavigation"; import { Icon } from "@iconify/react"; const Sidebar = ({ isOpen, onOpenChange }) => { return ( <div id="sidebar" className={cn( "transition-all absolute md:relative duration-300 ease-in-out overflow-hidden", isOpen ? "w-[336px]" : "w-0" )} > <Drawer isDismissable={false} hideCloseButton isKeyboardDismissDisabled={false} portalContainer={document.getElementById("sidebar") || undefined} backdrop={window.innerWidth < 768 && isOpen ? "blur" : "transparent"} classNames={{ wrapper: "!items-stretch w-auto relative", base: "data-[placement=right]:sm:my-3 data-[placement=left]:sm:my-3 rounded-e-large rounded-s-none", body: "pe-0", header: "p-[calc(1rem+2px)] ", }} shouldBlockScroll isOpen={isOpen} onOpenChange={onOpenChange} > <DrawerContent> <DrawerHeader className="flex justify-between gap-3 "> <h3>賲賳賵</h3> <Button isIconOnly variant="light" onPress={onOpenChange}> <Icon icon="solar:siderbar-outline" width={24} /> </Button> </DrawerHeader> <Divider /> <DrawerBody> <Listbox variant="flat" className="overflow-y-auto pe-3 ps-0" > {sidebarNavigation.map((menuItem) => menuItem.subItems ? ( <ListboxItem key={menuItem.title}> <Accordion showDivider={false} className="space-y-3"> <AccordionItem key={menuItem.title} aria-label={menuItem.title} startContent={ <div className={`flex items-center rounded-small justify-center ${menuItem.color} w-9 h-9`} > <img src={menuItem.icon} className="object-contain invert" width={24} alt={menuItem.title} /> </div> } subtitle={menuItem.subtitle} classNames={{ trigger: "p-0", content: "py-0 ps-3", }} title={menuItem.title} > <Listbox variant="flat" aria-label={`夭蹖乇賲賳賵 ${menuItem.title}`} classNames={{ list: cn("border-s border-default-200 ps-4"), }} > {menuItem.subItems.map((subItem) => ( <ListboxItem key={subItem.title} textValue={subItem.title} href={subItem.path} startContent={ <div className={`flex items-center rounded-small justify-center ${menuItem.color} w-7 h-7`} > <img src={subItem.icon} width={20} className="object-contain" alt={subItem.title} /> </div> } > <span>{subItem.title}</span> </ListboxItem> ))} </Listbox> </AccordionItem> </Accordion> </ListboxItem> ) : ( <ListboxItem title={menuItem.title} description={menuItem.subtitle} classNames={{ base: "gap-3", }} startContent={ <div className="ms-2"> <div className={`flex items-center rounded-small justify-center ${menuItem.color} w-9 h-9`} > <img src={menuItem.icon} width={20} className="invert" alt={menuItem.title} /> </div> </div> } > {menuItem.title} </ListboxItem> ) )} </Listbox> </DrawerBody> </DrawerContent> </Drawer> </div> ); }; export default Sidebar;
FormFastGroup.js:
import { Controller, useForm } from "react-hook-form"; import { Button, Form, Input } from "@nextui-org/react"; const FormFastGroup = () => { const { handleSubmit, control } = useForm(); const onSubmit = (data) => { console.log(data); }; return ( <Form className="w-full max-w-xs flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)} > <Controller name="groupName" control={control} defaultValue="" render={({ field }) => ( <Input {...field} label="分组名称" placeholder="请输入分组名称" variant="bordered" /> )} /> <Button type="submit" color="primary"> 提交 </Button> </Form> ); }; export default FormFastGroup;
备注:内容来源于stack exchange,提问作者Parsa Amirabadi
相关产品推荐
相关产品推荐

