高亮与代码片段 #
高亮概述 #
Algolia自动为搜索结果中的匹配关键词添加高亮标记,帮助用户快速定位相关内容。
高亮效果 #
text
搜索词: "iphone"
结果: <em>iPhone</em> 15 Pro - Apple's latest smartphone
配置高亮 #
设置高亮属性 #
javascript
await index.setSettings({
attributesToHighlight: ['name', 'description', 'brand']
});
搜索时指定 #
javascript
const results = await index.search('iphone', {
attributesToHighlight: ['name', 'description']
});
高亮结果结构 #
_highlightResult #
javascript
{
"objectID": "1",
"name": "iPhone 15 Pro",
"description": "Apple iPhone with A17 Pro chip",
"_highlightResult": {
"name": {
"value": "<em>iPhone</em> 15 Pro",
"matchLevel": "full",
"matchedWords": ["iphone"],
"fullyHighlighted": false
},
"description": {
"value": "Apple <em>iPhone</em> with A17 Pro chip",
"matchLevel": "full",
"matchedWords": ["iphone"],
"fullyHighlighted": false
}
}
}
字段说明 #
| 字段 | 说明 |
|---|---|
| value | 高亮后的文本 |
| matchLevel | 匹配级别 |
| matchedWords | 匹配的词列表 |
| fullyHighlighted | 是否完全高亮 |
matchLevel值 #
| 值 | 说明 |
|---|---|
| full | 完全匹配 |
| partial | 部分匹配 |
| none | 无匹配 |
自定义高亮标签 #
默认标签 #
默认使用 <em> 标签:
html
<em>iPhone</em> 15 Pro
自定义标签 #
javascript
const results = await index.search('iphone', {
attributesToHighlight: ['name', 'description'],
highlightPreTag: '<mark>',
highlightPostTag: '</mark>'
});
// 结果: <mark>iPhone</mark> 15 Pro
使用CSS类 #
javascript
const results = await index.search('iphone', {
attributesToHighlight: ['name'],
highlightPreTag: '<span class="highlight">',
highlightPostTag: '</span>'
});
// 结果: <span class="highlight">iPhone</span> 15 Pro
高亮UI实现 #
基本渲染 #
javascript
function renderHit(hit) {
const name = hit._highlightResult.name.value;
return `
<div class="product">
<h3>${name}</h3>
</div>
`;
}
安全渲染 #
javascript
function safeHighlight(highlightResult) {
// 使用DOM API避免XSS
const div = document.createElement('div');
div.innerHTML = highlightResult.value;
// 为高亮标签添加样式
div.querySelectorAll('em').forEach(el => {
el.classList.add('highlight');
});
return div.innerHTML;
}
React组件 #
jsx
function Hit({ hit }) {
return (
<div className="hit">
<h3
dangerouslySetInnerHTML={{
__html: hit._highlightResult.name.value
}}
/>
<p
dangerouslySetInnerHTML={{
__html: hit._highlightResult.description?.value
}}
/>
</div>
);
}
Vue组件 #
vue
<template>
<div class="hit">
<h3 v-html="hit._highlightResult.name.value"></h3>
<p v-html="hit._highlightResult.description?.value"></p>
</div>
</template>
代码片段 #
什么是代码片段? #
代码片段(Snippet)是截取匹配词周围的一段文本,用于展示上下文。
text
原文: "The new iPhone 15 Pro features the powerful A17 Pro chip,
delivering unprecedented performance for mobile gaming and
professional video editing."
搜索: "chip"
片段: "...features the powerful A17 Pro <em>chip</em>, delivering..."
配置代码片段 #
javascript
await index.setSettings({
attributesToSnippet: ['description:50', 'content:100']
});
搜索时指定 #
javascript
const results = await index.search('chip', {
attributesToSnippet: ['description:50']
});
片段结果结构 #
javascript
{
"_snippetResult": {
"description": {
"value": "...powerful A17 Pro <em>chip</em>, delivering unprecedented...",
"matchLevel": "full"
}
}
}
片段长度 #
javascript
// 数字表示返回的最大字符数
attributesToSnippet: ['description:50'] // 约50字符
attributesToSnippet: ['content:200'] // 约200字符
自定义省略号 #
默认省略号 #
默认使用 … 作为省略号。
自定义省略号 #
javascript
const results = await index.search('chip', {
attributesToSnippet: ['description:50'],
snippetEllipsisText: '…'
});
高亮与片段组合 #
同时使用 #
javascript
const results = await index.search('iphone', {
attributesToHighlight: ['name'],
attributesToSnippet: ['description:100']
});
// 渲染
function renderHit(hit) {
const name = hit._highlightResult.name.value;
const description = hit._snippetResult?.description?.value || hit.description;
return `
<div class="hit">
<h3>${name}</h3>
<p>${description}</p>
</div>
`;
}
优先级 #
javascript
function getDisplayValue(hit, attribute) {
// 优先使用片段,其次高亮,最后原始值
if (hit._snippetResult?.[attribute]) {
return hit._snippetResult[attribute].value;
}
if (hit._highlightResult?.[attribute]) {
return hit._highlightResult[attribute].value;
}
return hit[attribute];
}
高级用法 #
多属性高亮 #
javascript
const results = await index.search('apple', {
attributesToHighlight: ['name', 'brand', 'description']
});
// 检查哪个属性匹配
function getMatchedAttributes(hit) {
const matched = [];
for (const [attr, result] of Object.entries(hit._highlightResult)) {
if (result.matchLevel !== 'none') {
matched.push(attr);
}
}
return matched;
}
嵌套属性高亮 #
javascript
// 数据结构
{
"name": "iPhone",
"specs": {
"display": "6.1 inch",
"chip": "A17 Pro"
}
}
// 高亮嵌套属性
const results = await index.search('chip', {
attributesToHighlight: ['specs.chip']
});
// 结果
{
"_highlightResult": {
"specs": {
"chip": {
"value": "A17 <em>Pro</em>"
}
}
}
}
数组属性高亮 #
javascript
// 数据结构
{
"tags": ["phone", "apple", "5g"]
}
// 高亮数组
const results = await index.search('apple', {
attributesToHighlight: ['tags']
});
// 结果
{
"_highlightResult": {
"tags": [
{ "value": "phone", "matchLevel": "none" },
{ "value": "<em>apple</em>", "matchLevel": "full" },
{ "value": "5g", "matchLevel": "none" }
]
}
}
高亮样式 #
CSS样式 #
css
/* 默认em标签 */
em {
background-color: #fff3cd;
color: #856404;
padding: 0 2px;
border-radius: 2px;
font-style: normal;
}
/* 自定义类 */
.highlight {
background-color: #ffeb3b;
font-weight: bold;
}
/* 深色主题 */
.dark-theme em {
background-color: #5468ff;
color: white;
}
动画效果 #
css
em {
animation: highlight-fade 2s ease-out;
}
@keyframes highlight-fade {
0% {
background-color: #ffeb3b;
}
100% {
background-color: transparent;
}
}
高亮工具函数 #
高亮处理类 #
javascript
class HighlightProcessor {
constructor(options = {}) {
this.preTag = options.preTag || '<em>';
this.postTag = options.postTag || '</em>';
}
process(hit, attribute) {
const highlight = hit._highlightResult?.[attribute];
const snippet = hit._snippetResult?.[attribute];
if (snippet && snippet.matchLevel !== 'none') {
return this.wrap(snippet.value);
}
if (highlight && highlight.matchLevel !== 'none') {
return this.wrap(highlight.value);
}
return hit[attribute];
}
wrap(value) {
// 确保高亮标签正确
return value;
}
stripTags(value) {
return value
.replace(new RegExp(this.preTag, 'g'), '')
.replace(new RegExp(this.postTag, 'g'), '');
}
getMatchedWords(hit, attribute) {
return hit._highlightResult?.[attribute]?.matchedWords || [];
}
isFullyHighlighted(hit, attribute) {
return hit._highlightResult?.[attribute]?.fullyHighlighted || false;
}
}
使用示例 #
javascript
const processor = new HighlightProcessor({
preTag: '<mark>',
postTag: '</mark>'
});
const displayValue = processor.process(hit, 'name');
const matchedWords = processor.getMatchedWords(hit, 'name');
完整示例 #
搜索结果组件 #
javascript
class SearchResultRenderer {
constructor(container) {
this.container = container;
}
render(results) {
this.container.innerHTML = results.hits
.map(hit => this.renderHit(hit))
.join('');
}
renderHit(hit) {
return `
<article class="search-result">
<h3 class="result-title">
${this.getHighlightedValue(hit, 'name')}
</h3>
<p class="result-description">
${this.getSnippetValue(hit, 'description', 150)}
</p>
<div class="result-meta">
<span class="brand">${hit.brand}</span>
<span class="price">$${hit.price}</span>
<span class="rating">★ ${hit.rating}</span>
</div>
</article>
`;
}
getHighlightedValue(hit, attribute) {
if (hit._highlightResult?.[attribute]) {
return hit._highlightResult[attribute].value;
}
return hit[attribute] || '';
}
getSnippetValue(hit, attribute, maxLength = 100) {
if (hit._snippetResult?.[attribute]) {
return hit._snippetResult[attribute].value;
}
const value = hit[attribute] || '';
if (value.length <= maxLength) {
return value;
}
return value.substring(0, maxLength) + '…';
}
}
总结 #
高亮与代码片段要点:
| 要点 | 说明 |
|---|---|
| 高亮配置 | attributesToHighlight |
| 片段配置 | attributesToSnippet |
| 结果结构 | _highlightResult, _snippetResult |
| 自定义标签 | highlightPreTag, highlightPostTag |
| 省略号 | snippetEllipsisText |
| 安全渲染 | 避免XSS攻击 |
接下来,让我们学习 同义词管理。
最后更新:2026-03-28