Живая демо-версия
Утилита для обновления индекса Algolia на стороне сервера, а также компонент поиска на стороне клиента для приложений Svelte. Добавляет только одну зависимость:
algoliasearch
algoliasearch/lite
(13 КБ). Настройка svelte-algolia
состоит из 3 шагов:
npm install --dev svelte-algolia
Создайте объект algoliaConfig
:
import 'dotenv/config' // optional
async function loadPokedex ( ) {
const json = await import ( 'pokedex.json' )
return json . default . map ( ( el ) => ( { ... el , id : el . someUniqAttribute } ) )
}
const algoliaConfig = {
appId : process . env . VITE_ALGOLIA_APP_ID ,
// don't prefix admin key with VITE_ else it would get exposed to client-side code
apiKey : process . env . ALGOLIA_ADMIN_KEY ,
indices : [
{ name : `Pokedex` , getData : loadPokedex } ,
{ name : `Hitchhiker's Guide` , getData : guideLoader } ,
] ,
settings : {
attributesToHighlight : [ `name` ] ,
} ,
}
Ожидается, что функция getData
вернет массив объектов, содержащих данные, которые вы хотите проиндексировать (каталог продуктов, сообщения в блоге, страницы документации, покемоны или что-то еще). Каждый объект в массиве данных должен иметь ключ с именем id
, _id
или objectID
чтобы Algolia могла распознать его и перезаписать существующие данные, где это необходимо.
Объект настроек применяется ко всем индексам. Вы также можете передать объект настроек каждому индексу индивидуально, который переопределяет общий.
Передайте свою конфигурацию в indexAlgolia
:
import { indexAlgolia } from 'svelte-algolia/server-side'
indexAlgolia ( algoliaConfig )
Вы можете вызвать эту функцию везде, где хотите обновить свои индексы, например, в svelte.config.js
или в src/hooks.ts
(как это делается на этом демонстрационном сайте). Обычно вы включаете это в каждую производственную сборку вашего приложения.
const defaultConfig = {
verbosity : 1 , // 0, 1 or 2 for no/some/lots of logging
partialUpdates : false , // if true, figures out diffs between existing
// items and new ones and only uploads changes, otherwise, completely
// overwrites each index on every call to indexAlgolia()
matchFields : [ ] , // (only used when partialUpdates is true) keys of fields to check
// for whether an item has changed; could e.g. be a timestamp, hash or an ID that's
// updated every time the item has changed; if not provided, items are checked for
// deep-equality to discover changes which can become slow for thousands of items
settings : { } , // an object of Algolia index settings that applies to all indices
// see https://algolia.com/doc/api-reference/settings-api-parameters for available options
// can be overridden for individual indices by passing a settings object as part of the indices array:
// indices = [{ name: `pokedex`, ..., settings: { foo: `bar` }}],
}
Чтобы использовать этот пакет как часть процесса сборки (например, в приложении SvelteKit), просто вызовите indexAlgolia
в конфигурации сборки:
// svelte.config.js
// only update Algolia indices on production builds (saves API quota)
if ( process . env [ 'NODE_ENV' ] === `production` ) {
const { indexAlgolia } = await import ( `svelte-algolia/server-side` )
const algoliaConfig = {
// see above
}
indexAlgolia ( algoliaConfig )
}
<Search />
требуется идентификатор и ключ поиска вашего приложения Algolia для доступа к его индексам поиска, а также для сопоставления имен индексов с соответствующим компонентом Svelte, который должен отображать результаты поиска, поступающие из этого индекса. Каждый компонент попадания получает в качестве реквизита объект hit
со всеми атрибутами, хранящимися в индексе Algolia.
< script >
import Search from ' svelte-algolia '
import PokemonHit from ' $site/PokemonHit.svelte '
const appId = ' 0OJ5UL9OJX '
const searchKey = ' 63f563566cdd6de606e2bb0fdc291994 '
// in a real app you'd get your credentials like this:
const appId = import .meta.env.VITE_ALGOLIA_APP_ID
const searchKey = import .meta.env.VITE_ALGOLIA_SEARCH_KEY
</ script >
< header >
< nav >{ ... }</ nav >
< Search
{ appId }
{ searchKey }
indices ={{ Pokedex : PokemonHit }}
placeholder = " Search Pokedex " />
</ header >
Например, компонент PokemonHit.svelte
на демо-сайте выглядит так:
< script >
export let hit
</ script >
< h2 >{ @html hit . name }</ h2 >
< div >
< ul >
< li >Type: { @html hit . type . join ( ` , ` )}</ li >
< li >Height: { @html hit . height }</ li >
< li >Weight: { @html hit . weight }</ li >
< li >Weaknesses: { @html hit . weaknesses . join ( ` , ` )}</ li >
</ ul >
< img src ={ hit . img } alt ={ hit . nameOrig } />
</ div >
< style >
/* highlights text matching the search string */
:global( em ) {
color : darkcyan ;
line-height : 1.2 em ;
border-radius : 3 pt ;
font-style : normal ;
}
div {
display : flex ;
justify-content : space-between ;
}
</ style >
Подстроки в атрибутах, соответствующие текущей строке поиска, будут заключены в <em>
, для правильного отображения которого требуется тег {@html ...}
но затем их можно стилизовать, чтобы подчеркнуть, почему конкретное попадание соответствует текущей строке поиска. Исходное значение (т.е. без тегов <em>
) каждого выделенного атрибута доступно как hit.[attr]Orig
. См. hit.nameOrig
выше.
Полный список свойств/привязываемых переменных для этого компонента:
appId: string
Идентификатор приложения Алголия
ariaLabel: string = `Search`
Сообщает вспомогательным технологиям, как объявить пользователю элемент ввода.
hasFocus: boolean = false
Привязываемое логическое значение, указывающее, находится ли в данный момент фокус на панели ввода текста или панели результатов.
indices: Record < string , typeof SvelteComponent > | [ string , typeof SvelteComponent ] [ ]
Объект сопоставляет имя каждого индекса, к которому компонент Search
должен подключиться для поиска результатов поиска, с компонентом Svelte, который должен отображать эти совпадения.
input: HTMLInputElement | null = null
Дескриптор узла DOM.
loadingMsg: string = `Searching...`
Строка, отображаемая на панели результатов во время получения результатов поиска.
noResultMsg = ( query : string ) : string => `No results for ' ${ query } '`
Функция, которая возвращает строку для отображения, если поиск не дал результатов.
placeholder: string = `Search`
Заполнитель, отображаемый при вводе текста перед тем, как пользователь начнет печатать.
query: string = ``
Текущее значение узла DOM.
resultCounter = ( hits : SearchHit [ ] ) : string =>
hits . length > 0 ? `<span>Results: ${ hits . length } <span>` : ``
Функция, возвращающая строку, которая будет отображаться рядом с именем каждого индекса, чтобы показать, сколько результатов было найдено в этом индексе. Верните пустую строку, чтобы ничего не показать.
searchKey: string
Ключ API только для поиска
Search.svelte
прослушивает события on:close
для каждого компонента попадания, который он отображает, и устанавливает для hasFocus
значение false
, чтобы закрыться при получении. Вы можете использовать это, например, чтобы закрыть интерфейс поиска, когда пользователь нажимает ссылку в одном из результатов поиска и переходит на другую страницу вашего сайта:
< script >
import { createEventDispatcher } from ' svelte '
export let hit
const dispatch = createEventDispatcher ()
</ script >
< h3 >
< a href ={ hit . slug } on:click ={() => dispatch ( ` close ` )}>{ @html hit . title }</ a >
</ h3 >
< p >{ @html hit . body }</ p >
Он также генерирует событие focus
каждый раз, когда пользователь щелкает значок поиска и фокус вводит ввод текста.
< Search on:focus ={() => console . log ( " Let's search! " )} />
Search.svelte
предлагает следующие перечисленные здесь переменные CSS с их значениями по умолчанию (если таковые имеются), которые можно передавать непосредственно в качестве реквизита:
button
color: var(--search-icon-color)
h2
color: var(--search-heading-color)
input
background: var(--search-input-bg)
color: var(--search-input-color)
font-size: var(--search-input-font-size, 1em)
input::placeholder
color: var(--search-input-color)
input.hasFocus + button
color: var(--search-input-color)
div.results
background-color: var(--search-hits-bg-color, white)
box-shadow: var(--search-hits-shadow, 0 0 2pt black)
Например:
< Search
indices ={{ Pages : SearchHit , Posts : SearchHit }}
{ appId }
{ searchKey }
-- hitsBgColor = " var(--search-body-bg) "
-- inputColor = " var(--search-text-color) "
-- iconColor = " var(--search-link-color) "
/>
Элемент верхнего уровня — это aside
класса svelte-algolia
. Таким образом, вы также можете стилизовать все дерево DOM под ним, определив глобальные стили, например
: global (aside.svelte-algolia input button svg) {
/* this would target the search icon */
}
: global (aside.svelte-algolia div.results section h2) {
/* this would target the heading shown above the list of results for each index */
}
Некоторые сайты, использующие svelte-algolia
в производстве:
studenten-bilden-schueler.de
[код]afara.foundation
[код]ocean-artup.eu
[код] Используете svelte-algolia
самостоятельно? Отправьте PR, чтобы добавить свой сайт сюда!
ПР приветствуются, но лучше сначала открыть вопрос, чтобы обсудить изменения.
Идентификатор приложения и ключ поиска .env
были намеренно зафиксированы, чтобы вы могли клонировать этот репозиторий и работать с ним без необходимости предварительного создания собственного индекса. Чтобы опробовать свои изменения на локальном сервере разработки, используйте
git clone https://github.com/janosh/svelte-algolia
cd svelte-algolia
sed -i.bak ' s/name: `Pokedex`/name: `Pokedex Clone`/ ' svelte.config.js
npm install
npm run dev
Обратите внимание на команду sed
, которая меняет имя индекса в site/svelte.config.js
с 'Pokedex'
на 'Pokedex Clone'
чтобы вы случайно не испортили индекс поиска для этого демонстрационного сайта во время разработки.