Поиск в аккордеоне

У меня есть гармошка с заголовками разделов и отдельными элементами. Я собираюсь сослаться на идентификатор элемента, чтобы перейти к соответствующему разделу, но хочу использовать окно поиска для поиска «раздела 1» и т. д.

var acc = document.getElementByClassName("accordion");
var i;

for (i = 0; i < acc.length; i++) {
  acc[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var panel = this.nextElementSibling;
    if (panel.style.maxHeight){
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + "px";
    } 
  });
}

function myFunction() {
    var input, filter, ul, li, a, i, txtValue;
    input = document.getElementById("DefinitionSearch");
    filter = input.value.toUpperCase();
    ul = document.getElementByClassName("button");
    li = ul.getElementsByTagName("button");
    for (i = 0; i < li.length; i++) {
        a = li[i].getElementsByTagName("a")[0];
        txtValue = a.textContent || a.innerText;
        if (txtValue.toUpperCase().indexOf(filter) > -1) {
            li[i].style.display = "";
        } else {
            li[i].style.display = "none";
        }
    }
}
.accordion {
  background-color: #1AD879;
  color: #FFFFFF;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
  transition: 1.6s;
}

.active, .accordion:hover {
  background-color: #45F99F;
}

.panel {
  padding: 0 18px;
  background-color: #FFFFFF;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.8s ease-out;
}
<!--  -->
<h1>Search the definitions</h1>

<input type = "text" id = "DefinitionSearch" onkeyup = "myFunction()" placeholder = "Search for a definition" title = "Type in a name">

<h1>Section Header</h1>
<br>
<hr>
<button class = "accordion">Subject 1</button>
<div class = "panel">
<br>
<p class = "accordiontext">Subject definition</p>
<br>
</div>
<button class = "accordion">Subject 2</button>
<div class = "panel">
<br>
<p class = "accordiontext">Subject definition</p>
<br>
</div>
<button class = "accordion">Subject 3</button>
<div class = "panel">
<br>
<p class = "accordiontext">Subject definition</p>
<br>
</div>
<button class = "accordion">Subject 4</button>
<div class = "panel">
<br>
<p class = "accordiontext">Subject definition</p>
<br>
</div>
<hr>

Итак, если вы введете «Раздел 1» в поле поиска, оно прокрутится до этой позиции на странице, возможно, откроет ее. Если нет относительно простого решения, я просто посоветую пользователям использовать ctl/cmd+f, но это менее элегантное решение, хотя оно делает то, что я хочу. Затем я просто дам ссылку на идентификатор заголовка для каждого раздела.

Поведение ключевого слова "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
10
1 594
2

Ответы 2

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

Я кодировал столько, сколько мог, но оказалось, что выделить текст на странице непросто. Поэтому я нашел простую JS-библиотеку, которая поможет выполнить эту часть тяжелой работы. Если вам нужны подробности, я оставил информацию в коде. Ниже приведен рабочий фрагмент всего. Взгляните и посмотрите, не пропустил ли я что-нибудь.

//Hilitor Settings
var highlightIndex = new Hilitor("highlightIndex");
highlightIndex.setMatchType("left");

//Globals
var input = document.getElementById("DefinitionSearch");
var acc = document.getElementsByClassName("accordion");

//Open Subject Accordion
[].forEach.call(acc, function(item, index, a) {
  item.addEventListener("click", function() {
    var panel = this.nextElementSibling;
    this.classList.toggle("active");
    if (panel.style.maxHeight) {
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + "px";
    }
  });
});

//Search Accordings; Highlight & Open Matching Areas
input.addEventListener("keyup", function(event) {
  if (event.which === 13 || event.keyCode === 13) {

    var input, filter, i, acc, panels, txtValue, searchText, searchTitle;
    input = document.getElementById("DefinitionSearch");
    filter = input.value.toUpperCase();
    acc = document.getElementsByClassName("accordion");
    panels = document.getElementsByClassName("panel");

    for (i = 0; i < panels.length; i++) {
      for (i = 0; i < acc.length; i++) {
        searchText = panels[i].textContent || panels[i].innerText;
        searchTitle = acc[i].textContent || acc[i].innerText;
        if (input.value !== "") {
          if (searchText.toUpperCase().indexOf(filter) > -1 || searchTitle.toUpperCase().indexOf(filter) > -1) {
            if (!acc[i].classList.contains("active")) {
              acc[i].classList.add("active");
            }
            highlightIndex.apply(filter);
            panels[i].style.maxHeight = panels[i].scrollHeight + "px";
            panels[i].scrollIntoView({
              behavior: 'smooth'
            });
          } else {
            if (acc[i].classList.contains("active")) {
              acc[i].classList.remove("active");
            }
            panels[i].style.maxHeight = null;
          }
        } else {
          highlightIndex.remove();
          if (acc[i].classList.contains("active")) {
            acc[i].classList.remove("active");
          }
          panels[i].style.maxHeight = null;
        }
      }
    }
  }
});

//Clear button
function clearBtn() {
  var input, i, acc, panels;
  input = document.getElementById("DefinitionSearch");
  acc = document.getElementsByClassName("accordion");
  panels = document.getElementsByClassName("panel");

  input.value = "";
  highlightIndex.remove();
  for (i = 0; i < panels.length; i++) {
    for (i = 0; i < acc.length; i++) {
      if (acc[i].classList.contains("active")) {
        acc[i].classList.remove("active");
      }
      panels[i].style.maxHeight = null;
    }
  }
}

// Highlight Script "hilitor.js" Found at: https://www.the-art-of-web.com/javascript/search-highlight/
// Original JavaScript code by Chirp Internet: www.chirp.com.au
// Please acknowledge use of this code by including this header.
function Hilitor(id, tag) {

  // private variables
  var targetNode = document.getElementById(id) || document.body;
  var hiliteTag = tag || "MARK";
  var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM|SPAN)$");
  //var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"];
  var colors = ["#ff6"];
  var wordColor = [];
  var colorIdx = 0;
  var matchRegExp = "";
  var openLeft = false;
  var openRight = false;

  // characters to strip from start and end of the input string
  var endRegExp = new RegExp('^[^\\w]+|[^\\w]+$', "g");

  // characters used to break up the input string into words
  var breakRegExp = new RegExp('[^\\w\'-]+', "g");

  this.setEndRegExp = function(regex) {
    endRegExp = regex;
    return endRegExp;
  };

  this.setBreakRegExp = function(regex) {
    breakRegExp = regex;
    return breakRegExp;
  };

  this.setMatchType = function(type) {
    switch (type) {
      case "left":
        this.openLeft = false;
        this.openRight = true;
        break;

      case "right":
        this.openLeft = true;
        this.openRight = false;
        break;

      case "open":
        this.openLeft = this.openRight = true;
        break;

      default:
        this.openLeft = this.openRight = false;

    }
  };

  this.setRegex = function(input) {
    input = input.replace(endRegExp, "");

    //The next two deal with the search, If you want to seach somthing like subject 1 and not see all words with subject highlighted then keep the settings as is. If you want to see them all highlighted then uncomment ...(breakRegExp, "|") and comment out the current setting ...(breakRegExp, " ")

    //input = input.replace(breakRegExp, "|");
    input = input.replace(breakRegExp, " ");

    input = input.replace(/^\||\|$/g, "");
    if (input) {
      var re = "(" + input + ")";
      if (!this.openLeft) re = "\\b" + re;
      if (!this.openRight) re = re + "\\b";
      matchRegExp = new RegExp(re, "i");
      return matchRegExp;
    }
    return false;
  };

  this.getRegex = function() {
    var retval = matchRegExp.toString();
    retval = retval.replace(/(^/(\\b)?|\(|\)|(\\b)?/i$)/g, "");
    retval = retval.replace(/\|/g, " ");
    return retval;
  };

  // recursively apply word highlighting
  this.hiliteWords = function(node) {
    if (node === undefined || !node) return;
    if (!matchRegExp) return;
    if (skipTags.test(node.nodeName)) return;

    if (node.hasChildNodes()) {
      for (var i = 0; i < node.childNodes.length; i++)
        this.hiliteWords(node.childNodes[i]);
    }
    if (node.nodeType == 3) { // NODE_TEXT
      if ((nv = node.nodeValue) && (regs = matchRegExp.exec(nv))) {
        if (!wordColor[regs[0].toLowerCase()]) {
          wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length];
        }

        var match = document.createElement(hiliteTag);
        match.appendChild(document.createTextNode(regs[0]));
        match.style.backgroundColor = wordColor[regs[0].toLowerCase()];
        match.style.color = "#000";

        var after = node.splitText(regs.index);
        after.nodeValue = after.nodeValue.substring(regs[0].length);
        node.parentNode.insertBefore(match, after);
      }
    };
  };

  // remove highlighting
  this.remove = function() {
    var arr = document.getElementsByTagName(hiliteTag);
    while (arr.length && (el = arr[0])) {
      var parent = el.parentNode;
      parent.replaceChild(el.firstChild, el);
      parent.normalize();
    }
  };

  // start highlighting at target node
  this.apply = function(input) {
    this.remove();
    if (input === undefined || !input) return;
    if (this.setRegex(input)) {
      this.hiliteWords(targetNode);
    }
    return matchRegExp;
  };

}
.accordion {
  background-color: #1AD879;
  color: #FFFFFF;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
  transition: 1.6s;
}

.active,
.accordion:hover {
  background-color: #45F99F;
}

.panel {
  padding: 0 18px;
  background-color: #FFFFFF;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.8s ease-out;
}
<h1>Search the definitions</h1>

<input type = "text" id = "DefinitionSearch" placeholder = "Search for a definition" title = "Type in a name">
<button type = "button" id = "clearHighlight" onclick = "clearBtn();">Clear</button>


<h1>Section Header</h1>
<br>
<div id = "highlightIndex">
  <hr>
  <button class = "accordion">Subject 1</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">hello</p>
    <br>
  </div>
  <button class = "accordion">Subject 2</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">world</p>
    <br>
  </div>
  <button class = "accordion">Subject 3</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">definition.</p>
    <br>
  </div>
  <button class = "accordion">Subject 4</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">definition with more text.</p>
    <br>
  </div>
  <button class = "accordion">Subject 5</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">make the page longer</p>
    <br>
  </div>
  <button class = "accordion">Subject 6</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">to see the scroll effect</p>
    <br>
  </div>
  <button class = "accordion">Subject 7</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">stackoverflow</p>
    <br>
  </div>
  <button class = "accordion">Subject 8</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">many subjects</p>
    <br>
  </div>
  <button class = "accordion">Subject 9</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">this is the end.</p>
    <br>
  </div>
  <hr>
</div>

Я улучшил код, который сделал Рик Сибли.

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

//Hilitor Settings
var highlightIndex = new Hilitor("highlightIndex");
highlightIndex.setMatchType("left");

//Globals
var input = document.getElementById("DefinitionSearch");
var acc = document.getElementsByClassName("accordion");

//Open Subject Accordion
[].forEach.call(acc, function(item, index, a) {
  item.addEventListener("click", function() {
    var panel = this.nextElementSibling;
    this.classList.toggle("active");
    if (panel.style.maxHeight) {
      panel.style.maxHeight = null;
    } else {
      panel.style.maxHeight = panel.scrollHeight + "px";
    }
  });
});

//Search Accordings; Highlight & Open Matching Areas
input.addEventListener("keyup", function(event) {
  if (event.which === 13 || event.keyCode === 13) {

    var input, filter, i, acc, panels, txtValue, searchText, searchTitle;
    input = document.getElementById("DefinitionSearch");
    filter = input.value.toUpperCase();
    acc = document.getElementsByClassName("accordion");
    panels = document.getElementsByClassName("panel");

    for (i = 0; i < panels.length; i++) {
      for (i = 0; i < acc.length; i++) {
        searchText = panels[i].textContent || panels[i].innerText;
        searchTitle = acc[i].textContent || acc[i].innerText;
        if (input.value !== "") {
          if (searchText.toUpperCase().indexOf(filter) > -1 || searchTitle.toUpperCase().indexOf(filter) > -1) {
            if (!acc[i].classList.contains("active")) {
              acc[i].classList.add("active");
            }
            highlightIndex.apply(filter);
            panels[i].style.maxHeight = panels[i].scrollHeight + "px";
            panels[i].scrollIntoView({
              behavior: 'smooth'
            });
          } else {
            if (acc[i].classList.contains("active")) {
              acc[i].classList.remove("active");
              highlightIndex.remove();
            }
            panels[i].style.maxHeight = null;
          }
        } else {
          highlightIndex.remove();
          if (acc[i].classList.contains("active")) {
            acc[i].classList.remove("active");
          }
          panels[i].style.maxHeight = null;
        }
      }
    }
  }
});

//Clear button
function clearBtn() {
  var input, i, acc, panels;
  input = document.getElementById("DefinitionSearch");
  acc = document.getElementsByClassName("accordion");
  panels = document.getElementsByClassName("panel");

  input.value = "";
  highlightIndex.remove();
  for (i = 0; i < panels.length; i++) {
    for (i = 0; i < acc.length; i++) {
      if (acc[i].classList.contains("active")) {
        acc[i].classList.remove("active");
      }
      panels[i].style.maxHeight = null;
    }
  }
}

// Highlight Script "hilitor.js" Found at: https://www.the-art-of-web.com/javascript/search-highlight/
// Original JavaScript code by Chirp Internet: www.chirp.com.au
// Please acknowledge use of this code by including this header.
function Hilitor(id, tag) {

  // private variables
  var targetNode = document.getElementById(id) || document.body;
  var hiliteTag = tag || "MARK";
  var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM|SPAN)$");
  //var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"];
  var colors = ["#ff6"];
  var wordColor = [];
  var colorIdx = 0;
  var matchRegExp = "";
  var openLeft = false;
  var openRight = false;

  // characters to strip from start and end of the input string
  var endRegExp = new RegExp('^[^\\w]+|[^\\w]+$', "g");

  // characters used to break up the input string into words
  var breakRegExp = new RegExp('[^\\w\'-]+', "g");

  this.setEndRegExp = function(regex) {
    endRegExp = regex;
    return endRegExp;
  };

  this.setBreakRegExp = function(regex) {
    breakRegExp = regex;
    return breakRegExp;
  };

  this.setMatchType = function(type) {
    switch (type) {
      case "left":
        this.openLeft = false;
        this.openRight = true;
        break;

      case "right":
        this.openLeft = true;
        this.openRight = false;
        break;

      case "open":
        this.openLeft = this.openRight = true;
        break;

      default:
        this.openLeft = this.openRight = false;

    }
  };

  this.setRegex = function(input) {
    input = input.replace(endRegExp, "");

    //The next two deal with the search, If you want to seach somthing like subject 1 and not see all words with subject highlighted then keep the settings as is. If you want to see them all highlighted then uncomment ...(breakRegExp, "|") and comment out the current setting ...(breakRegExp, " ")

    //input = input.replace(breakRegExp, "|");
    input = input.replace(breakRegExp, " ");

    input = input.replace(/^\||\|$/g, "");
    if (input) {
      var re = "(" + input + ")";
      if (!this.openLeft) re = "\\b" + re;
      if (!this.openRight) re = re + "\\b";
      matchRegExp = new RegExp(re, "i");
      return matchRegExp;
    }
    return false;
  };

  this.getRegex = function() {
    var retval = matchRegExp.toString();
    retval = retval.replace(/(^/(\\b)?|\(|\)|(\\b)?/i$)/g, "");
    retval = retval.replace(/\|/g, " ");
    return retval;
  };

  // recursively apply word highlighting
  this.hiliteWords = function(node) {
    if (node === undefined || !node) return;
    if (!matchRegExp) return;
    if (skipTags.test(node.nodeName)) return;

    if (node.hasChildNodes()) {
      for (var i = 0; i < node.childNodes.length; i++)
        this.hiliteWords(node.childNodes[i]);
    }
    if (node.nodeType == 3) { // NODE_TEXT
      if ((nv = node.nodeValue) && (regs = matchRegExp.exec(nv))) {
        if (!wordColor[regs[0].toLowerCase()]) {
          wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length];
        }

        var match = document.createElement(hiliteTag);
        match.appendChild(document.createTextNode(regs[0]));
        match.style.backgroundColor = wordColor[regs[0].toLowerCase()];
        match.style.color = "#000";

        var after = node.splitText(regs.index);
        after.nodeValue = after.nodeValue.substring(regs[0].length);
        node.parentNode.insertBefore(match, after);
      }
    };
  };

  // remove highlighting
  this.remove = function() {
    var arr = document.getElementsByTagName(hiliteTag);
    while (arr.length && (el = arr[0])) {
      var parent = el.parentNode;
      parent.replaceChild(el.firstChild, el);
      parent.normalize();
    }
  };

  // start highlighting at target node
  this.apply = function(input) {
    this.remove();
    if (input === undefined || !input) return;
    if (this.setRegex(input)) {
      this.hiliteWords(targetNode);
    }
    return matchRegExp;
  };

}
.accordion {
  background-color: #1AD879;
  color: #FFFFFF;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
  transition: 1.6s;
}

.active,
.accordion:hover {
  background-color: #45F99F;
}

.panel {
  padding: 0 18px;
  background-color: #FFFFFF;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.8s ease-out;
}
<h1>Search the definitions</h1>

<input type = "text" id = "DefinitionSearch" placeholder = "Search for a definition" title = "Type in a name">
<button type = "button" id = "clearHighlight" onclick = "clearBtn();">Clear</button>


<h1>Section Header</h1>
<br>
<div id = "highlightIndex">
  <hr>
  <button class = "accordion">Subject 1</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">hello</p>
    <br>
  </div>
  <button class = "accordion">Subject 2</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">world</p>
    <br>
  </div>
  <button class = "accordion">Subject 3</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">definition.</p>
    <br>
  </div>
  <button class = "accordion">Subject 4</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">definition with more text.</p>
    <br>
  </div>
  <button class = "accordion">Subject 5</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">make the page longer</p>
    <br>
  </div>
  <button class = "accordion">Subject 6</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">to see the scroll effect</p>
    <br>
  </div>
  <button class = "accordion">Subject 7</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">stackoverflow</p>
    <br>
  </div>
  <button class = "accordion">Subject 8</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">many subjects</p>
    <br>
  </div>
  <button class = "accordion">Subject 9</button>
  <div class = "panel">
    <br>
    <p class = "accordiontext">this is the end.</p>
    <br>
  </div>
  <hr>
</div>

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