簡體   English   中英

使用 onBlur function 反應 JS 關閉下拉菜單

[英]React JS close dropdown using onBlur function

我在 React Js 上做了一個下拉列表。 我希望使用onBlur function 在外部單擊時關閉下拉菜單。 這里的問題是,當單擊下拉選項時它也會關閉,並且不會執行附加到該選項的 function。 我想向onBlur function 添加一個條件,它將檢查單擊的區域是在下拉列表內部還是外部並采取相應措施,但我不確定如何檢查。

我試過document.activeElement ,但那是選擇整個body元素。

這是我的代碼沙盒鏈接: https://codesandbox.io/s/intelligent-tdd-zq4qcr?file=/src/App.js:938-941

這是 function 我需要幫助:

const close = (event) => {
  // Help me with this function please
  // I need to wrap this function in a condition that checks
  // if the click was outside the dropdown
  let dropdown = event.target.nextSibling;

  // If I comment the lines below,
  // it updates the number, but doesn't close the dropdown
  if (dropdown?.classList.contains("display")) {
    dropdown.classList.remove("display");
    setOption("");
  }
};

我正在添加一個 class 屬性display: unset單擊下拉按鈕時未設置。 默認情況下,顯示設置為none

編輯:我的原始項目中這些下拉列表的數量是可變的。 它們可能是兩個,也可能是 10 個,具體取決於用戶。 所以我不能在 state 中維護它,需要使用 JavaScript 來跟蹤單擊了哪個下拉菜單。

您可以存儲打開的 state 並有條件地添加顯示 class。 要檢測 div 外部的點擊,您可以將 ref 傳遞給包裝器 div 並使用自定義掛鈎。

請注意,一般情況下,您應該避免直接操作 dom,如果您覺得必須這樣做,這很可能意味着您應該重新審視您的方法。


function useOnClickOutside(ref, cb) {
    useEffect(() => {
        function handleClickOutside(event) {
            if (ref.current && !ref.current.contains(event.target)) {
                cb();
            }
        }

        // Bind the event listener
        document.addEventListener("mousedown", handleClickOutside);
        return () => {
            // Unbind the event listener on clean up
            document.removeEventListener("mousedown", handleClickOutside);
        };
    }, [ref, cb]);
}

function Dropdown({onSelect, values}) {
    const [isOpen, setIsOpen] = useState(false);
    const wrapperRef = useRef(null);

    const close = () => {
        setIsOpen(false);
    };

    useOnClickOutside(wrapperRef, close);

    const toggle = () => {
        setIsOpen(prev => !prev)
    };


    return (
        <div className={`dropdown`} tabIndex={0}>
            <button onClick={toggle}>•••</button>
            <div ref={wrapperRef} style={{zIndex: 999}} className={`list ${isOpen ? 'display' : ''}`}>
                <ul>
                    {values.map(v => <li
                        key={v}
                        onClick={() => {
                            onSelect(v)
                            setIsOpen(false)
                        }}>{"Option " + v}</li>)}

                </ul>
            </div>
        </div>
    )

}

export default function App() {
    const [option, setOption] = useState(null);


    return (
        <div className="App">
            <h2>Option: {option}</h2>
            <p>
                Dropdown should close when I click outside it
                <br/>
                Option Number should update
            </p>
            <Dropdown onSelect={setOption} values={[1, 2, 3]}/>
            <Dropdown onSelect={setOption} values={[4, 5, 6]}/>
            <Dropdown onSelect={setOption} values={[6, 7, 8]}/>
        </div>
    );
}


你有一個很好的開始,但是缺少一些東西。 不必自己添加/刪除 class,您可以為此創建一個 state 並讓 React 為您處理它。

此外,如果您在 div 上添加 onFocus 事件,您可以管理下拉菜單何時打開。

export default function App() {
    const [option, setOption] = useState("");
    const [isOpen, setIsOpen] = useState(false);

    const close = () => {
        setIsOpen(false);
    }
    const open = () => {
        setIsOpen(true);
    }
    const selectValue = (event) => {
        const value = event.target.value;
        setOption(value);
        close();
    }

    return (
        <div className="App">
        <h2>Option: {option}</h2>
        <p>
            Dropdown should close when I click outside it
            <br />
            Option Number should update
        </p>

        <div className="dropdown" tabIndex={0} onBlur={close} onFocus={open}>
            <button onClick={open}>•••</button>

            <div className={`list ${isOpen ? "display" : ""} `}>
            <ul>
                <li value={1} onClick={selectValue}>Option 1</li>
                <li value={2} onClick={selectValue}>Option 2</li>
            </ul>
            </div>
        </div>
        </div>
    );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM