Реагировать, не удается сфокусировать пункт меню при использовании клавиатуры - PullRequest
0 голосов
/ 10 ноября 2019

Контекст

Все действия выполняются только с клавиатуры, без щелчка мыши.

Пример :

У меня естьТаблица из 2 столбцов с файлом и кнопкой.

При нажатии клавиши ввода на button1 появится меню (содержит загрузку, просмотр, удаление). В фокусе button1

Нажмите кнопку со стрелкой вниз, фон download подсвечен синим цветом.

enter image description here

Моя проблема

Я хочу, чтобы кнопка download была Фокус вместо button1, при нажатии стрелки вниз на button1

Полный код:

import React, {useState, useEffect, useRef, createRef, useContext} from 'react';

const AppContext = React.createContext({
  name: 'AppContext'
});

const createMenuItemRefs = (items, rowInd) => {
  // obj
  let menuItemRefs = {};
  // loop each
  for (let i = 0; i < Object.keys(items).length; i++) {
    // When assign createRef, no current
    menuItemRefs[rowInd + i] = createRef();
  }
  return menuItemRefs;
};

function Menu({buttonName, parentRowIndex}) {
  const [currRowInd, setCurrRowInd] = useState('');
  const [open, setOpen] = useState(false);
  // press down key, will get 1st item which at index 0
  const [menuItemActiveIndex, setMenuItemActiveIndex] = useState(-1);

  const menuItems = {download: 'download', view: 'view', delete: 'delete'};
  const menuItemRefs = useRef(createMenuItemRefs(menuItems, parentRowIndex));

  useEffect(() => {
    if (open && menuItemActiveIndex >= 0 && parentRowIndex !== '') {
      menuItemRefs.current[parentRowIndex + menuItemActiveIndex].focus();
    }
  }, [menuItemActiveIndex, open, parentRowIndex]);

  // on the button level
  const buttonIconKeyDown = (event, parentRowIndex) => {
    if (event.keyCode === 13) {
      // Enter pressed
      console.log('enter is pressed');

      setOpen(!open);
      setCurrRowInd(parentRowIndex);
    } else if (event.keyCode === 9) {
      // tab away
      console.log('tab away');

      setOpen(!open);
      setCurrRowInd('');
    } else if (event.keyCode === 40) {
      //test
      console.log('down arrow');

      // 38 is up arrow

      // No scrolling
      event.preventDefault();

      // set to 1st item in 0 index
      setMenuItemActiveIndex(0);
    }
  };

  //test
  console.log(
    'menuItemRefs.current',
    menuItemRefs.current,
    'menuItemActiveIndex',
    menuItemActiveIndex
  );

  return (
    <div>
      <button
        onKeyDown={event => {
          //test
          console.log('parent buttonicon onkeydown: ');
          buttonIconKeyDown(event, parentRowIndex);
        }}
      >
        {buttonName}
      </button>

      {open && parentRowIndex === currRowInd && (
        <ul style={{padding: '5px', margin: '10px', border: '1px solid #ccc'}}>
          {Object.keys(menuItems).map((item, itemIndex) => {
            if (itemIndex === menuItemActiveIndex)
              return (
                <li
                  key={itemIndex}
                  style={{
                    listStyle: 'none',
                    padding: '5px',
                    backgroundColor: 'blue'
                  }}
                  // put a ref
                  ref={element =>
                    (menuItemRefs.current[parentRowIndex + itemIndex] = element)
                  }
                >
                  <button>{item}</button>
                </li>
              );
            else
              return (
                <li
                  key={itemIndex}
                  style={{listStyle: 'none', padding: '5px'}}
                  ref={element =>
                    (menuItemRefs.current[parentRowIndex + itemIndex] = element)
                  }
                >
                  <button>{item}</button>
                </li>
              );
          })}
        </ul>
      )}
    </div>
  );
}

function TableElement() {
  const items = [
    {
      file: 'file1',
      button: 'button1'
    },
    {
      file: 'file2',
      button: 'button2'
    },
    {
      file: 'file3',
      button: 'button3'
    }
  ];
  return (
    <table style={{borderCollapse: 'collapse', border: '1px solid black'}}>
      <tbody>
        {items.map((item, index) => {
          return (
            <tr key={index}>
              <td style={{border: '1px solid black'}}>
                <a href="#">{item.file}</a>
              </td>
              <td style={{border: '1px solid black'}}>
                <Menu buttonName={item.button} parentRowIndex={index} />
              </td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}

function App() {
  const appContextObj = {};

  return (
    <>
      <AppContext.Provider value={appContextObj}>
        <TableElement />
      </AppContext.Provider>
    </>
  );
}

export default App;

github https://github.com/kenpeter/key-mouse-dropdown/tree/feature/focus

1 Ответ

0 голосов
/ 10 ноября 2019

В вашем useEffect блоке

useEffect(() => {
  if (open && menuItemActiveIndex >= 0 && parentRowIndex !== '') {
    menuItemRefs.current[parentRowIndex + menuItemActiveIndex].children[0].focus();
  }
}, [menuItemActiveIndex, open, parentRowIndex]);

В этом случае вы можете вызывать фокус на ваших детях <button> вместо того, чтобы вместо этого сфокусироваться на вашем <li>. Обратите внимание, что если приведенный выше код всегда будет фокусироваться на первом дочернем элементе вашего текущего экземпляра ссылки.

Бонус:

Вы также можете использовать tabIndex={-1} на любых элементах, чтобы предотвратить его фокусировку. .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...