消失的DOM元素没有注册点击事件
Disappearing DOM element does not register click event
我正在 React 中构建一个输入字段,如下所示:
单击'x'时(StyledCloseCircle
),文本将被清除,'x'符号应该消失。 'x' 符号当前显示为 javascript 当输入字段获得焦点时,
export const Search = React.forwardRef((props, ref) => {
const [isFocused, setFocus] = useState(false);
const [isHovered, setHover] = useState(false);
return (
<InputContainer
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
<StyledInput
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
isHovered={isHovered}
ref={ref}
{...props}
/>
{isFocused && !props.value && (
<StyledMagnifyingGlass
isHovered={isHovered}
isFocused={isFocused}
onClick={props.onSearch}
/>
)}
{isFocused && props.value && (
<StyledCloseCircle onClick={() => console.log("THIS DOES NOT FIRE")} />
)}
{!isFocused && (
<StyledMagnifyingGlass
isHovered={isHovered}
isFocused={isFocused}
onClick={props.onSearch}
/>
)}
</InputContainer>
);
});
问题是单击 'x' 时,输入失去焦点,导致 'x' 在下一次渲染时被移除,并且不注册 click
事件。但是,它确实会触发 mousedown
事件。
因此,我的两个问题是:
- 单击 'x' 时的操作顺序是什么,导致它注册
mousedown
而不是 click
?
- 我怎样才能达到预期的效果?
您应该创建一个单独的状态来控制 show/hide 清除按钮的位置。像现在一样显示它 onFocus
,但如果用户在输入容器外单击或单击“清除”按钮,则隐藏它。您还可以隐藏它 onBlur
但有一些超时 (500-1000ms) 以防用户使用键盘而不是鼠标。
这是以下代码的 CodeSnadbox example:
function App() {
const inputContainerRef = useRef();
const [value, setValue] = useState("");
const [showClear, setShowClear] = useState(false);
const onFocus = useCallback(() => {
setShowClear(true);
}, []);
const onClear = useCallback(() => {
setValue("");
setShowClear(false);
}, []);
const onOutsideClick = useCallback(e => {
// hide Clear button only if clicked outside of the container
if (!inputContainerRef.current.contains(e.target)) {
setShowClear(false);
}
}, []);
useLayoutEffect(
() => {
// set the listener only if we shown the Clear button and remove the listener once we hid it
if (showClear) {
document.addEventListener("click", onOutsideClick);
return () => document.removeEventListener("click", onOutsideClick);
}
},
[showClear] // re-invoke if the state changes
);
return (
<div className="App">
<div className="input-container" ref={inputContainerRef}>
<input
value={value}
onChange={e => {
setValue(e.target.value);
}}
className="input"
type="tetxt"
onFocus={onFocus}
/>
{showClear && (
<div className="clear" onClick={onClear}>
X
</div>
)}
</div>
</div>
);
}
我正在 React 中构建一个输入字段,如下所示:
单击'x'时(StyledCloseCircle
),文本将被清除,'x'符号应该消失。 'x' 符号当前显示为 javascript 当输入字段获得焦点时,
export const Search = React.forwardRef((props, ref) => {
const [isFocused, setFocus] = useState(false);
const [isHovered, setHover] = useState(false);
return (
<InputContainer
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
<StyledInput
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
isHovered={isHovered}
ref={ref}
{...props}
/>
{isFocused && !props.value && (
<StyledMagnifyingGlass
isHovered={isHovered}
isFocused={isFocused}
onClick={props.onSearch}
/>
)}
{isFocused && props.value && (
<StyledCloseCircle onClick={() => console.log("THIS DOES NOT FIRE")} />
)}
{!isFocused && (
<StyledMagnifyingGlass
isHovered={isHovered}
isFocused={isFocused}
onClick={props.onSearch}
/>
)}
</InputContainer>
);
});
问题是单击 'x' 时,输入失去焦点,导致 'x' 在下一次渲染时被移除,并且不注册 click
事件。但是,它确实会触发 mousedown
事件。
因此,我的两个问题是:
- 单击 'x' 时的操作顺序是什么,导致它注册
mousedown
而不是click
? - 我怎样才能达到预期的效果?
您应该创建一个单独的状态来控制 show/hide 清除按钮的位置。像现在一样显示它 onFocus
,但如果用户在输入容器外单击或单击“清除”按钮,则隐藏它。您还可以隐藏它 onBlur
但有一些超时 (500-1000ms) 以防用户使用键盘而不是鼠标。
这是以下代码的 CodeSnadbox example:
function App() {
const inputContainerRef = useRef();
const [value, setValue] = useState("");
const [showClear, setShowClear] = useState(false);
const onFocus = useCallback(() => {
setShowClear(true);
}, []);
const onClear = useCallback(() => {
setValue("");
setShowClear(false);
}, []);
const onOutsideClick = useCallback(e => {
// hide Clear button only if clicked outside of the container
if (!inputContainerRef.current.contains(e.target)) {
setShowClear(false);
}
}, []);
useLayoutEffect(
() => {
// set the listener only if we shown the Clear button and remove the listener once we hid it
if (showClear) {
document.addEventListener("click", onOutsideClick);
return () => document.removeEventListener("click", onOutsideClick);
}
},
[showClear] // re-invoke if the state changes
);
return (
<div className="App">
<div className="input-container" ref={inputContainerRef}>
<input
value={value}
onChange={e => {
setValue(e.target.value);
}}
className="input"
type="tetxt"
onFocus={onFocus}
/>
{showClear && (
<div className="clear" onClick={onClear}>
X
</div>
)}
</div>
</div>
);
}