失去焦点/onBlur 时反应 textarea 回调
React textarea callback when losing focus / onBlur
https://codesandbox.io/s/react-textarea-callback-on-blur-yoh8n?file=/src/App.tsx
在 React 中有一个文本区域我想实现两个基本用例:
- 当用户按下“Escape”键时移除焦点并重置某些状态
- 当用户在文本区域外单击并失去焦点时执行回调 (
saveToDatabase
) (=> onBlur
)
<textarea
ref={areaRef}
value={input}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
/>
对于第一个用例,我在目标上调用 blur()
:
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Escape") {
console.log("Escape clicked");
setInput(inputForReset);
e.currentTarget.blur();
}
};
..但这也调用了 onBlur
处理程序,我实际上想将其用于第二个用例。我试图通过 ref 确定事件调用者是否是 textarea 本身,但这不起作用:
const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
console.log("blur");
/**
* Only save to database when losing focus through clicking
* outside of the text area, not for every blur event.
*/
if (areaRef.current && !areaRef.current.contains(e.currentTarget as Node)) {
saveToDatabase();
}
};
换句话说:当用户在文本区域完成编辑时,我想将一些东西保存到数据库中,但我不知道如何区分我以编程方式触发的 blur
事件和本机事件blur
当您在节点外部单击时文本区域使用的事件。
也许您可以添加一个变量(或者 class 属性,如果您使用 class 组件而不是功能组件)作为“preventsaveOnBlur”标志;类似于:
let preventSaveOnBlur: boolean = false;
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Escape") {
console.log("Escape clicked");
setInput(inputForReset);
preventSaveOnBlur = true; // will prevent saving on DB - see handleBlur
e.currentTarget.blur();
}
};
const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
console.log("blur");
/**
* Only save to database when losing focus through clicking
* outside of the text area, not for every blur event.
*/
if (!preventSaveOnBlur) {
saveToDatabase();
}
};
const handleFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {
preventSaveOnBlur = false;
};
并且在文本区域中您也处理了 onFocus 事件:
<textarea
ref={areaRef}
value={input}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
onFocus={handleFocus} // will reset 'preventSaveOnBlur' to false every time the textarea get the focus
/>
我注意到错误是什么。
模糊事件的目标是自己
areaRef === event.target
所以你必须实现一个额外的功能来捕捉框外的点击。
import * as React from "react";
import "./styles.css";
import { useState, useRef, useEffect } from "react";
function useOutsideAlerter(
ref: React.RefObject<HTMLTextAreaElement>,
fun: () => void
) {
useEffect(() => {
function handleClickOutside(event: any) {
if (
ref.current &&
!ref.current.contains(event.target) &&
// THIS IS IMPORTANT TO CHECK
document.activeElement === ref.current
) {
fun();
}
}
// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
}
export default function App() {
const areaRef = useRef<HTMLTextAreaElement>(null);
const [inputForReset, setInputForReset] = useState<string>("Original input");
const [input, setInput] = useState<string>(inputForReset);
const saveToDatabase = () => {
console.log("save to database");
setInputForReset(input);
alert(input);
};
// OUT SIDE CLICK
useOutsideAlerter(areaRef, saveToDatabase);
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setInput(e.target.value);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Escape") {
console.log("Escape clicked");
setInput(inputForReset);
e.currentTarget.blur();
e.stopPropagation();
}
};
// it doesnt work
const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
/**
* Only save to database when losing focus through clicking
* outside of the text area, not for every blur event.
*/
console.log(event.target);
console.log(areaRef);
if (areaRef.current && !areaRef.current.contains(event.target)) {
saveToDatabase();
}
};
return (
<div className="App">
<textarea
ref={areaRef}
value={input}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
className="area"
/>
<p>Input state: {input}</p>
</div>
);
}
请检查我的sandbox
https://codesandbox.io/s/react-textarea-callback-on-blur-yoh8n?file=/src/App.tsx
在 React 中有一个文本区域我想实现两个基本用例:
- 当用户按下“Escape”键时移除焦点并重置某些状态
- 当用户在文本区域外单击并失去焦点时执行回调 (
saveToDatabase
) (=>onBlur
)
<textarea
ref={areaRef}
value={input}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
/>
对于第一个用例,我在目标上调用 blur()
:
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Escape") {
console.log("Escape clicked");
setInput(inputForReset);
e.currentTarget.blur();
}
};
..但这也调用了 onBlur
处理程序,我实际上想将其用于第二个用例。我试图通过 ref 确定事件调用者是否是 textarea 本身,但这不起作用:
const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
console.log("blur");
/**
* Only save to database when losing focus through clicking
* outside of the text area, not for every blur event.
*/
if (areaRef.current && !areaRef.current.contains(e.currentTarget as Node)) {
saveToDatabase();
}
};
换句话说:当用户在文本区域完成编辑时,我想将一些东西保存到数据库中,但我不知道如何区分我以编程方式触发的 blur
事件和本机事件blur
当您在节点外部单击时文本区域使用的事件。
也许您可以添加一个变量(或者 class 属性,如果您使用 class 组件而不是功能组件)作为“preventsaveOnBlur”标志;类似于:
let preventSaveOnBlur: boolean = false;
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Escape") {
console.log("Escape clicked");
setInput(inputForReset);
preventSaveOnBlur = true; // will prevent saving on DB - see handleBlur
e.currentTarget.blur();
}
};
const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
console.log("blur");
/**
* Only save to database when losing focus through clicking
* outside of the text area, not for every blur event.
*/
if (!preventSaveOnBlur) {
saveToDatabase();
}
};
const handleFocus = (e: React.FocusEvent<HTMLTextAreaElement>) => {
preventSaveOnBlur = false;
};
并且在文本区域中您也处理了 onFocus 事件:
<textarea
ref={areaRef}
value={input}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
onFocus={handleFocus} // will reset 'preventSaveOnBlur' to false every time the textarea get the focus
/>
我注意到错误是什么。 模糊事件的目标是自己
areaRef === event.target
所以你必须实现一个额外的功能来捕捉框外的点击。
import * as React from "react";
import "./styles.css";
import { useState, useRef, useEffect } from "react";
function useOutsideAlerter(
ref: React.RefObject<HTMLTextAreaElement>,
fun: () => void
) {
useEffect(() => {
function handleClickOutside(event: any) {
if (
ref.current &&
!ref.current.contains(event.target) &&
// THIS IS IMPORTANT TO CHECK
document.activeElement === ref.current
) {
fun();
}
}
// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
}
export default function App() {
const areaRef = useRef<HTMLTextAreaElement>(null);
const [inputForReset, setInputForReset] = useState<string>("Original input");
const [input, setInput] = useState<string>(inputForReset);
const saveToDatabase = () => {
console.log("save to database");
setInputForReset(input);
alert(input);
};
// OUT SIDE CLICK
useOutsideAlerter(areaRef, saveToDatabase);
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setInput(e.target.value);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Escape") {
console.log("Escape clicked");
setInput(inputForReset);
e.currentTarget.blur();
e.stopPropagation();
}
};
// it doesnt work
const handleBlur = (e: React.FocusEvent<HTMLTextAreaElement>) => {
/**
* Only save to database when losing focus through clicking
* outside of the text area, not for every blur event.
*/
console.log(event.target);
console.log(areaRef);
if (areaRef.current && !areaRef.current.contains(event.target)) {
saveToDatabase();
}
};
return (
<div className="App">
<textarea
ref={areaRef}
value={input}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
className="area"
/>
<p>Input state: {input}</p>
</div>
);
}
请检查我的sandbox