#javascript #html #reactjs #focus #blur
#javascript #HTML #reactjs #фокус #размытие
Вопрос:
У меня есть два (или более) Элементы HTML и я хочу выполнять обратный вызов всякий раз, когда какой-либо из них теряет фокус, за исключением случаев, когда фокус перемещается между ними. Другими словами, я хочу рассматривать эти элементы как один с точки зрения фокуса и выполнять групповой onBlur
обратный вызов.
Используя React, я пытался отслеживать фокус каждого элемента на состоянии, но при перемещении фокуса с элемента a
на элемент b
onBlur
on a
всегда происходит перед onFocus
on b
. Кроме того, поскольку обновление состояния может быть асинхронным, я не уверен в согласованности состояния.
Комментарии:
1. Можете ли вы поделиться примером кода?
Ответ №1:
Вы можете сохранить ссылки на каждый из входных данных, которые вы хотите «поделиться» фокусом, а затем проверить, сфокусирован ли какой-либо из них в вашей onBlur
функции, прежде чем предпринимать какие-либо действия. Однако обратите внимание, что сфокусированный элемент — это body
if, который вы проверяете сразу, когда происходит размытие. Чтобы обойти это, вы можете обернуть свою onBlur
логику в setTimeout
вызов с задержкой 0
в мс.
Вот пример:
function MyComponent() {
const aRef = React.useRef(null);
const bRef = React.useRef(null);
function onBlurGroup() {
window.setTimeout(() => {
if (document.activeElement === aRef.current || document.activeElement === bRef.current) {
console.log("a or b is focused");
return;
}
console.log("focus lost from group");
// do blur handling
}, 0)
}
return (
<div>
<input ref={aRef} name="a" type="text" onBlur={onBlurGroup}/>
<input ref={bRef} name="b" type="text" onBlur={onBlurGroup}/>
<input name="other" type="text"/>
</div>
);
}
И функционирующий образец (с использованием компонента на основе классов, поскольку Stack пока не поддерживает перехваты):
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.aRef = React.createRef();
this.bRef = React.createRef();
}
onBlurGroup = () => {
window.setTimeout(() => {
if (document.activeElement === this.aRef.current || document.activeElement === this.bRef.current) {
console.log("a or b is focused");
return;
}
console.log("focus lost from group");
// do stuff
}, 0)
}
render() {
return (
<div>
<input ref={this.aRef} name="a" placeholder="A" type="text" onBlur={this.onBlurGroup}/>
<input ref={this.bRef} name="b" placeholder="B" type="text" onBlur={this.onBlurGroup}/>
<input name="other" placeholder="Other" type="text"/>
</div>
);
}
}
ReactDOM.render(<MyComponent/>, document.querySelector("#root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
Ответ №2:
Обычно вы выполняете это с таймаутом и ждете несколько миллисекунд, прежде чем запускать текстовый шаг. Быстрый и грязный код react.
class Test extends React.Component {
constructor(props) {
super(props)
this.state = {
blurTimer: null
}
this.handleBlur = this.handleBlur.bind(this);
this.handleFocus = this.handleFocus.bind(this);
}
clearTimer() {
if (this.state.blurTimer) {
window.clearTimeout(this.state.blurTimer);
this.setState({ blurTimer: null });
}
}
processIt() {
console.log('Process it!!!!');
}
handleBlur() {
this.clearTimer();
const blurTimer = window.setTimeout(() => this.processIt(), 100);
this.setState({ blurTimer });
}
handleFocus() {
this.clearTimer();
}
render() {
return (
<div>
<h2>foo</h2>
<input type="text" onBlur={this.handleBlur} onFocus={this.handleFocus} />
<input type="text" onBlur={this.handleBlur} onFocus={this.handleFocus} />
</div>
)
}
}
ReactDOM.render(<Test />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>