Компонент DaData-подсказок для Vue 3.
Попробуйте демо, чтобы ознакомиться с возможностями компонента:
Демо
Установка
npm i @dadata-sdk/vueИли
pnpm i @dadata-sdk/vueИли напрямую из последнего коммита на GitHub:
pnpm add @dadata-sdk/vue@github:alexchexes/dadata-sdk#rewritten&path:/packages/vue-dadataИспользование
<script setup>
import { ref } from 'vue';
import { VueDadata } from 'vue-dadata';
// use shipped CSS if needed:
import 'vue-dadata/dist/vue-dadata.css';
const token = import.meta.env.VITE_APP_DADATA_API_KEY; // API key
const query = ref(''); // input field value
const suggestion = ref(undefined); // selected suggestion
</script>
<template>
<VueDadata v-model="query" v-model:suggestion="suggestion" :token="token" />
</template>V-Models
v-model
- Обязательный
- Тип:
string
v‑model для текста запроса. Значение используется при вызовах API и синхронизировано с полем ввода (<input>) всё время, кроме как при навигации по подсказкам с клавиатуры (клавишами ↑↓) — в этот момент поле ввода отображает текст из «подсвеченной» в данный момент подсказки, а значение v-model сохраняет текст, который был в поле до начала навигации. После выбора подсказки или выхода (Esc, Клик вне элемента), поле снова синхронизировано со значением в данном v-model.
v-model:suggestion
- Тип:
object | undefined
v‑model для объекта выбранной в данный момент подсказки. Обеспечивает простой доступ к объекту, но работает в обе стороны — можно задать «начальную» подсказку при загрузке страницы без необходимости вызывать API. При установке непустого объекта извне, будет также обновлён v-model текста запроса.
Пропсы
Основные настройки
token
string
Ваш API-ключ (token) DaData.
suggestType
string
Тип подсказок, то есть используемый эндпоинт suggest API DaData:
address- обычные адреса https://dadata.ru/api/suggest/address/fias- адреса строго по ФИАС (не рекомендовано) https://dadata.ru/api/suggest/fias/party- организации https://dadata.ru/api/suggest/party/bank- банки https://dadata.ru/api/suggest/bank/fio- имена, фамилии, отчества https://dadata.ru/api/suggest/name/email- email-адреса https://dadata.ru/api/suggest/email/
По умолчанию address
httpCache
boolean
Если false, HTTP-запросы не будут кэшироваться.
По умолчанию true
url
string
Пользовательский URL API.
Полезно, если вы проксируете запросы к DaData.
Важно: эндпоинт (то есть suggestType) в настоящий момент не добавляется автоматически.
Нужно передать полный URL вашего эндпоинта, например https://my-api-proxy.example.com/suggest/address.
Если не передано, итоговый URL собирается из базового suggest API DaData (.../api/4_1/rs/suggest/) + suggestType.
payload
OptionalSuggestPayload (object)
Пользовательский payload для API-запроса.
Поля, указанные здесь, будут добавлены в итоговый payload, переопределяя существующие значения.
headers
PlainHeaders (object)
Пользовательские HTTP-заголовки для API-запроса.
Заголовки, указанные здесь, будут добавлены в итоговые headers переопределяя существующие значения.
Запросы к Адресам
count
number
Максимальное количество подсказок, запрашиваемых у API DaData.
Макс: 20, по умолчанию: 10
locationsBoost
KladrIdFilter (object) | string | number | array
kladr_id или массив kladr_id региона/города, который нужно приоритизировать в подсказках.
Соответствует параметру API locations_boost.
Примеры:
-
55— Омская область -
63000001— город Самара -
6300000100000— город Самара (полный код КЛАДР) -
[50, 77]— Московская область и Москва -
{kladr_id: '02'}или[{kladr_id: '02'}, ...]— нативный формат API DaData -
'address': https://confluence.hflabs.ru/pages/viewpage.action?pageId=285343795
-
'fias': https://confluence.hflabs.ru/pages/viewpage.action?pageId=968425529
Макс: 10 элементов
locationsFilter
LocationRestriction (object) | string | number | array
Ограничивает поиск конкретными локациями (параметр API locations).
Макс: 10 элементов
Например, при suggestType=address, чтобы искать только по городу Воронежу и Ростовской области:
:locationsFilter="[{'region':'Воронежская','city':'Воронеж'},{'region':'Ростовская'}]"
- Для
address: https://confluence.hflabs.ru/pages/viewpage.action?pageId=204669108 - Для
fias: https://confluence.hflabs.ru/pages/viewpage.action?pageId=967835974
Для party и bank поддерживается только фильтр kladr_id.
fromBound
string
Ограничивает тип адресного объекта, с которого DaData начинает поиск:
country|region|area|city|settlement|planning_structure|street|house
Соответствует параметру API from_bound.
toBound
string
Ограничивает тип адресного объекта, до которого DaData выполняет поиск:
country|region|area|city|settlement|planning_structure|street|house|flat
Соответствует параметру API to_bound.
https://confluence.hflabs.ru/pages/viewpage.action?pageId=222888017
restrictValue
boolean
Используется вместе с locationsFilter. Если true, отображаемая подсказка
(то есть поле value) будет без частей адреса до уровня ограничения.
Например, если в фильтре указать region, этот регион не попадет в результат;
если указать city, из результата будут исключены и регион, и город.
Соответствует параметру API restrict_value.
- https://confluence.hflabs.ru/pages/viewpage.action?pageId=222888017
- https://confluence.hflabs.ru/pages/viewpage.action?pageId=968425521
- https://confluence.hflabs.ru/pages/viewpage.action?pageId=1023737934#id-Ограничениепоназваниюадресногообъекта-Адресбезрегионаигорода
- https://confluence.hflabs.ru/display/SGTDOC/address.value#address.value-Параметрrestrict_value
radiusFilter
RadiusFilter (object)
Ограничивает поиск заданным радиусом вокруг точки с широтой и долготой.
Пример: {lat: '59.244634', lon: '39.913355', radius_meters: 200}
Соответствует параметру API locations_geo.
See https://confluence.hflabs.ru/pages/viewpage.action?pageId=990871806
division
string
Тип территориального деления:
ADMINISTRATIVE(административное):Московская обл, г Одинцово, село НикольскоеMUNICIPAL(муниципальное):Московская обл, г.о. Одинцовский, село Никольское
Также влияет на набор полей внутри suggestion.data.
По умолчанию: 'ADMINISTRATIVE'
See https://confluence.hflabs.ru/pages/viewpage.action?pageId=1326056589
language
string
Язык в возвращаемых подсказках по адресам. RU или EN.
EN - почти всегда простая транслитерация латиницей,
однако для некоторых городов, например, "Moscow" - поля будут содержать реальный перевод,
причём переведён будет также тип города - "city" (тогда как для других это обычно "gorod").
По умолчанию: RU.
https://confluence.hflabs.ru/pages/viewpage.action?pageId=976388726
Запросы к другим API
entityType
string | (string | array) | (string | array) | (string | array)
Тип организации или банка (для подсказок party, party_by, party_kz и bank).
-
для
party:LEGALилиINDIVIDUAL, https://confluence.hflabs.ru/pages/viewpage.action?pageId=206176337 -
для
bank: https://confluence.hflabs.ru/pages/viewpage.action?pageId=262996122 -
для
party_by: https://dadata.ru/api/suggest/party_by/ -
для
party_kz: https://dadata.ru/api/suggest/party_kz/
entityStatus
(string | array) | (string | array) | (string | array)
Статус организации или банка (для подсказок party, party_by и bank)
'ACTIVE' | 'LIQUIDATING' | 'LIQUIDATED' | etcparty: https://confluence.hflabs.ru/pages/viewpage.action?pageId=206176335party_by: https://dadata.ru/api/suggest/party_by/bank: https://confluence.hflabs.ru/pages/viewpage.action?pageId=262996120
branchType
string | array
Фильтр по типу филиала (для подсказок party)
MAIN- искать только головные организацииBRANCH- искать только филиалы
See https://confluence.hflabs.ru/pages/viewpage.action?pageId=568918095
okved
string | array
Фильтр по коду ОКВЭД (для подсказок party). Макс: 10 элементов
fioParts
string | array
Фильтр по частям ФИО (для подсказок fio, см. https://dadata.ru/api/suggest/name/).
Примеры:
- Только имена:
['NAME']илиNAME - Имена и отчества:
['NAME', 'PATRONYMIC'] - Имена и фамилии:
['NAME', 'SURNAME']
fioGender
string
Фильтр по полу (для подсказок fio).
UNKNOWN/MALE/FEMALE
filters
SuggestFmsUnitFilter (object) | SuggestFnsUnitFilter (object) | SuggestMetroFilter (object) | SuggestMktuFilter (object) | SuggestOkpd2Filter (object) | SuggestOkved2Filter (object) | SuggestPartyByFilter (object) | SuggestPartyKzFilter (object) | SuggestPostalUnitFilter (object) | SuggestCourtFilter (object) | array
Фильтры для API, у которых нет отдельных props-опций,
например fms_unit, fns_unit, metro, mktu, okpd2, okved2, postal_unit, court.
Чтобы задать filters для party_by и party_kz, используйте entityStatus
и entityType, как и для обычного party.
Поведение компонента
debounce
number
Задержка (в мс) после изменения ввода (query) перед отправкой запроса.
Работает по принципу debounce: если ввод продолжает изменяться,
запрос не будет отправлен до тех пор, пока с последнего изменения
не прошло это количество миллисекунд.
По умолчанию 100
minChars
number
Минимальная длина ввода (query), начиная с которой подсказки начинают работать.
По умолчанию 1
disabled
boolean
Задаёт атрибут disabled у поля ввода, отключает подсказки и все взаимодействия.
По умолчанию false
placeholder
string
Текст для атрибута placeholder у поля ввода.
inputName
string
Значение атрибута name у поля ввода.
По умолчанию dadata-input
inputAttributes
suggestionsHint
string
Текст, который отображается над списком подсказок.
noSuggestionsHint
string | boolean
Текст, отображаемый на месте подсказок, когда ничего не найдено.
Если используете слот #hint, передайте true для отображения своего элемента
при отсутствии подсказок, чтобы контейнер оставался видимым.
classes
VueDadataClasses (object)
Пользовательские имена CSS-классов для элементов компонента.
Значения по умолчанию: DEFAULT_CLASSES
showOnFocus
string | boolean
Управляет тем, в каких случаях при фокусе на поле ввода должен быть показан список подсказок.
false: никогда не показывать список по фокусу'always': всегда показывать список по фокусу, если поле ввода не пустое и список подсказок не пуст'no_selection': показывать список по фокусу, если сейчас нет выбранной подсказки
По умолчанию: 'no_selection'
selectOnBlur
boolean
Если true, при потере полем ввода фокуса будет автоматически "выбрана" первая подсказка.
По умолчанию: false
selectOnEnter
boolean
Если true, нажатие Enter выбирает первую подсказку, если список открыт.
По умолчанию: true
enrichOnSelect
boolean
Нужно ли отправлять дополнительный запрос после выбора подсказки, чтобы дополнить ее
данными вроде geo_lat, geo_lon, city_district (а также получить полный value,
если используется restrictValue).
Поставьте false, если хотите сэкономить запросы к API и эти данные вам не нужны.
По умолчанию: true
clearOnChange
string | boolean
Определяет, удалять ли объект выбранной подсказки из v-model:suggestion
при изменении текста ввода (query).
false: выбранная подсказка никогда не очищается при изменении query'any': подсказка очищается при любом изменении query'significant': подсказка очищается только если новое значение query после нормализации
(trim, case-folding) отличается от предыдущего
По умолчанию: 'significant'
addSpace
boolean
Если true, после выбора подсказки в input будет добавлен пробел. Например,
пользователь сможет выбрать улицу и сразу продолжить вводить номер дома.
По умолчанию true
continueSelecting
boolean
Если true, список подсказок останется видимым после выбора подсказки.
По умолчанию: false
showClearButton
boolean
Если true, в непустом поле ввода будет показываться кнопка очистки (×).
По умолчанию: false
focusOnMounted
boolean
Если true, input сразу получит фокус после загрузки компонента (хук onMounted).
По умолчанию false
forceShow
boolean
Принудительно держит список подсказок видимым.
Полезно во время разработки, при настройке стилей, и т.д.
По умолчанию: false
forceHide
boolean
Принудительно держит список подсказок скрытым.
По умолчанию: false
События компонента
| Событие | Когда | Что передаётся |
|---|---|---|
@error | В случае любой ошибки | unknown |
@select | Подсказка выбрана (по клику, по нажатию "Enter", или автоматически если selectOnBlur=true) | (suggestion: object, selectType: string) |
@enriched | Дополнительные данные об адресе получены (если enrichOnSelect=true) | (suggestion: object, diff: object | null) |
@enrichFail | Не удалось получить дополнительные данные об адресе (если enrichOnSelect=true) | string (suggestion.unrestricted_value) |
@focus | Поле ввода получило фокус | FocusEvent |
@blur | Поле ввода потеряло фокус | FocusEvent |
Слоты
В пропсы каждого слота передаётся
mergedClasses- объект со всеми используемыми компонентом CSS-классами в том же формате, что и объект для пропсаclassesна компоненте (VueDadataClasses).
inputWrapper
Слот для замены основного видимого контейнера с полем ввода, включающего <input> и кнопку-«крестик».
В пропсы слота передаются:
coreInputProps- рекомендуется забиндить на свойinputполностью черезv-bind. Включает базовые необходимые компоненту обработчики событий@input,@keydown,@focus,@blur, а также атрибутdisabled, иvalue, который не всегда соответствует тексту вquery, поскольку может содержать текущий видимый текст при навигации по подсказкам клавиатурой.browserAutoProps- атрибуты для отключения функций браузера, мешающих взаимодействию: встроенных подсказок, автозаполнения, автокоррекции и проверки правописания.allInputProps- включает всё, что включено вcoreInputPropsиbrowserAutoProps, а также дополнительно, атрибутыtype,class,name, иplaceholder.mergedClasses- используемые компонентом CSS-классы.
Пример использования:
<template #inputWrapper="{ allInputProps, coreInputProps, browserAutoProps }">
<!-- Your custom input/wrapper/anything -->
<MyFancyInput
v-bind="{ ...coreInputProps, ...browserAutoProps }"
:placeholder="allInputProps.placeholder"
/>
</template>При желании, <input> можно заменить на <textarea>, забиндив на неё все пропсы аналогичным образом.
input
Заменяет только <input>, не трогая вышестоящий контейнер и оверлей с кнопкой-«крестиком». Пропсы слота те же, что для inputwrapper. Пример:
<template #input="{ allInputProps, coreInputProps, browserAutoProps }">
<textarea v-bind="allInputProps" />
</template>inputOverlay
Пустой слот, позволяющий добавить свои элементы внутри контейнера с inputом, например, индикатор загрузки, кнопки и подобное. Пропсов кроме mergedClasses нет. Пример:
<template #inputOverlay>
<!-- Custom loading spinner, icons, buttons, etc -->
</template>clearButtonIcon
Заменяет иконку встроенной кнопки-«крестика» (×), не трогая сам элемент <button>. Пропсов кроме mergedClasses нет. Пример:
<template #clearButtonIcon>
<svg><!-- Custom "clear" icon --></svg>
</template>hint
Слот позволяет добавить собственные элементы, отображаемые над списком подсказок при их наличии, либо вместо списка при их отсутствии. Например, здесь можно добавить ссылку или кнопку, когда подсказок не найдено, или свой дизайн сообщения "Выберите вариант или продолжите ввод...".
На контейнер добавлен @mousedown.prevent, чтобы исключить потерю фокуса и скрытие списка подсказок при кликах внутри контейнера.
Чтобы контейнер оставался видимым, когда подсказки не найдены, необходимо передать true в пропс компонента noSuggestionsHint.
Пропсы слота:
suggestionsList- текущий список подсказокsuggestionsHint- текст сообщения при наличии подсказок (дефолтное или из пропсаsuggestionsHintкомпонента)noSuggestionsHint- текст сообщения при отсутствии подсказок (из пропсаnoSuggestionsHintкомпонента)mergedClasses- используемые компонентом CSS-классы.
Пример:
<!-- <VueDadata :noSuggestionsHint="true" ...> -->
<template #hint="{ suggestionsList, suggestionsHint, noSuggestionsHint }">
<!-- Стандартное сообщение если подсказки найдены -->
<template v-if="suggestionsList.length"> {{ suggestionsHint }} </template>
<!-- Свой блок если подсказок нет -->
<template v-else>
Ничего нет...
<button @click="reset">Сбросить фильтры?</button>
</template>
</template>suggestions
Заменяет полностью список подсказок (не трогая сам контейнер выпадающего списка и hint).
Пропсы слота:
suggestionsList- Массив из объектов подсказокnavigatedIndex- Индекс "подсвеченной" подсказки (при навигации клавиатурой)handleSuggestionClick- Обработчик клика, который необходимо добавить на каждый элемент подсказки, чтобы функции компонента продолжали работать в полном объёме (используйте@mousedown.prevent="...")mergedClasses- используемые компонентом CSS-классы.
Пример:
<template #suggestions="{ suggestionsList, navigatedIndex, handleSuggestionClick }">
<div
v-for="(suggestion, index) in suggestionsList"
:key="index"
@mousedown.prevent="handleSuggestionClick(index)"
>
{{ suggestion.value }}
</div>
</template>suggestionItem
Заменяет каждый отдельный элемент списка подсказок (включая его контейнер).
Пропсы слота:
suggestion- объект подсказкиindex- индекс элемента в списке (с0)isNavigated- является ли данный элемент "подсвеченным" (при навигации клавиатурой)handleSuggestionClick- Обработчик клика, который необходимо добавить на ваш элемент подсказки, чтобы функции компонента продолжали работать в полном объёме (используйте@mousedown.prevent="...")mergedClasses- используемые компонентом CSS-классы.
Пример:
<template #suggestionItem="{ suggestion, index, isNavigated, handleSuggestionClick }">
<button @mousedown.prevent="handleSuggestionClick(index)">
{{ suggestion.value }}
</button>
</template>suggestionItemContent
Заменяет внутренний контент каждого элемента в списке подсказок, не трогая его родительский контейнер. Пропсы те же, что для suggestionItem, но без handleSuggestionClick.
<template #suggestionItemContent="{ suggestion, index, isNavigated }">
{{ suggestion.value }}
</template>suggestionItemTitle
Заменяет элемент с основным отображаемым текстом подсказки (suggestion.value). При использовании слота понадобится добавить собственную подсветку совпадений; чтобы получить размеченные части для подсветки можно использовать экспортируемую библиотекой функцию highlightChunks.
Пропсы слота те же, что для suggestionItem, но без handleSuggestionClick.
<template #suggestionItemTitle="{ suggestion, index, isNavigated }">
<!-- Show `unrestricted_value` instead of `value` (with custom `highlight`) -->
<span v-html="highlight(query, suggestion.unrestricted_value)" />
</template>suggestionItemSubtitle
Заменяет элемент для размещения дополнительного текста под основным текстом подсказки. Дефолтный контент слота отображается только в определённых случаях, например для подсказок по организациям или банкам, слот же позволяет выводить дополнительное инфо в любой момент.
Пропсы те же, что для suggestionItem, но без handleSuggestionClick.
<template #suggestionItemSubtitle="{ suggestion, index, isNavigated }">
<div :class="mergedClasses.suggestionSubtitle">
Фед. округ: {{ (suggestion.data as AddressAdminData).federal_district }}
</div>
</template>Методы и свойства компонента
Следующие методы и свойства доступны через template-ref компонента (<VueDadata ref='vueDadata' ... />):
| Name | Type | Description |
|---|---|---|
inputRef | ShallowRef<HTMLInputElement | null> | templateRef элемента <input> |
suggestionsList | Ref<DadataSuggestion[], DadataSuggestion[]> | Текущий список подсказок или пустой массив |
isDropdownVisible | ComputedRef<boolean> | true когда список подсказок показан |
isFocused | ComputedRef<boolean> | true когда <input> имеет фокус |
update() | (options) => DadataSuggestion[] | Отправить запрос и обновить список подсказок. В аргументе можно передать опции, которые перезапишут опции, переданные, установленные через пропсы. Возвращает полученный список подсказок, или выбрасывает исключение в случае ошибки. |
clear() | () => void | Очистить текст запроса (modelValue), v-model:suggestion и suggestionsList |
show() | () => void | Показать подсказки (если они в этот момент загружены) |
hide() | () => void | Скрыть подсказки |
focus() | () => void | Передать фокус <input> |
blur() | () => void | Убрать фокус с <input> |
Пример использования методов
<script setup>
// ...
const query = ref('');
const suggestion = ref(undefined);
const vueDadata = useTemplateRef('vueDadata');
onMounted(async () => {
// `focus()`: Autofocus the input with a small delay after page load
setTimeout(() => {
vueDadata.value?.focus();
}, 300);
// set "selected suggestion" v-model manually
suggestion.value = {
/*...existing suggestion object...*/
};
// wait one tick so that v-model:suggestion propagates and changes the `query`
await nextTick();
// now fetch suggestions list with `update()`
const suggestions = await vueDadata.value?.update();
// the updated suggestions list is also available in the return value
console.log('Updated. Suggestions: ', suggestions);
// and finally use `show()` to open the dropdown programmatically
vueDadata.value?.show();
});
</script>
<template>
<VueDadata ref="vueDadata" v-model="query" v-model:suggestion="suggestion" ... />
<!-- Access to the fetched suggestions list -->
<pre>{{ vueDadata?.suggestionsList }}</pre>
</template>