Как активировать пункт раскрывающегося меню начальной загрузки, нажав клавишу клавиатуры

Панель навигации Bootstrap 5 содержит выпадающие меню.
В раскрывающихся меню есть подчеркнутые горячие клавиши, такие как a,n,s,e :

<div class = "btn-group">
  <button type = "button" class = "btn btn-danger dropdown-toggle" data-bs-toggle = "dropdown" aria-expanded = "false">
    Action
  </button>
  <ul class = "dropdown-menu">
    <li><a class = "dropdown-item" href = "#"><u>A</u>ction</a></li>
    <li><a class = "dropdown-item" href = "#">A<u>n</u>other action</a></li>
    <li><a class = "dropdown-item" href = "#"><u>S</u>omething else here</a></li>
    <li><hr class = "dropdown-divider"></li>
    <li><a class = "dropdown-item" href = "#">S<u>e</u>parated link</a></li>
  </ul>
</div>

Как активировать пункт меню, если нажать клавишу на клавиатуре? Например, если раскрывающееся меню открыто, нажатие A должно действовать так же, как щелчок по пункту меню «Действие».

jsfiddle: https://jsfiddle.net/b6or2s5e/

Стрелки влево и вправо уже обрабатываются с помощью

Как использовать клавиши со стрелками влево и вправо для навигации по навигационной панели начальной загрузки

document.addEventListener("DOMContentLoaded", function () {
  document.querySelectorAll('.dropdown').forEach(function (el) {
    el.addEventListener('shown.bs.dropdown', function () {
      document.addEventListener('keydown', function (e) {
        const click = new MouseEvent("click", {
          bubbles: true,
          cancelable: true,
          view: window,
        })
        if (e.key === "ArrowRight") {
          const o = getNextSibling(e.target.closest('.dropdown'), '.dropdown')
          if (!o) {
            document.querySelector('.dropdown-toggle').dispatchEvent(click)
          } else {
            o.querySelector('.Xdropdown-toggle').dispatchEvent(click)
          }
        } else if (e.key === "ArrowLeft") {
          const o = getPrevSibling(e.target.closest('.dropdown'), '.dropdown')
          if (!o) {
            const ar = document.querySelectorAll('.dropdown-toggle')
            ar[ar.length - 1].dispatchEvent(click)
          } else {
            o.querySelector('.dropdown-toggle').dispatchEvent(click)
          }
        }
      }, { once: true })
    })
  })
})

Как добавить обработку горячих клавиш?

Это то, что вам нужно? jsfiddle.net/mj304z2w

dale landry 11.08.2024 04:34

Да, это так. Он использует жестко запрограммированные значения горячих клавиш в переключателе. Как это изменить, чтобы горячие клавиши не были жестко прописаны в коде? Можно ли удалить оператор switch и вызвать findUnderlined для любой клавиши, если alt или ctrl не нажаты?

Andrus 11.08.2024 10:36

Как это изменить, чтобы горячие клавиши не были жестко прописаны в коде? , позвольте мне взглянуть на фрагмент и посмотреть, смогу ли я как-нибудь вытащить их из списка узлов... Можно ли удалить оператор switch и вызвать findUnderlined для любой клавиши, если alt или ctrl не нажаты? можно поподробнее, немного не совсем понимаю, что вы имеете в виду...

dale landry 11.08.2024 18:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот обновленный фрагмент с динамическим подходом: получение подчеркнутых элементов и использование цикла forEach для списка узлов подчеркнутых элементов для сравнения события keydown в окне с текстовым контентом каждого подчеркнутого элемента, преобразованного в toLowerCase(), а затем сравнения. Если есть совпадение, мы запускаем click() для соответствующего элемента.

Можно ли удалить оператор switch и вызвать findUnderlined для любой клавиши, если alt или ctrl не нажаты?

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

Дополнительные примечания см. во фрагменте ниже...

document.addEventListener("DOMContentLoaded", function() {
  // get drop-down menu
  const dropdownMenu = document.querySelector('.dropdown-menu');
  // get action button
  const action = document.querySelector('#dropdown-btn');
  // get the underlined elements as a nodelist
  const sections = dropdownMenu.querySelectorAll('li u');
  // helper function pass in underlined els and event key
  const setClickForUnderlinedEls = (els, key) => {
    // loop over underlined elements
    els.forEach(sec => {
      // conditional to compare the underlined 
      // elements text to lowercase
      if (key === sec.textContent.toLowerCase()) {
        // simulate a click on element
        sec.click()
      }
    });
  }
  // event click on action button to open dropdown
  action.addEventListener('click', (event) => {
    // window event on keydown to check key
    addEventListener('keydown', (e) => {
      // make sure the dropdown is expanded 
      // using aria-expanded attribute
      if (event.target.ariaExpanded !== 'false') {
        // run helper function to compare the key and
        // the underlined elements textContent
        setClickForUnderlinedEls(sections, e.key);
      }
    });
  })
});

document.addEventListener("DOMContentLoaded", function() {
  const dropdownMenu = document.querySelector('.dropdown-menu');
  const action = document.querySelector('#dropdown-btn');
  const sections = dropdownMenu.querySelectorAll('li u');
  const setClickForUnderlinedEls = (els, key) => {
    els.forEach(sec => {
      if (key === sec.textContent.toLowerCase()) {
        sec.click()
      }
    });
  }
  action.addEventListener('click', (event) => {
    addEventListener('keydown', (e) => {
      if (event.target.ariaExpanded !== 'false') {
        setClickForUnderlinedEls(sections, e.key);
      }
    });
  })
});
#vertical-space,
#section1,
#section2,
#section3,
#section4,
#section5{
  height: 100vh;
}
<link href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel = "stylesheet" integrity = "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin = "anonymous">
<script src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity = "sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin = "anonymous"></script>

<!-- Example single danger button -->
<div class = "btn-group" id = "top">
  <!--/ Added the id dropdown-btn for this example /-->
  <button id = "dropdown-btn" type = "button" class = "btn btn-danger dropdown-toggle" data-bs-toggle = "dropdown" aria-expanded = "false">
    Action
  </button>
  <ul class = "dropdown-menu">
    <li><a class = "dropdown-item" href = "#section1"><u>A</u>ction</a></li>
    <li><a class = "dropdown-item" href = "#section2">A<u>n</u>other action</a></li>
    <li><a class = "dropdown-item" href = "#section3"><u>W</u>e have a link</a></li>
    <li><a class = "dropdown-item" href = "#section4"><u>S</u>omething else here</a></li>
    <li>
      <hr class = "dropdown-divider">
    </li>
    <li><a class = "dropdown-item" href = "#section5">S<u>e</u>parated link</a></li>
  </ul>
</div>
<!--/ added purely for example /-->
<div id = "vertical-space">
</div>
<div id = "section1">
  <p>
    You pressed the <strong>a</strong> button and instantiated a click on the <em>Action</em> button. <a href = "#top">Back to top</a>
  </p>
  
</div>
<div id = "section2">
  <p>
    You pressed the <strong>n</strong> button and instantiated a click on the <em>Another action</em> button. <a href = "#top">Back to top</a>
  </p>
</div>
<div id = "section3">
  <p>
    You pressed the <strong>w</strong> button and instantiated a click on the <em>We have a link</em> button. <a href = "#top">Back to top</a>
  </p>
</div>
<div id = "section4">
  <p>
    You pressed the <strong>s</strong> button and instantiated a click on the <em>Something else here</em> button. <a href = "#top">Back to top</a>
  </p>
</div>
<div id = "section5">
  <p>
    You pressed the <strong>e</strong> button and instantiated a click on the <em>Separate link</em> button. <a href = "#top">Back to top</a>
  </p>
</div>

Зачем нужен const nextEl = target.nextElementSibling? nextEl не используется.

Andrus 11.08.2024 21:15
setClickForUnderlinedEls второй параметр можно удалить.
Andrus 11.08.2024 21:30

@Андрус отредактировал, спасибо за предупреждение.

dale landry 12.08.2024 00:14

Спасибо. Большой. Я разместил соответствующий вопрос в stackoverflow.com/questions/78863181/…

Andrus 12.08.2024 20:49

Другие вопросы по теме