Как найти через скрипт

Время на прочтение
8 мин

Количество просмотров 95K

Пару дней назад получил тестовое задание от компании на вакансию Front-end dev. Конечно же, задание состояло из нескольких пунктов. Но сейчас речь пойдет только об одном из них — организация поиска по странице. Т.е. банальный поиск по введенному в поле тексту (аналог Ctrl+F в браузере). Особенность задания была в том, что использование каких-либо JS фреймворков или библиотек запрещено. Все писать на родном native JavaScript.

(Для наглядности далее буду сопровождать всю статью скринами и кодом, чтоб мне и вам было понятнее, о чем речь в конкретный момент)

Поиск готового решения

Первая мысль: кто-то уже точно такое писал, надо нагуглить и скопипастить. Так я и сделал. За час я нашел два неплохих скрипта, которые по сути работали одинаково, но были написаны по-разному. Выбрал тот, в коде которого лучше разобрался и вставил к себе на старничку.

Если кому интересно, код брал тут.

Скрипт сразу заработал. Я думал, что вопрос решен, но как оказалось, не в обиду автору скрипта, в нем был огромный недостаток. Скрипт вел поиск по всему содержимому тега ... и, как вы уже наверное догадались, при поиске любого сочетания символов, которые напоминают тег или его атрибуты, ломалась вся страница HTML.

Почему скрипт работал некорректно?

Все просто. Скрипт работает следующим образом. Сперва в переменную записываем все содержимое тега body, затем ищем совпадения с регулярным выражением (задает пользователь при вводе в текстовое поле) и затем заменяем все совпадения на следующий код:

<span style="background-color: yellow;">...найденное совпадение...</span>

А затем заменяем текущий тег body на новый полученный. Разметка обновляется, меняются стили и на экране подсвечиваются желтым все найденные результаты.

Вы уже наверняка поняли, в чем проблема, но я все же объясню подробней. Представьте, что в поле поиска ввели слово «div». Как вы понимаете, внутри body есть множество других тегов, в том числе и div. И если мы всем к «div» применим стили, указанные выше, то это уже будет не блок, а непонятно что, так как конструкция ломается. В итоге после перезаписи разметки мы получим полностью сломанную веб-страницу. Выглядит это так.

Было до поиска: выложить фото в интернетПросмореть полностью
Стало после поиска: выложить фото бесплатноПросмореть полностью

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

Итак пишем скрипт с нуля

Как все у меня выглядит.

Сейчас нас интересует форма с поиском. Обвел ее красной линией.

Давайте немного разберемся. Я это реализовал следующим образом (пока чистый HTML). Форма с тремя тегами.

Первый — для ввода текста;
Второй — для для отмены поиска (снять выделение);
Третий — для поиска (выделить найденные результаты).

<form>
      <input type="text" value="" placeholder="Search" autofocus> 
      <input type="button" value=" " title="Отменить поиск">
      <input  type="submit" value=" " title="Начать поиск">
</form>

Итак, у нас есть поле для ввода и 2 кнопки. JavaScript буду писать в файле js.js. Предпложим, что его вы уже создали и подключили.

Первое, что сделаем: пропишем вызовы функции при нажатии на кнопку поиска и кнопку отмены. Выглядеть будет так:

<form>
      <input class="place_for_search" type="text" id="text-to-find" value="" placeholder="Search" autofocus> 
      <input class="button_for_turn_back" type="button" onclick="javascript: FindOnPage('text-to-find',false); return false;" value=" " title="Отменить поиск">
      <input class="button_for_search" type="submit" onclick="javascript: FindOnPage('text-to-find',true); return false;" value=" " title="Начать поиск">
</form>

Давайте немного поясню что тут и зачем нужно.

Полю с текстом даем id=«text-to-find» (по этому id будем обращатсья к элементу из js).

Кнопке отмены даем такие атрибуты: type=«button» onclick=«javascript: FindOnPage(‘text-to-find’,false); return false;»

Тип: button
При нажатии вызывается функция FindOnPage(‘text-to-find’,false); и передает id поля с текстом, false

Кнопке поиска даем такие атрибуты: type=«button» onclick=«javascript: FindOnPage(‘text-to-find’,true); return false;»

Тип: submit (не кнопка потому, что тут можно юзать Enter после ввода в поле, а так можете и button использовать)
При нажатии вызывается функция FindOnPage(‘text-to-find’,true); и передает id поля с текстом, true

Вы наверняка заметили еще 1 атрибут: true/false. Его будем использовать для определения, на какую именно кнопку нажали (отменить поиск или начать поиск). Если жмем на отмену, то передаем false. Если жмем на поиск, то передаем true.

Окей, двигаемся дальше. Переходим к JavaScript

Будем считать, что вы уже создали и подключили js файл к DOM.

Прежде, чем начнем писать код, давайте отвлечемся и сперва обсудим, как все должно работать. Т.е. по сути пропишем план действий. Итак, нам надо, чтоб при вводе текста в поле шел поиск по странице, но нельзя затрагивать теги и атрибуты. Т.е. только текстовые объекты. Как этого достичь — уверен есть много способов. Но сейчас будем использовать регулярные выражения.

Итак, следующее регулярное выражение будет искать только текст след. вида: «>… текст…<«. Т.е. будет проходить поиск только текстовых объектов, в то время, как теги и атрибуты будут оставаться нетронутыми.

/>(.*?)</g

Так мы будем находить нужные части кода, которые будем парсить и искать совпадения с текстом, который ввел пользователь. Затем будем добавлять стили найденным объектам и после этого заменять html — код на новый.

Приступим. Сперва переменные, которые нам понадобятся.

var input,search,pr,result,result_arr, locale_HTML, result_store;
//input - принимаем текст, который ввел пользователь
//search - делаем из строки регулярное выражение
//pr - сохраняем в нее текущий <body></body>
//result - выборка текста из pr (т.е. отсекаем теги и атрибуты)
//result_arr - аналог pr, но со стилями для подсветки
//locale_HTML - оригинал <body></body> который менять не будем, используем для обнуления стилей

И сразу определим locale_HTML значение независимо от того, ищем мы что-то или нет. Это нужно, чтоб сразу сохранить оригинал страницы и иметь взможность обнулять стили.

var input,search,pr,result,result_arr, locale_HTML, result_store;

locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)

Ок, теперь уже стоит создать функцию, которая вызывается у нас из DOM. Сразу прикинем, что внутри у нас должны быть 2 функции, каждая из которых срабатывает в зависимости от нажатой кнопки. Ведь мы либо проводим поиск, либо обнуляем его. И контроллируется это атрибутом true/false, как вы помните. Так же надо понимать, что при повторном поиске прежние стили должны обнуляться. Таким образом получим следующее:

var input,search,pr,result,result_arr, locale_HTML, result_store;

locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)

function FindOnPage(name, status) {

        if(status) { FindOnPageBack(); FindOnPageGo(); } //чистим прошлое и Выделяем найденное
	if(!status) { FindOnPageBack(); } //Снимаем выделение
}

Ок, часть логики реализована, двигаемся дальше. Необходимо проверять полученное слово на количество символов. Ведь зачем нам искать 1 букву/символ. В общем, я решил эту возможность ограничить 3+ символа.

Итак, сперва приниамем значение, которое ввел пользователь, и, в зависимости от его длины, выполняем либо основную функцию поиска, либо функцию вывода предупреждения и обнуления. Выглядеть будет так:

var input,search,pr,result,result_arr, locale_HTML, result_store;

locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)

function FindOnPage(name, status) {

	input = document.getElementById(name).value; //получаем значение из поля в html
	
	if(input.length<3&&status==true) {
		alert('Для поиска вы должны ввести три или более символов');
		function FindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
	}
        
        if(input.length>=3)
	{
              //выполняем поиск
        }
        
        function FindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
        if(status) { FindOnPageBack(); FindOnPageGo(); } //чистим прошлое и Выделяем найденное
	if(!status) { FindOnPageBack(); } //Снимаем выделение
}

Сейчас поясню этот участок кода. Единственное, что могло стать не ясно — вот эта строка:

function FindOnPageBack() { document.body.innerHTML = locale_HTML; }

Тут все просто: метод innerHTML возвращает html код объекта. В данном случае мы просто заменяем текущий body на оригинальный, который мы сохранили при загрузке всей страницы.

Двигаемся дальше. Даем значения основным переменным.

var input,search,pr,result,result_arr, locale_HTML, result_store;

locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)

function FindOnPage(name, status) {

	input = document.getElementById(name).value; //получаем значение из поля в html
	
	if(input.length<3&&status==true) {
		alert('Для поиска вы должны ввести три или более символов');
		function FindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
	}
        
        if(input.length>=3)
	{
              function FindOnPageGo() {
                     search = '/'+input+'/g';  //делаем из строки регуярное выражение
		     pr = document.body.innerHTML;   // сохраняем в переменную весь body
		     result = pr.match(/>(.*?)</g);  //отсекаем все теги и получаем только текст
		     result_arr = [];   //в этом массиве будем хранить результат работы (подсветку)
              }
        }
        
        function FindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
        if(status) { FindOnPageBack(); FindOnPageGo(); } //чистим прошлое и Выделяем найденное
	if(!status) { FindOnPageBack(); } //Снимаем выделение
}

Итак, на данном этапе у нас уже есть основные переменные и значения. Теперь надо придать нужным участкам кода стили с выделенным фоном. Т.е. проверка выбранного текста на регулярное выражение (по сути мы выбранный регулярным выражением текст снова парсим регулярным выражением). Для этого надо из введенного текста сделать регулярное выражение (сделали), а затем выполнить метод, переданный в виде такста. Тут нам поможет метод eval().

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

var input,search,pr,result,result_arr, locale_HTML, result_store;

locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)

function FindOnPage(name, status) {

	input = document.getElementById(name).value; //получаем значение из поля в html
	
	if(input.length<3&&status==true) {
		alert('Для поиска вы должны ввести три или более символов');
		function FindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
	}
        
        if(input.length>=3)
	{
              function FindOnPageGo() {
                     search = '/'+input+'/g';  //делаем из строки регуярное выражение
		     pr = document.body.innerHTML;   // сохраняем в переменную весь body
		     result = pr.match(/>(.*?)</g);  //отсекаем все теги и получаем только текст
		     result_arr = [];   //в этом массиве будем хранить результат работы (подсветку)

                     for(var i=0; i<result.length;i++) {
		        result_arr[i] = result[i].replace(eval(search), '<span style="background-color:yellow;">'+input+'</span>'); //находим нужные элементы, задаем стиль и сохраняем в новый массив
			}
		     for(var i=0; i<result.length;i++) {
			pr=pr.replace(result[i],result_arr[i])  //заменяем в переменной с html текст на новый из новогом ассива
			}
		     document.body.innerHTML = pr;  //заменяем html код
              }
        }
        function FindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
        if(status) { FindOnPageBack(); FindOnPageGo(); } //чистим прошлое и Выделяем найденное
	if(!status) { FindOnPageBack(); } //Снимаем выделение
}

По сути все готово, и скрипт уже работает. Но добавим еще пару деталей для красоты.

1) Обрежем пробелы у текста, который вводит пользователь. Вставляем этот код:

        input = numer.replace(/^s+/g,'');
        input = numer.replace(/[ ]{1,}/g,' ');

После этой строки:

        input = document.getElementById(name).value; //получаем значение из поля в html

2) Сделаем проверку на совпадения (если совпадений не найдено — сообщим об этом). Этот код вставляем внутрь функции function FindOnPageGo() после переменных.

        var warning = true;
	for(var i=0;i<result.length;i++) {
	if(result[i].match(eval(search))!=null) {
			warning = false;
		}
	}
	if(warning == true) {
		alert('Не найдено ни одного совпадения');
	}

Посмотреть исходник можно тут.
Скачать исходник можно тут.

Теперь все. Конечно, можно добавить скролл к первому найденному результату, живой поиск ajax, да и вообще улучшать можно бесконечно. Сейчас это довольно примитивный поиск по сайту. Целью статьи было помочь новичкам, если возникет такой же вопрос как у меня. Ведь простого готового решения я не нашел.

P.S.: для корректной работы необходимо убрать переносы текста в html документе в тех местах, где есть обычный текст между тегами.

Например, вместо

  <p> бла бла бла
  </p>

Надо

   <p> бла бла бла </p>

Это не принципиально, можно от этих переносов избаляться автоматически на сервисе, но может подскажете заодно, как это пофиксить, если поймете раньше меня.

Также, если кто писал подобное, но с живым поиском, поделитесь исходником, будет интересно разобрать.

Буду рад выслушать конструкнтиную критику, мнения, может, рекомендации.

На днях дописал немного код, сделал живой поиск по странице. Так, что вопрос снят. Код HTML не менялся. JS можете посмотреть тут.

Поиск ведется по тегам с классом «place_for_live_search». Так что для того, чтоб алгоритм парсил нужный контент, добавляем класс и готово.

Недавно мы говорили о библиотеках и фреймворках — и обещали, что попробуем что-нибудь на них собрать. Настало время.

Сегодня мы возьмём популярную библиотеку jQuery и сделаем на её основе поиск по странице. Браузеры это умеют делать встроенными инструментами, но с помощью нашего метода можно будет более тонко всё настроить и сделать поле поиска видимым и удобным.

Нам понадобятся:

  • библиотека jQuery — она обеспечит работу нашего поискового плагина, потому что плагин сделан тоже для jQuery.
  • плагин highlight — поможет нам найти нужные слова в тексте и подсветить их приятным цветом (каким захотим)
  • поле ввода и кнопка — отвечают за сам интерфейс поиска.

Общая идея

У нас есть сайт с неким текстом, и нам нужно быстро находить в нём нужные слова или части слов. Для этого мы в самом начале страницы делаем поле ввода, куда будем писать наши слова для поиска, и кнопку, которая этот поиск запускает.

Дальше скрипт берёт весь текст, находит в нём нужные фрагменты и подсвечивает их. Если он ничего не находит — пишет сообщение о том, что таких слов в тексте нет.

Готовим каркас

Сделаем как обычно — возьмём наш стандартный шаблон из предыдущих задач и немного поправим описания разделов. Сохраним его как .html-файл и открывать в браузере пока не будем — всё равно мы ничего не увидим на странице, кроме названия вкладки.

<html>
<!-- служебная часть -->

<head>
  <!-- заголовок страницы -->
  <title>Поиск на странице</title>
  <!-- настраиваем служебную информацию для браузеров -->
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- задаём CSS-стили прямо здесь же, чтобы всё было в одном файле -->
  <style type="text/css">
  </style>
  <!-- закрываем служебную часть страницы -->
</head>
<!-- началось содержимое страницы -->

<body>
  <!-- пишем скрипт, который поможет нам с поиском -->
  <script>
  </script>
  <!-- Здесь будет текст, в котором нам нужно что-то найти -->
  <!-- закончилось содержимое страницы -->
</body>
<!-- конец всего HTML-документа -->

</html>

Добавляем форму поиска и текст

Наша форма поиска — это поле ввода и кнопка, которая запускает скрипт. Мы не будем сильно настраивать внешний вид формы, при желании вы можете сделать это сами — все нужные знания для этого у вас уже есть. Если что-то забыли — посмотрите, как мы настраивали вид поля ввода в статье про планировщик задач.

Добавим код формы сразу после тега <body>:

<!-- говорим браузеру, что мы хотим разместить форму -->
<form id="search-highlight" method="post" action="#">
  <!-- добавляем текстовое поле ввода, где будем писать наш поисковый запрос -->
  <input type="text" name="term" id="term" />
  <!-- добавляем кнопку, которая запускает поиск -->
  <input type="submit" name="submit" id="submit" value="Найти" />
  <!-- конец формы -->
</form>
<!-- сразу после формы будем писать, сколько совпадений мы нашли -->
<p class="results"></p>
<!-- а в этом блоке разместим наш основной текст -->
<div class="content">
  Сюда вставим наш текст
</div>

Осталось добавить сам текст в блок <div class="content">. Для простоты мы скопируем первые абзацы этой статьи и обернём их в HTML-теги. Вы можете вставить какой угодно текст, на работу скрипта это никак не повлияет.

<h2>Общая идея</h2>

<p>

У нас есть сайт с неким текстом, и нам нужно быстро находить в нём нужные слова или части слов. Для этого мы в самом начале страницы делаем поле ввода, куда будем писать наши слова для поиска, и кнопку, которая этот поиск запускает.

</p>

<p>

Дальше скрипт берёт весь текст, находит в нём нужные фрагменты и подсвечивает их. Если он ничего не находит — пишет сообщение, что таких слов в тексте нет.

</p>

Сохраняем, открываем в браузере:

Настраиваем стили

Стили отвечают за внешний вид всех элементов на странице. Главное, что нам нужно сделать, — нормальный внешний вид формы поиска и выбрать подсветку для найденных результатов. Это мы настроим в блоке <style> в начале страницы:

/*поле ввода*/
.searchtext {
  font-size: 16px;
  font-weight: bold;
  height: 27px;
  padding: 0 6px 0;
  width: 250px;
  /*делаем стильную границу вокруг поля*/
  border: 1px solid rgba(0, 0, 0, 0.1);
}
/* выбираем цвет подсветки — светло-зелёный*/
.highlight {
  background: #4cff00;
}
/*кнопка поиска*/
.search-button {
  background-color: #0b2f3f;
  font-weight: bold;
  font-size: 12px;
  /*устанавливаем высоту кнопки*/
  height: 28px;
  margin: 0;
  color: #ffffff;
  padding: 6px;
  /*тоже делаем стильную границу у кнопки*/
  border: 1px solid rgba(0, 0, 0, 0.1);
}

Сохраняем и обновляем страницу — теперь форма выглядит лучше:

Пишем скрипт

Задача скрипта — пробежаться по всему содержимому текста и сравнить все слова с тем, что мы ввели в строке поиска. Всю работу за нас сделает плагин highlight, нам остаётся только вывести количество найденных совпадений и очистить страницу от предыдущих результатов поиска.

<!-- подключаем библиотеку jQuery -->
<script src="http://thecode.local/wp-content/uploads/2019/06/jquery.js" type="text/javascript"></script>
<!--подключаем к ней плагин highlight.js -->
<script src='http://thecode.local/wp-content/uploads/2019/06/jqueryhighlight.js' />
</script>
<!-- говорим браузеру, что сейчас начнётся скрипт -->
<script type="text/javascript">
  $(document).ready(function () {
    // обрабатываем нажатие на кнопку
    $("#submit").click(function () {
      // очищаем переменную, в которой будет наш поисковый запрос
      var term = "";
      // и переменную, которая отвечает за количество найденных совпадений
      var n = "0";
      // убираем всю подсветку из прошлого поиска, если она была
      $('body').removeHighlight();
      // скрываем блок с текстом о количестве найденных результатов
      $("p.results").hide().empty();
      // с помощью магии jQuery берём текст из строки поиска и кладём его в переменную term
      term = $('#term').attr('value');
      // если строка поиска пустая — выводим сообщение
      if ($('#term').val() == "") {
        $("p.results").fadeIn().append("Вы ничего не ввели :(");
        return false;
        // иначе, если в строке поиска что-то было…
      } else {
        // в блоке content, где у нас находится весь текст, плагином подсвечиваем все найденные совпадения (если совпадений не будет — не будет и подсветки)
        $('.content').highlight(term);
        // берём количество совпадений
        n = $("span.highlight").length;
        // если совпадений нет — в разделе results пишем, что ничего не нашли
        if (n == 0) {
          $("p.results").fadeIn().append("Ничего такого в тексте нет");
          // иначе в том же разделе пишем число совпадений  
        } else {
          $("p.results").fadeIn().append('Найдено совпадений:' + n);
        }
        return false;
      }
    });
  });

Вставляем скрипт в HTML-файл, сохраняем и смотрим, что получилось в итоге:

А вот как всё будет работать: 

Проект: собственный поиск по странице на jQuery

Общий код страницы

<html>
<!-- служебная часть -->

<head>
  <!-- заголовок страницы -->
  <title>Поиск на странице</title>
  <!-- настраиваем служебную информацию для браузеров -->
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- задаём CSS-стили прямо здесь же, чтобы всё было в одном файле -->
  <style type="text/css">
    /*поле ввода*/
    .searchtext {
      font-size: 16px;
      font-weight: bold;
      height: 27px;
      padding: 0 6px 0;
      width: 250px;
      /*делаем стильную границу вокруг поля*/
      border: 1px solid rgba(0, 0, 0, 0.1);
    }

    /* выбираем цвет подсветки — светло-зелёный*/
    .highlight {
      background: #4CFF00;
    }

    /*кнопка поиска*/
    .search-button {
      background-color: #0B2F3F;
      font-weight: bold;
      font-size: 12px;
      /*устанавливаем высоту кнопки*/
      height: 28px;
      margin: 0;
      color: #ffffff;
      padding: 6px;
      /*тоже делаем стильную границу у кнопки*/
      border: 1px solid rgba(0, 0, 0, 0.1);
    }
  </style>
  <!-- закрываем служебную часть страницы -->
</head>
<!-- началось содержимое страницы -->

<body>
  <!-- говорим браузеру, что мы хотим разместить форму -->
  <form id="search-highlight" method="post" action="#">
    <!-- добавляем текстовое поле ввода, где будем писать наш поисковый запрос -->
    <input type="text" name="term" id="term" class="searchtext" />
    <!-- добавляем кнопку, которая запускает поиск -->
    <input type="submit" name="submit" id="submit" value="Найти" class="search-button" />
    <!-- конец формы -->
  </form>
  <!-- подключаем библиотеку jQuery -->
  <script src="http://thecode.local/wp-content/uploads/2019/06/jquery.js" type="text/javascript"></script>
  <!-- подключаем к ней плагин highlight.js -->
  <script src='http://thecode.local/wp-content/uploads/2019/06/jqueryhighlight.js' />
  </script>
  <!-- говорим браузеру, что сейчас начнётся скрипт -->
  <script type="text/javascript">
    $(document).ready(function () {
      // обрабатываем нажатие на кнопку
      $("#submit").click(function () {
        // очищаем переменную, в которой будет наш поисковый запрос
        var term = "";
        // и переменную, которая отвечает за количество найденных совпадений
        var n = "0";
        // убираем всю подсветку из прошлого поиска, если она была
        $('body').removeHighlight();
        // скрываем блок с текстом о количестве найденных результатов
        $("p.results").hide().empty();
        // с помощью магии jQuery берём текст из строки поиска и кладём его в переменную term
        term = $('#term').attr('value');
        // если строка поиска пустая — выводим сообщение
        if ($('#term').val() == "") {
          $("p.results").fadeIn().append("Вы ничего не ввели :(");
          return false;
          // иначе, если в строке поиска что-то было…
        } else {
          // в блоке content, где у нас находится весь текст, плагином подсвечиваем все найденные совпадения (если совпадений не будет — не будет и подсветки)
          $('.content').highlight(term);
          // берём количество совпадений
          n = $("span.highlight").length;
          // если совпадений нет — в разделе results пишем, что ничего не нашли
          if (n == 0) {
            $("p.results").fadeIn().append("Ничего такого в тексте нет");
            // иначе в том же разделе пишем число совпадений  
          } else {
            $("p.results").fadeIn().append('Найдено совпадений:' + n);
          }
          return false;
        }
      });
    });
  </script>
  <!-- сразу после формы будем писать, сколько совпадений мы нашли -->
  <p class="results"></p>
  <!-- а в этом блоке разместим наш основной текст -->
  <div class="content">
    <p>
      Чтобы лучше понять, как работают библиотеки и плагины в веб-программировании, давайте с их помощью сделаем удобный
      поиск по странице. Мы знаем, что современные браузеры тоже умеют это делать, но мы сделаем свою версию, которая
      работает не хуже, чем в Хроме или Сафари.
    <p>
    <h2>Общая идея</h2>
    <p>
      У нас есть сайт с неким текстом, и нам нужно быстро находить в нём нужные слова или части слов. Для этого мы в
      самом начале страницы делаем поле ввода, куда будем писать наши слова для поиска, и кнопку, которая этот поиск
      запускает.
    </p>
    <p>
      Дальше скрипт берёт весь текст, находит в нём нужные фрагменты и подсвечивает их. Если он ничего не находит —
      пишет сообщение о том, что таких слов в тексте нет.
    </p>
  </div>
  <!-- закончилось содержимое страницы -->
</body>
<!-- конец всего HTML-документа -->

</html>

Как можно улучшить

Можно убрать кнопку «Найти» и запускать поиск при вводе текста в поле.

Можно сделать два поля ввода, подсвечивая найденное по каждому разными цветами. Это полезно, например, если нужно проанализировать, каких слов в тексте больше.

Регулярные выражения! О них отдельно напишем, это же просто праздник какой-то.

how can i search an html page for a word fast?
and how can i get the html tag that the word is in? (so i can work with the entire tag)

asked Apr 14, 2009 at 16:08

Chen Kinnrot's user avatar

Chen KinnrotChen Kinnrot

20.5k17 gold badges79 silver badges139 bronze badges

To find the element that word exists in, you’d have to traverse the entire tree looking in just the text nodes, applying the same test as above. Once you find the word in a text node, return the parent of that node.

var word = "foo",
    queue = [document.body],
    curr
;
while (curr = queue.pop()) {
    if (!curr.textContent.match(word)) continue;
    for (var i = 0; i < curr.childNodes.length; ++i) {
        switch (curr.childNodes[i].nodeType) {
            case Node.TEXT_NODE : // 3
                if (curr.childNodes[i].textContent.match(word)) {
                    console.log("Found!");
                    console.log(curr);
                    // you might want to end your search here.
                }
                break;
            case Node.ELEMENT_NODE : // 1
                queue.push(curr.childNodes[i]);
                break;
        }
    }
}

this works in Firefox, no promises for IE.

What it does is start with the body element and check to see if the word exists inside that element. If it doesn’t, then that’s it, and the search stops there. If it is in the body element, then it loops through all the immediate children of the body. If it finds a text node, then see if the word is in that text node. If it finds an element, then push that into the queue. Keep on going until you’ve either found the word or there’s no more elements to search.

answered Apr 14, 2009 at 16:15

nickf's user avatar

3

You can iterate through DOM elements, looking for a substring within them. Neither fast nor elegant, but for small HTML might work well enough.

I’d try something recursive, like: (code not tested)

findText(node, text) {
  if(node.childNodes.length==0) {//leaf node
   if(node.textContent.indexOf(text)== -1) return [];
   return [node];
  }
  var matchingNodes = new Array();
  for(child in node.childNodes) {
    matchingNodes.concat(findText(child, text));
  }
  return matchingNodes;
}

answered Apr 14, 2009 at 16:14

vartec's user avatar

vartecvartec

130k36 gold badges217 silver badges244 bronze badges

0

You can try using XPath, it’s fast and accurate

http://www.w3schools.com/Xpath/xpath_examples.asp

Also if XPath is a bit more complicated, then you can try any javascript library like jQuery that hides the boilerplate code and makes it easier to express about what you want found.

Also, as from IE8 and the next Firefox 3.5 , there is also Selectors API implemented. All you need to do is use CSS to express what to search for.

answered Apr 14, 2009 at 16:16

Azder's user avatar

AzderAzder

4,6787 gold badges37 silver badges57 bronze badges

2

You can probably read the body of the document tree and perform simple string tests on it fast enough without having to go far beyond that — it depends a bit on the HTML you are working with, though — how much control do you have over the pages? If you are working within a site you control, you can probably focus your search on the parts of the page likely to be different page from page, if you are working with other people’s pages you’ve got a tougher job on your hands simply because you don’t necessarily know what content you need to test against.

Again, if you are going to search the same page multiple times and your data set is large it may be worth creating some kind of index in memory, whereas if you are only going to search for a few words or use smaller documents its probably not worth the time and complexity to build that.

Probably the best thing to do is to get some sample documents that you feel will be representative and just do a whole lot of prototyping based around the approaches people have offered here.

answered Apr 14, 2009 at 16:19

glenatron's user avatar

glenatronglenatron

10.9k13 gold badges63 silver badges109 bronze badges

form.addEventListener("submit", (e) => {
e.preventDefault();
var keyword = document.getElementById("search_input");
let words = keyword.value;
var word = words,
    queue = [document.body],
    curr;
while (curr = queue.pop()) {
    if (!curr.textContent.toUpperCase().match(word.toUpperCase())) continue;
    for (var i = 0; i < curr.childNodes.length; ++i) {
        switch (curr.childNodes[i].nodeType) {
            case Node.TEXT_NODE: // 3
                if (curr.childNodes[i].textContent.toUpperCase().match(word.toUpperCase())) {
                    console.log("Found!");
                    console.log(curr);
                    curr.scrollIntoView();
                }
                break;
            case Node.ELEMENT_NODE: // 1
                queue.push(curr.childNodes[i]);
                break;
        }
    }
}

});

answered Dec 18, 2020 at 17:39

Mohammed Adil's user avatar

В этой статье мы разберём как сделать на JavaScript поиск на странице или если точнее по списку, будет крайне полезная и интересная статья.

Также рекомендую прочитать «Прогноз погоды на JavaScript», тоже крайне интересная и полезная статья.

Как создать поиск на JavaScript:

Для начала, перед созданием нам нужно сделать не большой HTML блок со списком, это делается всё очень просто, вот:

<input type=«text» id=«inputSearch» placeholder=«Search..» title=«Type in a category»>

<ul id=«list»>

    <li><a href=«#»>HTML</a></li>

    <li><a href=«#»>CSS</a></li>

    <li><a href=«#»>JavaScript</a></li>

    <li><a href=«#»>PHP</a></li>

    <li><a href=«#»>Python</a></li>

    <li><a href=«#»>jQuery</a></li>

    <li><a href=«#»>SQL</a></li>

    <li><a href=«#»>Bootstrap</a></li>

    <li><a href=«#»>Node.js</a></li>

</ul>

Здесь всё просто, мы просто создали не большой список, в котором храним ссылке, но это для примера.

Теперь перейдём самому главному, это самому поиску, для этого нам понадобится создать одну функцию, которая как раз и будет выполнять поиск, вот она:

function search() {

    let input = document.getElementById(«inputSearch»);

    let filter = input.value.toUpperCase();

    let ul = document.getElementById(«list»);

    let li = ul.getElementsByTagName(«li»);

    // Перебирайте все элементы списка и скрывайте те, которые не соответствуют поисковому запросу

    for (let i = 0; i < li.length; i++) {

        let a = li[i].getElementsByTagName(«a»)[0];

        if (a.innerHTML.toUpperCase().indexOf(filter) > 1) {

            li[i].style.display = «»;

        } else {

            li[i].style.display = «none»;

        }

    }

}

В начале функции мы объявляем различного рода переменные, сначала берём наш input, потом создаём новую переменную присваиваем ей значение поля, но предварительно всю строку переводим в большой регистр, это нам пригодиться для сравнения.

Последнее берём ul и остальные элементы списка, который есть внутри него, проходимся по ним циклом, берём элемент a и сравниваем его, с переменной filter предварительно переводя высший регистр, всё это нужно, чтобы строки правильно сравнились, а при сравнение строк также учитывается и их регистр.

Если мы находим совпадение в строке ссылки, то тогда выставляем настройки display, пустую строку, иначе none, таким образом и работает поиск на JS.

Последние что нам осталось, это отследить, это событие нажатия клавиш, для этого вписываем такой код:

document.addEventListener(‘keyup’, search);

Таким образом мы будим следить на нажатие клавиш, и если в поле что-то изменилось, то применять это.

Вот что получилось:

Как можете заметить всё работает.

Вывод:

В этой статье вы прочитали, как сделать на JavaScript поиск на странице или по списку, и в целом тут не чего сложного нет, надо просто создать одну функцию.

Кусок кода был взят с сайта по этой ссылке.

Подписываетесь на соц-сети:

Оценка:

Загрузка…

Также рекомендую:

Только для читателей Lifeexample возможно открыть интернет-магазин на Moguta.CMS со скидкой в 15%

JavaScript поиск по странице

Здравствуйте уважаемые читатели блога LifeExample, все мы пользуемся электронным поиском по странице в наших веб браузерах при помощи горячих клавиш CTRL+F либо F3. И кажется уже от таких привилегий нам никуда не деться, так как самостоятельно читать все содержимое страницы, зачастую бывает некогда. Беда в том, что далеко не все начинающие пользователи знают о таких скрытых возможностях любого браузера, но им можно помочь, прикрутив самодельный JavaScript поиск по странице, в тех проектах, где без него совсем никак.

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

Искать на странице нужную информацию будет удобнее, если для этого реализовать соответствующий интерфейс:

Форма ввода поиска по странице

В поле нужно ввести слово для поиска и нажать кнопку «Искать», тут все интуитивно понятно. Давайте перейдем к реализации самого механизма поиска по странице и посмотрим, какие могут быть нюансы при его реализации.

Как искать слово на странице?

  1. Нужно проверить корректность ввода данных, в нашем случае мы только обрежем пробельные символы по бокам фразы для поиска, а также просто проверим на саму форму на наличие в ней поискового запроса.
  2. Так как данные статичны, и хранятся только в DOM’e страницы, то поиск по ней будет производиться именно по содержимому DOM (Document Object Model).
  3. Важным является, показать пользователю все результаты, которые нашел наш JavaScript поиск. Т.е. подсветить фон под найденными частями содержимого страницы.
  4. Так как этот мини модуль поиска по странице имеет смысл подключать только к большим страницам, которые имеют прокрутку, то при наличии найденной фразы, где-то вне зоны видимости неплохо будет прокрутить scroll до найденного элемента.
  5. Повторное использование поиска, также является важным моментом в работе данного скрипта. Т.к. подсветка найденных частей является результатом изменения содержимого DOM объекта, то каждый последующий цикл поиска должен затирать результаты предыдущего и возвращать содержимое страницы к исходному виду, для дальнейших изменений новой итерации.

Ну, так вкратце вроде бы и все. Несмотря на объемность выделенных пунктов, реализация их не занимает много времени и места в коде, вот готовый скрипт для механизма JavaScript поиска по странице :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

<script type=«text/javascript»>
var lastResFind=»»; // последний удачный результат
var copy_page=»»; // копия страницы в ихсодном виде
function TrimStr(s) {
     s = s.replace( /^s+/g, »);
  return s.replace( /s+$/g, »);
}
function FindOnPage(inputId) {//ищет текст на странице, в параметр передается ID поля для ввода
  var obj = window.document.getElementById(inputId);
  var textToFind;

 
  if (obj) {
    textToFind = TrimStr(obj.value);//обрезаем пробелы
  } else {
    alert(«Введенная фраза не найдена»);
    return;
  }
  if (textToFind == «») {
    alert(«Вы ничего не ввели»);
    return;
  }

 
  if(document.body.innerHTML.indexOf(textToFind)==»-1″)
  alert(«Ничего не найдено, проверьте правильность ввода!»);

 
  if(copy_page.length>0)
        document.body.innerHTML=copy_page;
  else copy_page=document.body.innerHTML;

 
  document.body.innerHTML = document.body.innerHTML.replace(eval(«/name=»+lastResFind+»/gi»),» «);//стираем предыдущие якори для скрола
  document.body.innerHTML = document.body.innerHTML.replace(eval(«/»+textToFind+»/gi»),»<a name=«+textToFind+» style=‘background:red’>«+textToFind+»</a>«); //Заменяем найденный текст ссылками с якорем;
  lastResFind=textToFind; // сохраняем фразу для поиска, чтобы в дальнейшем по ней стереть все ссылки
  window.location = ‘#’+textToFind;//перемещаем скрол к последнему найденному совпадению
 }
</script>
<body>
<h2>JavaScript поиск по странице</h2>
<input type=«text» id=«text-to-find» value=«»>
<input type=«button» onclick=«javascript: FindOnPage(‘text-to-find’); return false;» value=«Искать»/>
<br/><i>Введите слово или фразу для поиска.</i>
<hr/>

<table border=‘2’ cellpadding=’20’>
 <tr><th>Товар</th><th>Вес</th><th>Стоимость</th></tr>
 <tr><td>Монитор 19 дюймов</td><td>1 кг</td><td>1900 руб.</td></tr>
 <tr><td>монитор 18 дюймов</td><td>2 кг</td><td>1800 руб.</td></tr>
 <tr><td>Монитор 20 дюймов</td><td>2 кг</td><td>1900 руб.</td></tr>
</table>
</body>

Попробуйте, протестировать поисковыми запросами «19», «2 кг» и другими. Также советую проверить авто скролинг, для этого добавляйте текст до тех пор пока справа не появится полоса прокрутки.

Вот так выглядит пример использования скрипта:

Пример JavaScript поиска по странице

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

Реализованный в данной статье, с помощью языка JavaScript , поиск по странице валиден во всех браузерах, включая Internet Explorer.

Читайте также похожие статьи:

Чтобы не пропустить публикацию следующей статьи подписывайтесь на рассылку по E-mail или RSS ленту блога.

Яндекс.Метрика

Понравилась статья? Поделить с друзьями:
  • Как можно найти запрос по картинке
  • Как найти стороны многоугольника зная все углы
  • Положение об оплате труда как составить образец положения
  • Как найти своих друзей в стиме
  • Как составить портфолио достижений