React中InputBase子组件聚焦时如何触发父div元素聚焦并修改样式
问题说明
这是我当前的SearchBar效果:
我想要实现的效果是:当我聚焦<InputBase>组件时,触发父级<div className={classes.search} ref={refSearchBar}></div>的聚焦状态,让父元素的box-shadow变成如下效果:
我尝试用useRef实现但没有生效,原代码如下:
import React, { useRef } from "react"; import { makeStyles } from "@material-ui/core/styles"; import InputBase from "@material-ui/core/InputBase"; import SearchIcon from "@material-ui/icons/Search"; const useStyles = makeStyles((theme) => ({ search: { position: "relative", borderRadius: theme.shape.borderRadius, padding: "0 0.5rem", width: "50%", border: "1px solid grey", "&:focus": { boxShadow: "0 0 0 1px blue, 0 0 0 4px blue" } }, })); export default function PrimarySearchAppBar(props) { const classes = useStyles(); const refSearchBar = useRef(null); return ( <div className={classes.search} ref={refSearchBar}> <div className={classes.searchIcon}> <SearchIcon /> </div> <InputBase placeholder="Search…" classes={{ root: classes.inputRoot, input: classes.inputInput }} inputProps={{ "aria-label": "search" }} style={{ width: "100%" }} onClick={() => { refSearchBar.current.focus(); }} /> </div> ); }
解决方案
你的代码不生效有两个核心问题:
- 普通div元素默认不支持聚焦事件,必须给父div添加
tabIndex属性才能触发:focus伪类对应的样式 - 你绑定的是
onClick事件,仅点击输入框时会触发,用键盘Tab切换聚焦到输入框的场景无法覆盖,应该改为绑定onFocus事件
另外需要在父div的聚焦样式里加outline: none,去掉浏览器默认的聚焦轮廓线,避免和自定义的box-shadow冲突,同时补全缺失的搜索图标、输入框样式避免布局错位,修改后的完整代码如下:
import React, { useRef } from "react"; import { makeStyles } from "@material-ui/core/styles"; import InputBase from "@material-ui/core/InputBase"; import SearchIcon from "@material-ui/icons/Search"; const useStyles = makeStyles((theme) => ({ search: { position: "relative", borderRadius: theme.shape.borderRadius, padding: "0 0.5rem", width: "50%", border: "1px solid grey", "&:focus": { outline: "none", boxShadow: "0 0 0 1px blue, 0 0 0 4px rgba(0,0,255,0.2)" } }, searchIcon: { height: "100%", position: "absolute", pointerEvents: "none", display: "flex", alignItems: "center", justifyContent: "center", left: 8, }, inputRoot: { color: "inherit", width: "100%", }, inputInput: { padding: theme.spacing(1, 1, 1, 0), paddingLeft: `calc(1em + ${theme.spacing(2)}px)`, width: "100%", } })); export default function PrimarySearchAppBar(props) { const classes = useStyles(); const refSearchBar = useRef(null); return ( <div className={classes.search} ref={refSearchBar} tabIndex={0}> <div className={classes.searchIcon}> <SearchIcon /> </div> <InputBase placeholder="Search…" classes={{ root: classes.inputRoot, input: classes.inputInput }} inputProps={{ "aria-label": "search" }} onFocus={() => { refSearchBar.current.focus(); }} /> </div> ); }
内容的提问来源于stack exchange,提问作者CCCC
相关产品推荐
相关产品推荐

