Подсказки при наборе адреса на сайт
Наверняка вы видели на некоторых сайтах – подсказки. Очень много где требуется регистрироваться или прост вводить данные (например, адрес), то как только вы начинаете нажимать на клавиши, то снизу появляются варианты выбора. Например, вводим «Вол» и внизу появляется – «Вологда», «Волгоград». Вы кликаете на город и он сразу же ставится в поле ввода. Давайте разберемся как это сделать просто и бесплатно.
Схема работы очевидна – ловим событие в текстовом поле (нажатие или изменение), отправляем по ajax, осуществляем поиск и внизу выводим. Самое сложное тут это – поиск. Точнее, что и где искать.
Первое, что приходит в голову – это создание своей базы данных. То есть, если мы говорим об адресе, то список регионов, городов и сел. Взять готовые или спарсить откуда-то – в принципе это возможно. Но как быть с улицами? Номерами домов? И самый главный момент – актуальность информации.
Приходим к выводу, что лучше использовать внешние сервисы. Я обычно использую для этого дадату. Регистрируетесь и получаете 500 бесплатных запросов адреса в день. Для небольшого начинающего проекта этого хватит за глаза. А если разрастётесь – тогда можно и прикупить, не проблема.
Теперь соберем все из кубиков
Фронт (верстка)
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Поиск адреса</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
}
.search-container {
position: relative;
max-width: 500px;
margin: 0 auto;
}
#address-input {
width: 100%;
padding: 12px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 6px;
box-sizing: border-box;
}
.suggestions {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 1px solid #ddd;
border-top: none;
border-radius: 0 0 6px 6px;
max-height: 200px;
overflow-y: auto;
z-index: 1000;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.suggestion-item {
padding: 10px 12px;
cursor: pointer;
border-bottom: 1px solid #eee;
}
.suggestion-item:hover {
background-color: #f5f5f5;
}
.error {
color: red;
font-size: 14px;
margin-top: 5px;
}
</style>
</head>
<body>
<div class="search-container">
<input type="text" id="address-input" placeholder="Введите адрес..." />
<div id="suggestions-list" class="suggestions"></div>
<div id="error-message" class="error"></div>
</div>
</body>
</html>
JavaScript
<script>
const input = document.getElementById('address-input');
const suggestionsList = document.getElementById('suggestions-list');
const errorMessage = document.getElementById('error-message');
let timeoutId = null;
input.addEventListener('input', function () {
const query = input.value.trim();
clearTimeout(timeoutId);
// Очистка ошибок и подсказок
errorMessage.textContent = '';
suggestionsList.innerHTML = '';
if (query.length < 3) return;
timeoutId = setTimeout(() => {
fetch('api.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query })
})
.then(response => {
if (!response.ok) {
throw new Error(`Ошибка сети: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.error) {
errorMessage.textContent = data.error;
return;
}
if (!data.suggestions || data.suggestions.length === 0) {
suggestionsList.innerHTML = '<div class="suggestion-item">Ничего не найдено</div>';
return;
}
suggestionsList.innerHTML = data.suggestions
.map(item => {
return `<div class="suggestion-item" data-value="${item.unrestricted_value}">
${item.value}
</div>`;
})
.join('');
// Добавляем обработчики клика
document.querySelectorAll('.suggestion-item').forEach(item => {
item.addEventListener('click', function () {
input.value = this.dataset.value;
suggestionsList.innerHTML = '';
});
});
})
.catch(err => {
errorMessage.textContent = 'Ошибка: ' + err.message;
});
}, 300); // Дебаунс
});
// Скрываем подсказки при клике вне поля
document.addEventListener('click', function (e) {
if (!input.contains(e.target) && !suggestionsList.contains(e.target)) {
suggestionsList.innerHTML = '';
}
});
</script>
Сервер (PHP)
<?php
// api.php
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *'); // Для разработки. На продакшене укажите ваш домен
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
$token = "ваш_токен_от_dadata"; // ← Замените на реальный токен
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Метод не поддерживается'], JSON_UNESCAPED_UNICODE);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['query']) || empty(trim($input['query']))) {
echo json_encode(['suggestions' => []]);
exit;
}
$query = trim($input['query']);
// Параметры запроса к DaData
$url = "https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/address";
$headers = [
'Content-Type: application/json',
'Accept: application/json',
"Authorization: Token {$token}",
];
$postData = [
'query' => $query,
'count' => 5, // Ограничим количество подсказок
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 10,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($postData, JSON_UNESCAPED_UNICODE),
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_FOLLOWLOCATION => false,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
http_response_code(500);
echo json_encode(['error' => 'Ошибка подключения к DaData', 'details' => $error], JSON_UNESCAPED_UNICODE);
exit;
}
if ($httpCode !== 200) {
http_response_code($httpCode);
echo json_encode(['error' => 'Ошибка от DaData', 'status' => $httpCode], JSON_UNESCAPED_UNICODE);
exit;
}
$result = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
// Возвращаем только нужные поля
$suggestions = array_map(function ($item) {
return [
'value' => $item['value'],
'unrestricted_value' => $item['unrestricted_value']
];
}, $result['suggestions'] ?? []);
echo json_encode(['suggestions' => $suggestions], JSON_UNESCAPED_UNICODE);
На сайте дадаты есть и другие апи – поиск по ИНН, названию компании – все в разумных пределах бесплатно.
Вот так просто можно реализовать подсказки при наборе адреса (живой поиск).
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.
Программы на заказ
Отзывы
Контакты