Styled-components onFocus и onBlur не работают - PullRequest
2 голосов
/ 10 июля 2020

Я использую React JS + Typescript для своего приложения. Для стилизации я использую styled-components . Я действительно новичок в стилизованных компонентах. Я создал одно раскрывающееся меню. Логи c отлично работает. Но когда я нахожусь за пределами кнопки раскрывающегося списка, он все равно отображает список параметров. Я хочу скрыть список, когда он находится за пределами раскрывающегося списка. Я пробовал все до единого, но у меня ничего не вышло. Вот так это выглядит, когда он находится вне focus:

enter image description here

This is my Dropdown component

import React, { useState } from "react";
import styled from "styled-components";
import Arrow from './Arrow.svg'

const Wrapper = styled.div`
  box-sizing: border-box;
  border: 1 solid #d2d6dc;
`;

const MenuLabel = styled.span`
box-shadow: 0 1px 2px 0 rgba(0,0,0,.05);
border-radius: .375rem;
& after,
& before:{
  box-sizing: border-box;
  border: 0 solid #d2d6dc;
}
`;

const ItemList = styled.div`
color: #798697;
background: white;
line-height: 30px;
padding: .25em 2em .25em 2em;
cursor: defaul;
user-select: none;
transition: all .25s ease;
&:hover,
&.selected {
  background: #F7F7F7;
  color: #4A4A4A;
}

`;

const Button = styled.button<{ isOpen?: boolean }>`
display:inline-flex;
padding: 10px 30px;
font-size: 14px;
justify-content: center;
border-radius:5px;
position: relative;
background: white;
font-size: 12px;
border-color: gray;
transition: ease-in-out .2s;
& hover:{
color: gray;
}
&:focus {
  border: 1px solid blue;
  outline: none;
}

`

const CaratContainer = styled.img<{ isOpen?: boolean }>`
  transform: ${props => (props.isOpen ? "rotate(180deg)" : "rotate(0deg)")};
  transition: all 0.2s ease;
  height: 30px;
  width:20px
`;

const DropDown = styled.ul`
`

export interface IOptions {
  label: string;
  value: number;
}

export interface IDropdown {
  labelDefault: string;
  options: IOptions[];
  onClick?: () => void;
  style?: React.CSSProperties;
  onFocus?: () => void;
  onBlur?: () => void;
}


const Dropdown = ({ labelDefault, options, onClick, style, onFocus, onBlur }: IDropdown) => {
  const [isOpened, setIsOpened] = useState(false);
  const [selectedOption, setSelectedOption] = useState("");
  const [label, setLabel] = useState("");
  const [isFocussed, setIsFocussed] = useState(false)

  const handleSelectedItem = (obj: any) => {
    setSelectedOption(obj.value);
    setLabel(obj.label);
    setIsOpened(!isOpened);
  };

  return (
    

      
      {isOpened ? options.map(el => (
         handleSelectedItem(el)}
          onFocus={() => {
            setIsFocussed(true);
            onFocus && onFocus()
          }}
          onBlur={() => {
            setIsFocussed(false);
            onBlur && onBlur()
          }}
        >
          {el.label}
        
      )) : null}


    
  );
}
export default Dropdown;

This is the parent component

import * as React from "react";
import Dropdown from "./dropdown";

const MockData = [
  { label: "one", value: 1 },
  { label: "two", value: 2 },
  { label: "three", value: 3 }
];

export default function App() {
  return (
      Hello CodeSandbox  ); } 

Ответы [ 2 ]

0 голосов
/ 10 июля 2020

Если я понимаю вашу проблему / вопрос, похоже, вы хотите, чтобы раскрывающийся список закрывался, когда он теряет фокус.

Изменить - используйте функцию «обрабатывать внешнее событие», не беспокойтесь об управлении фокусом

Создать эффект, который добавляет / удаляет прослушиватель событий для события, возникающего вне оболочки раскрывающегося списка.

const dropdownRef = useRef();

useEffect(() => {
  const externalEventHandler = e => {
    if (!isOpened) return;

    const node = dropdownRef.current;

    if (node && node.contains(e.target)) {
      return;
    }

    setIsOpened(false);
  }

  if (isOpened) {
    document.addEventListener('click', externalEventHandler);
  } else {
    document.removeEventListener('click', externalEventHandler);
  }
  
  return () => {
    document.removeEventListener('click', externalEventHandler);
  }
}, [isOpened]);

Пришлось сделать оболочку неблокирующим уровнем элемент, иначе вы должны щелкнуть полностью выше или ниже раскрывающегося списка.

const Wrapper = styled.div`
  display: inline; // <-- no block level element
  box-sizing: border-box;
  border: 1 solid #d2d6dc;
`;

Править пылкий-туман-btwei

0 голосов
/ 10 июля 2020

Помните, что onBlur означает, что элемент теряет фокус. Это происходит, когда другой элемент получает фокус или вы просто щелкаете где-нибудь на странице, а не когда курсор перемещается.

Еще я заметил, что вы используете переменную isOpened, чтобы определить, должен ли ваш ItemList получить визуализацию, а курсор должен быть повернут, но в методах onFocus и onBlur вы устанавливаете состояние isFocussed.

Похоже, вы просто используете setIsFocussed, но никогда не используете isFocussed. Возможно, вы захотите проверить ESLint , он поможет вам легко обнаруживать подобные ошибки.

...