博客的搜索功能是怎么实现的
之前我介绍了我的博客的实现,其中最后的demo里面有个搜索功能,今天就来介绍下这个搜索功能的实现吧。其实静态博客的搜索功能实现起来挺简单的
思路
假设我们有一个posts 的包含所有文章信息的列表, 通过generate_search_xml函数处理传入的posts参数,将文章的标题、内容等信息写入一个search.xml文件内,后续在通过搜索页面对该文件内容进行搜索实现搜索展示。这里涉及到两个部分:
search.xml文件的生成,由generate_search_xml函数实现- 搜索页面对
search.xml文件进行搜索,并展示搜索结果
generate_search_xml函数实现
import xml.etree.ElementTree as ET
def generate_search_xml(posts):
"""根据文章信息生成 search.xml"""
search_xml = ET.Element('search')
for post in posts:
title = post['title']
html_content = post['html_content']
metadata = post['metadata']
# 生成描述,提取文章正文的前200个字符作为描述
description = html_content[:200].strip() # 提取内容的前200个字符作为描述
if len(description) == 200 and html_content[200] not in [' ', '<']: # 防止截断在单词或标签中间
description = description.rsplit(' ', 1)[0]
item = ET.SubElement(search_xml, 'item')
title_elem = ET.SubElement(item, 'title')
title_elem.text = title
description_elem = ET.SubElement(item, 'description')
description_elem.text = description
# metadata_elem = ET.SubElement(item, 'metadata')
# metadata_elem.text = metadata
html_content_elem = ET.SubElement(item, 'html_content')
html_content_elem.text = html_content
# 写入到 search.xml 文件
tree = ET.ElementTree(search_xml)
output_path = os.path.join(OUTPUT_DIR, 'search.xml')
tree.write(output_path, encoding='utf-8', xml_declaration=True)
# print(f"search.xml 文件已保存至 {output_path}")
print(f"Generated {search_xml}")
上面这个函数,将每篇文章的信息以<item>元素添加到search.xml文件的根元素<search>当中,每个 <item> (也就是每篇文章)包含:
<title>: 文章标题<description>: 文章描述(前200个字符)<html_content>: 文章的完整 HTML 内容
搜索页面的实现
首先通过loadXML()函数加载search.xml文件到searchData列表,然后通过id="search-input"获取搜索关键字query,通过方法filter查找包含关键字query的内容。最后对查找结果使用displayResults方法进行生成展示
- 搜索页模板
search.html
{% extends "base.html" %}
{% block title %}搜索页面{% endblock %}
{% block content %}
<!-- 页面主要内容 -->
<div class="search-box content">
{# <h1>搜索页面</h1>#}
<div id="search-container">
<img src="../static/img/搜索_search.png" alt="Search Icon" class="search-icon"> <!-- 这里是你的搜索图标图片路径 -->
<input type="text" id="search-input" placeholder="请输入搜索关键字" oninput="search()">
</div>
<div id="search-results"></div>
</div>
<script>
// 初始化变量
let searchData = [];
// 加载 search.xml 数据
function loadXML() {
fetch('search.xml')
.then(response => response.text())
.then(data => {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(data, 'text/xml');
const items = xmlDoc.getElementsByTagName('item');
searchData = [];
for (let i = 0; i < items.length; i++) {
let title = items[i].getElementsByTagName('title')[0].textContent;
let description = items[i].getElementsByTagName('description')[0].textContent;
let html_content = items[i].getElementsByTagName('html_content')[0].textContent;
searchData.push({ title, description,html_content });
}
})
.catch(error => console.error('加载 XML 数据失败:', error));
}
function search() {
const query = document.getElementById('search-input').value.trim().toLowerCase();
// 如果搜索框为空,清空结果并返回
if (query === '') {
document.getElementById('search-results').innerHTML = ''; // 清空搜索结果
return;
}
// 如果有搜索内容,执行搜索操作
const results = searchData.filter(item =>
item.title.toLowerCase().includes(query) || item.description.toLowerCase().includes(query) || item.html_content.toLowerCase().includes(query)
);
displayResults(query,results);
}
// 显示搜索结果
function displayResults(query,results) {
const resultsContainer = document.getElementById('search-results');
resultsContainer.innerHTML = '';
if (results.length === 0) {
resultsContainer.innerHTML = '<p>没有找到相关结果</p>';
return;
}
results.forEach(item => {
const resultTitle = document.createElement('h1');
resultTitle.innerHTML=`包含关键字<span class="query-color">${query}</span>的文章:`;
resultsContainer.appendChild(resultTitle);
const resultItem = document.createElement('div');
resultItem.className = 'result-item';
resultItem.innerHTML = `
<div class="result-title">
<img src="../static/img/文字_text.png">
<a href="article/${item.title}.html">${item.title}</a>
</div>
<div class="result-description">${item.description}</div>
`;
resultsContainer.appendChild(resultItem);
});
}
// 初始化时加载 XML 数据
window.onload = loadXML;
</script>
{% endblock %}
- 搜索页面渲染函数实现
def generate_search_pages():
""" 根据search_template 生成搜索页面"""
search_template = env.get_template('search.html')
search_output_file = os.path.join(OUTPUT_DIR, f"search.html")
# 创建目录(如果不存在)
# os.makedirs(os.path.dirname(share_output_file), exist_ok=True)
with open(search_output_file, 'w', encoding='utf-8') as file:
file.write(search_template.render())
print(f"Generated {search_output_file}")
这样搜索功能就完成了。