本文也算是一篇教程,可以给 hugo 网站加个搜索功能,并且实现热更新,体验感更好。
如果是其他程序,只需要按照特定的模板生成以下格式的文件即可,主要代码从 第 2 部分 开始,第一章节写的是如何用 hugo 输出文章列表 json 文件。
title
是文章标题,permalink
是文章链接。
[{
"permalink": "",
"title": ""
}, {
"permalink": "",
"title": ""
}]
1. hugo 模板生成文章列表 json 文件
在 layouts
文件夹下新建 index.json
文件,模板内容如下:
其中第 2 行最后面的 "blog"
是你文章文件夹的名称。大部分是 posts 等等,这里是我个人的名称。
{{- $.Scratch.Set "posts" slice -}}
{{- range where .Site.RegularPages "Type" "blog" -}}
{{- $.Scratch.Add "posts" (dict "title" .Title "permalink" .Permalink) -}}
{{- end -}}
{{- $.Scratch.Get "posts" | jsonify -}}
按照这个模板,hugo 本地预览可以打开 http://localhost:1313/index.json
查看,如果输出了一些数据如下图,说明你成功了。
2. js 代码
在 /layouts/_default
新建一个模板文件 search.html
,大致的结构参考其他模板文件,然后写入我们需要的内容。
首先是一个简单的 html 结构,给 input 绑定一个事件。
<form class="search">
<input type="text" id="searchTerm" name="searchTerm" autocomplete="off" oninput="initiateSearch()">
</form>
<div id="resultsContainer">请输入关键词进行搜索...</div>
然后通过一个 get 请求获取 json 文件,传入关键词参数,生成搜索列表。
<script>
function search(jsonData, searchTerm) {
let results = [];
for (let i = 0; i < jsonData.length; i++) {
for (let property in jsonData[i]) {
if (jsonData[i].hasOwnProperty(property) && jsonData[i][property].toString().indexOf(searchTerm) > -1) {
results.push(jsonData[i]);
break;
}
}
}
return results;
}
function displayResults(searchResults) {
let container = document.getElementById("resultsContainer");
container.innerHTML = "";
if (searchResults.length > 0) {
for (let i = 0; i < searchResults.length; i++) {
let resultDiv = document.createElement("div");
let resultTitle = document.createElement("a");
resultTitle.innerText = searchResults[i].title;
resultTitle.setAttribute('href', searchResults[i].permalink)
resultDiv.appendChild(resultTitle);
container.appendChild(resultDiv);
}
} else {
let noResultsMessage = document.createElement("p");
noResultsMessage.innerText = "没有找到搜索结果。";
container.appendChild(noResultsMessage);
}
}
function initiateSearch() {
let searchTerm = document.getElementById("searchTerm").value;
let xhr = new XMLHttpRequest();
xhr.open('GET', '/index.json', true);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
let jsonData = JSON.parse(xhr.responseText);
let searchResults = search(jsonData, searchTerm);
displayResults(searchResults);
}
};
xhr.send();
}
</script>
然后再在 /content
新建一个 search.md
文件调用该模板即可。
---
slug: search
title: 搜索
layout: search
---
写了一个基础的样式,可以直接使用。
.search {
width: 100%;
display: flex;
align-items: center;
height: 36px;
}
.search #searchTerm {
width: 100%;
height: 100%;
outline: none;
border: none;
padding: 0 15px;
box-shadow: 1px 2px 10px rgba(0, 0, 0, 0.1);
}
#resultsContainer {
margin-top: 20px;
}
#resultsContainer div {
margin-bottom: 10px;
margin: 0;
}
#resultsContainer div a {
display: block;
width: 100%;
padding: 6px 10px;
transition: all 0.1s linear;
border-radius: 4px;
}
#resultsContainer div a:hover {
background: #f3f3f3;
}