站内搜索插件

Hugo是由 Steve Francis 大神(http://spf13.com/)基于Go语言开发的静态网站构建工具。没错你现在看到的本博客blog.qikqiak.com就是基于Hugo的,使用 Hugo 创建一个网站是非常简单的,基本上没有什么门槛,官方还提供了大量的主题供你选择,你只需要专心写你的文章就行。不过有个问题是搜索,我们知道搜索属于动态行为了,如何给静态网站增加搜索功能呢?当然我们可以使用Google的站内搜索功能,Hugo 官方也提供了一些开源的和商业的解决方案,今天我们要介绍的就是一个非常优秀的商业解决方案:Algolia

简介

Algolia是为你的 APP 或者网站添加搜索的最佳方式。 开发人员可以使用 API 上传并同步希望搜索的数据,然后可以进行相关的配置,比如产品转化率等等。可以使用 InstantSearch 等前端框架进行自定义搜索,为用户创造最佳的搜索体验。

注册

前往官方网站https://www.algolia.com/ 使用 GitHub 或 Google 帐号登录。登录完成后根据提示信息填写一些基本的信息即可,注册完成后前往 Dashboard,我们可以发现 Algolia 会默认给我们生成一个 app。
dashboard index

选择 Indices,添加一个新的索引,我们这里命名为qikqiak-blog,创建成功后,我们可以看到提示中还没有任何记录。
indices
Algolia 为我们提供了三种方式来增加记录:手动添加、上传 json 文件、API。我们这里使用第三种方式来进行数据的添加。

插件

要使用 API 的方式来添加搜索的数据,我们可以自己根据 Algolia 提供的 API 文档进行开发,这也是很容易的,为简单起见,我们这里使用一个hugo-algolia的插件来完成我们的数据同步工作。

要安装hugo-aligolia我们需要先确保我们已经安装了 npm 或者 yarn 包管理工具。

使用下面的命令安装即可:

  1. $ npm install hugo-algolia -g

安装完成后,在我们 hugo 生产的静态页面的根目录下面新建一个config.yaml的文件(和config.toml同级),然后在config.yaml文件中指定 Algolia相关的 API 数据。

  1. ---
  2. baseurl: "/"
  3. DefaultContentLanguage: "zh-cn"
  4. hasCJKLanguage: true
  5. languageCode: "zh-cn"
  6. title: "River's Site"
  7. theme: "beautifulhugo"
  8. metaDataFormat: "yaml"
  9. algolia:
  10. index: "qikqiak-blog"
  11. key: "3f541d53f128036d7542f6f2362d4a67"
  12. appID: "XYLRNJ38SQ"
  13. ---

API 相关数据可以前往 dashboard 的 API Keys查看,注意上面的keyAdmin API Key

配置完成以后,在根目录下面执行下面的命令:

  1. $ hugo-algolia -s
  2. JSON index file was created in public/algolia.json
  3. { updatedAt: '2018-02-23T02:36:09.480Z', taskID: 249063848950 }

然后我们可以看到,上面命令执行完成后会在public目录下面生成一个algolia.json的文件。这个时候我们在 dashboard 中打开 Indices,可以看到已经有几十条数据了。
Indices

如果某篇文章不想被索引的话,我们只需要在文件的最前面设置 index 参数为 false 即可,hugo-algolia插件在索引的过程中会自动跳过它。

前端

现在我们将需要被搜索的文章数据已经成功提交到Algolia,接下来的事情就是前端页面的展示了。下面的操作对于不同的主题或许有不同的地方,请根据自己的实际情况进行相应的修改。我这里使用的是beautifulhugo主题,在themes/beautifulhugo/layouts/partials目录下面新增文件:(search.html

  1. <div class="aa-input-container" id="aa-input-container">
  2. <input type="search" id="aa-search-input" class="aa-input-search" placeholder="Search for titles or URIs..." name="search" autocomplete="off" />
  3. <svg class="aa-input-icon" viewBox="654 -372 1664 1664">
  4. <path d="M1806,332c0-123.3-43.8-228.8-131.5-316.5C1586.8-72.2,1481.3-116,1358-116s-228.8,43.8-316.5,131.5 C953.8,103.2,910,208.7,910,332s43.8,228.8,131.5,316.5C1129.2,736.2,1234.7,780,1358,780s228.8-43.8,316.5-131.5 C1762.2,560.8,1806,455.3,1806,332z M2318,1164c0,34.7-12.7,64.7-38,90s-55.3,38-90,38c-36,0-66-12.7-90-38l-343-342 c-119.3,82.7-252.3,124-399,124c-95.3,0-186.5-18.5-273.5-55.5s-162-87-225-150s-113-138-150-225S654,427.3,654,332 s18.5-186.5,55.5-273.5s87-162,150-225s138-113,225-150S1262.7-372,1358-372s186.5,18.5,273.5,55.5s162,87,225,150s113,138,150,225 S2062,236.7,2062,332c0,146.7-41.3,279.7-124,399l343,343C2305.7,1098.7,2318,1128.7,2318,1164z" />
  5. </svg>
  6. </div>
  7. <script src="{{ "https://res.cloudinary.com/jimmysong/raw/upload/rootsongjc-hugo/algoliasearch.min.js" | absURL }}"></script>
  8. <script src="{{ "https://res.cloudinary.com/jimmysong/raw/upload/rootsongjc-hugo/autocomplete.min.js" | absURL }}"></script>
  9. <script>
  10. var client = algoliasearch("XYLRNJ38SQ", "3f541d53f128036d7542f6f2362d4a67");
  11. var index = client.initIndex('qikqiak-blog');
  12. autocomplete('#aa-search-input',
  13. { hint: false}, {
  14. source: autocomplete.sources.hits(index, {hitsPerPage: 8}),
  15. displayKey: 'name',
  16. templates: {
  17. suggestion: function(suggestion) {
  18. console.log(suggestion);
  19. return '<span>' + '<a href="/post/' + suggestion.slug + '">' +
  20. suggestion._highlightResult.title.value + '</a></span>';
  21. }
  22. }
  23. });
  24. </script>

注意上面 JS 代码:

  1. var client = algoliasearch("XYLRNJ38SQ", "3f541d53f128036d7542f6f2362d4a67");
  2. var index = client.initIndex('qikqiak-blog');

其中algoliasearch的第一个参数为Application ID,第二个参数为Search-Only API Key,下面的initIndex方法的参数为我们创建的索引名称qikqiak-blog

然后我们只需要添加一个搜索入口即可,在themes/beautifulhugo/layouts/partials/nav.html文件最下面添加如下代码:

  1. <div id="modalSearch" class="modal fade" role="dialog">
  2. <div class="modal-dialog">
  3. <div class="modal-content">
  4. <div class="modal-header">
  5. <button type="button" class="close" data-dismiss="modal">&times;</button>
  6. <h4 class="modal-title">Search blog.qikqiak.com</h4>
  7. </div>
  8. <div class="modal-body">
  9. {{ partial "search.html" . }}
  10. </div>
  11. <div class="modal-footer">
  12. <button type="button" class="btn btn-default" data-dismiss="modal">close</button>
  13. </div>
  14. </div>
  15. </div>
  16. </div>

并且在下面代码下面,添加搜索入口按钮
只要在config.toml文件[Params]里面带有algolia = “xxxxxxxxxxx”,配置按钮的配置就会生效。

  1. {{ if isset .Site.Params "gcse" }}
  2. <li>
  3. <a href="#modalSearch" data-toggle="modal" data-target="#modalSearch" style="outline: none;">
  4. <span class="hidden-sm hidden-md hidden-lg">{{ i18n "gcseLabelShort" }}</span> <span id="searchGlyph" class="glyphicon glyphicon-search"></span>
  5. </a>
  6. </li>
  7. {{ end }}
  1. {{ if isset .Site.Params "algolia" }}
  2. <li>
  3. <a href="#modalSearch" data-toggle="modal" data-target="#modalSearch" style="outline: none;">
  4. <span class="hidden-sm hidden-md hidden-lg">{{ i18n "gcseLabelShort" }}</span> <span id="searchGlyph" class="glyphicon glyphicon-search"></span>
  5. </a>
  6. </li>
  7. {{ end }}

其中最重要的代码是引入上面我们新建的search.html文件。剩下的就是一些美化搜索页面的工作,新建themes/beautifulhugo/static/css/search.css文件:

  1. @import 'https://fonts.googleapis.com/css?family=Montserrat:400,700';
  2. .aa-input-container {
  3. display: inline-block;
  4. position: relative;
  5. width: 100%;
  6. }
  7. .aa-input-container span,.aa-input-container input {
  8. width: inherit;
  9. }
  10. .aa-input-search {
  11. width: 300px;
  12. padding: 12px 28px 12px 12px;
  13. border: 2px solid #e4e4e4;
  14. border-radius: 4px;
  15. -webkit-transition: .2s;
  16. transition: .2s;
  17. font-family: "Montserrat", sans-serif;
  18. box-shadow: 4px 4px 0 rgba(241, 241, 241, 0.35);
  19. font-size: 11px;
  20. box-sizing: border-box;
  21. color: #333;
  22. -webkit-appearance: none;
  23. -moz-appearance: none;
  24. appearance: none;
  25. }
  26. .aa-input-search::-webkit-search-decoration, .aa-input-search::-webkit-search-cancel-button, .aa-input-search::-webkit-search-results-button, .aa-input-search::-webkit-search-results-decoration {
  27. display: none;
  28. }
  29. .aa-input-search:focus {
  30. outline: 0;
  31. border-color: #3a96cf;
  32. box-shadow: 4px 4px 0 rgba(58, 150, 207, 0.1);
  33. }
  34. .aa-input-icon {
  35. height: 16px;
  36. width: 16px;
  37. position: absolute;
  38. top: 50%;
  39. right: 16px;
  40. -webkit-transform: translateY(-50%);
  41. transform: translateY(-50%);
  42. fill: #e4e4e4;
  43. }
  44. .aa-hint {
  45. color: #e4e4e4;
  46. }
  47. .aa-dropdown-menu {
  48. background-color: #fff;
  49. border: 2px solid rgba(228, 228, 228, 0.6);
  50. border-top-width: 1px;
  51. font-family: "Montserrat", sans-serif;
  52. width: 300px;
  53. margin-top: 10px;
  54. box-shadow: 4px 4px 0 rgba(241, 241, 241, 0.35);
  55. font-size: 11px;
  56. border-radius: 4px;
  57. box-sizing: border-box;
  58. }
  59. .aa-suggestion {
  60. padding: 12px;
  61. border-top: 1px solid rgba(228, 228, 228, 0.6);
  62. cursor: pointer;
  63. -webkit-transition: .2s;
  64. transition: .2s;
  65. display: -webkit-box;
  66. display: -ms-flexbox;
  67. display: flex;
  68. -webkit-box-pack: justify;
  69. -ms-flex-pack: justify;
  70. justify-content: space-between;
  71. -webkit-box-align: center;
  72. -ms-flex-align: center;
  73. align-items: center;
  74. }
  75. .aa-suggestion:hover, .aa-suggestion.aa-cursor {
  76. background-color: rgba(241, 241, 241, 0.35);
  77. }
  78. .aa-suggestion > span:first-child {
  79. color: #333;
  80. }
  81. .aa-suggestion > span:last-child {
  82. text-transform: uppercase;
  83. color: #a9a9a9;
  84. }
  85. .aa-suggestion > span:first-child em, .aa-suggestion > span:last-child em {
  86. font-weight: 700;
  87. font-style: normal;
  88. background-color: rgba(58, 150, 207, 0.1);
  89. padding: 2px 0 2px 2px;
  90. }

当然还得在页面中引入上面的 CSS 样式文件,在文件themes/beautifulhugo/layouts/partials/head.htmlhead区域添加如下代码:

  1. <link rel="stylesheet" href="{{ "css/search.css" | absURL }}" />

搜索

上面的所有工作完成后,我们重新生成静态页面,更新网站数据。我们可以看到导航栏最右边已经有了一个搜索按钮了。
search demo

参考资料