本文也算是一篇教程,可以给 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; }