如何在 React 中将焦点设置在 div 上,以便通过 onBlur 触发效果?

问题描述 投票:0回答:1

我正在使用 React 开发一个非常基本的笔记应用程序。纯粹是前端问题。

在侧边栏上,我有一个所有当前笔记的列表,用户可以使用它们在它们之间进行交换。列表中显示的每个注释的右侧都有一个删除按钮,可以删除该注释。单击该按钮后,将出现一个 div(我称之为“批准框”),要求确认。 “删除?是还是不是。”批准框基于布尔值 useState 显示。

在此输入图片描述

这就是我正在尝试做的事情。如果用户单击页面上的其他任何位置,我希望取消批准框。我的目的是将焦点设置在 div 上,然后使用 onBlur 事件切换 useState,然后关闭 div。如果焦点丢失,则不再有批准框。

问题是我一生都无法弄清楚如何真正将焦点集中在批准框上。

这是我正在编写的组件的代码:

import { useRef } from 'react';
import { useAppContext } from '../../App';
import { BsX } from 'react-icons/bs';

const useFocus = () => {
  const htmlElRef = useRef(null);
  const setFocus = () => {
    htmlElRef.current && htmlElRef.current.focus();
  };

  return [htmlElRef, setFocus];
};

const DeleteButton = ({ note, showApproval, setShowApproval }) => {
  const { deleteSelectedNote } = useAppContext();
  const [approvalBoxRef, setApprovalBoxFocus] = useFocus();

  const handleClickDelete = () => {
    setShowApproval(!showApproval);
    setApprovalBoxFocus();
  };

  const handleConfirmDelete = (noteId) => {
    deleteSelectedNote(noteId);
  };

  return (
    <div className='delete-btn-container'>
      <button
        className={showApproval ? 'delete-btn btn pending' : 'delete-btn btn'}
        onClick={handleClickDelete}
      >
        <BsX size={'1em'} />
      </button>

      <div
        className={showApproval ? 'approval-box active' : 'approval-box'}
        tabIndex='1'
        onBlur={() => {
          setShowApproval(false);
          console.log('approval removed');
        }}
        ref={approvalBoxRef}
      >
        Delete?
        <span className='yes' onClick={() => handleConfirmDelete(note.id)}>
          {' '}
          Y{' '}
        </span>
        /
        <span className='no' onClick={() => setShowApproval(false)}>
          {' '}
          N
        </span>
      </div>
    </div>
  );
};
export default DeleteButton;

现在,我在批准框中将 tabIndex 设置为 1,并且当用户单击初始删除按钮时,我使用自定义挂钩将焦点设置在其上。

但是当我这样做时,批准框没有获得焦点。用户仍然可以单击并与应用程序的其余部分交互,并且批准框的 onBlur 事件永远不会触发。仅当用户实际单击审批框时,焦点才会设置在审批框上。然后,如果他们点击离开,就会发生所需的效果,并且批准框将被关闭。

关于焦点如何运作,有什么我不明白的地方吗?

我不知道这是否重要,但正如您在代码中看到的,这是我的列表中单个注释项的删除按钮。每个笔记都会有其中之一,我希望用户一次只能与其中一个进行交互。

审批框始终呈现,但我使用 CSS 使其可见且具有交互性。我尝试过有条件地渲染批准框而不是仅仅显示它,但在这种情况下焦点问题是相同的。

如果有更好的方法来达到我想要的效果,我绝对愿意接受有关替代方案的建议。

javascript reactjs focus simplemodal onblur
1个回答
0
投票

您可以创建一个

useClickOutside.js
钩子

import { useEffect, useCallback } from 'react';

const isRefArray = r => 'length' in r;

const isTarget = (ref, event) =>
    ref && ref.current && ref.current.contains(event.target);

const trueForAny = (array, condition) =>
    array.reduce(
        (conditionAlreadyMet, value) => conditionAlreadyMet || condition(value),
        false,
    );

const useClickOutside = (ref, onclick) => {
    const handleClick = useCallback(
        click => {
            if (isRefArray(ref)) {
                if (trueForAny(ref, d => isTarget(d, click))) {
                    return;
                }
            } else if (isTarget(ref, click)) {
                return;
            }
            onclick();
        },
        [onclick, ref],
    );

    useEffect(() => {
        document.addEventListener('click', handleClick);

        return () => {
            document.removeEventListener('click', handleClick);
        };
    }, [handleClick]);

    return ref;
};

export default useClickOutside;

上面的钩子的作用是监视您何时在传递的

ref
组件之外单击。

在您的组件文件中,执行此操作

 import { useState, useRef } from 'react';
 import useClickOutside from 'hooks/useClickOutside';

 const clickRef = useRef();

 useClickOutside(clickRef, () => {
    // Set the state to close the approval-box on click outside here
     setShowApproval(false);
  });


  function DeleteButton(){
   ...

   return(
     <div className='delete-btn-container'>
      <button
        ref={clickRef)
        className={showApproval ? 'delete-btn btn pending' : 'delete-btn btn'}
        onClick={handleClickDelete}
      >
        <BsX size={'1em'} />
      </button>
      ...
     </div>
   )
 }

您可以摆脱

useFocus
函数和
focus
实现。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.