搜索功能的实现最主要是生成一份关键字到站内链接的索引,当用户输入关键字后能够根据索引展示相应的链接。
通常,搜索引擎公司(例如Google,百度)会有自己的爬虫,当你将自己的网站地址提交给他们后,他们会用爬虫定期分析你的网站结构,然后生成索引文件并加入自己的索引库中。这样当终端用户输入和你的网站匹配的关键词后,你的网站内的链接就会在结果中显示出来。
站内搜索一般就不需要爬虫了,因为,其实最重要的是索引文件,只要你的网站更新的时候同时更新索引文件即可。
插入Google搜索框
你可以利用Hexo函数search_form直接插入Google搜索框。
search_form
插入 Google 搜索框。
1
| <%- search_form(options) %>
|
参数 |
描述 |
默认值 |
class |
表单的 class name |
search-form |
text |
搜索提示文字 |
Search |
button |
显示搜索按钮。此参数可为布尔值(boolean)或字符串, 当设定是字符串的时候,即为搜索按钮的文字。 |
false |
自定义站内搜索
你也可以利用Hexo插件实现自己的站内搜索的功能。
安装插件
这个插件的本质是生成了一个搜索索引文件。
插件: hexo-generator-search
通过以下命令安装:
1
| $ npm install hexo-generator-search --save
|
修改hexo配置
在_config.yml中添加站内搜索配置项:
1 2 3 4
| search: path: search.xml field: all
|
实现搜索框视图
结构文件
search.ejs
1 2 3 4 5 6 7 8 9 10
| <div class="search-box" id="search-box"> <form> <div class="search-btn"></div> <input autocomplete="off" type="text" id="search-input" name="q" results="0" placeholder="搜索" /> <button type="reset" class="reset-search-btn"></button> </form> <article id="search-result" class="search-result content"></article> </div>
|
样式文件
search.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| // 搜索框 .search-box { position: absolute; right: 40px; top: 13px; width: 40px; height: 36px; line-height: 1; outline: none; transition: width 0.1s; } .search-box-focus { width: 164px; padding-left: 38px; background: #f0f1f2; } .search-box-focus #search-input { display: block; } .search-box form { display: block; padding: 0; margin: 0; } .search-box .search-btn, .reset-search-btn { position: absolute; width: 30px; height: 30px; top: 3px; border: none; outline: 0; background-size: 30px 30px; background-repeat: no-repeat; background-position: center; background-color: initial; } .search-box .search-btn { left: 3px; background-image: url(../images/header_search.png); } .reset-search-btn { right: 3px; display: none; background-image: url(../images/header_close.png); } .search-box-focus .reset-search-btn{ display: block; } #search-input { display: none; width: calc(100% - 36px); border: none; font: inherit; font-size: 14px; line-height: 1; outline: none; padding: 8px 0; background: transparent; } #search-input::-webkit-input-placeholder { color: #999; } .search-result ul, .search-result li { list-style: none; margin: 0; padding: 0; } .search-result li { padding-top: 30px; } .search-result li .search-result { overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; } .search-result { display: none; } .search-result h1 { padding-bottom: 20px; margin-bottom: 0; color: #333; } .search-result em { color: #38f; -webkit-text-emphasis: none; } .search-result h1 em { margin: 0 5px; } .search-result h1.empty-title { color: #999; border-bottom: none; padding-top: 200px; text-align: center; }
|
实现站内搜索逻辑
search.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
| function searchFunc(path, searchId, contentId) { $.ajax({ url: path, dataType: 'xml', success: function (xmlResponse) { var datas = $('entry', xmlResponse).map(function () { return { title: $('title', this).text(), content: $('content', this).text(), url: $('url', this).text() }; }).get();
var $searchBox = $('#' + searchId); if (!($searchBox && $searchBox.length == 1)) { return; } var $resultContent = $('#' + contentId); if (!($resultContent && $resultContent.length == 1 )) { return; }
var $input = $searchBox.find('#search-input'); var $searchBtn = $searchBox.find('.search-btn'); var $resetBtn = $searchBox.find('.reset-search-btn');
$searchBtn.on('click', function (e) { $searchBox.addClass('search-box-focus'); $input[0].focus(); }); $resetBtn.on('click', function (e) { $('#content').css({ display: 'block' }); $resultContent.css({ display: 'none' }); $input[0].focus(); }); $input.on('blur', function () { ($(this).val() === '') && $searchBox.removeClass('search-box-focus'); }); var flag = true; $input.on('compositionstart', function () { flag = false; }); $input.on('compositionend', function () { flag = true; }); $input.on('keydown', function (e) { var e = e || event; if (e.keyCode === 13) { e.returnValue = false; e.preventDefault(); } }) $input.on('input', function () { var $this = this; setTimeout(function () { if (!flag) { return; } var str = '<ul class="search-result-list">'; var keywords = $this.value.trim().toLowerCase().split(/\s+/); $resultContent[0].innerHTML = ''; if ($this.value.trim().length <= 0) { $('#content').css({ display: 'block' }); $resultContent.css({ display: 'none' }); return; } else { $('#content').css({ display: 'none' }); $resultContent.css({ display: 'block' }); } var matchCount = 0; datas.forEach(function (data) { var isMatch = true; if (!data.title || data.title.trim() === '') { return false; } var data_title = data.title.trim().toLowerCase(); var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase(); var data_url = data.url; var index_title = -1; var index_content = -1; var first_occur = -1; if (data_content !== '') { keywords.forEach(function (keyword, i) { index_title = data_title.indexOf(keyword); index_content = data_content.indexOf(keyword);
if (index_title < 0 && index_content < 0) { isMatch = false; } else { if (index_content < 0) { index_content = 0; } if (i === 0) { first_occur = index_content; } } }); } else { isMatch = false; } if (isMatch) { matchCount++; str += '<li><h3><a target = "_blank" href="' + data_url + '" class="search-result-title">' + data_title + '</a></h3>'; var content = data.content.trim().replace(/<[^>]+>/g, ''); if (first_occur >= 0) { var start = first_occur - 20; var end = first_occur + 80;
if (start < 0) { start = 0; }
if (start === 0) { end = 100; }
if (end > content.length) { end = content.length; }
var match_content = content.substr(start, end);
keywords.forEach(function (keyword) { var reg = new RegExp(keyword, 'gi'); match_content = match_content.replace(reg, function (str) { return '<em class="search-keyword">' + str + '</em>'; }) });
str += '<p class="search-result">' + match_content + '...</p>'; } str += '</li>'; } }); $input.attr('results', matchCount); str += '</ul>'; var title = matchCount ? '<h1>找到<em>' + $this.value.trim() + '</em>相关内容' + matchCount + '个</h1>' : '<h1 class="empty-title">没有找到<em>' + $this.value.trim() + '</em>相关内容</h1>'; str = title + str; $('#content').css({ display: 'none' });
$resultContent.css({ display: 'block' }); $resultContent[0].innerHTML = str; }, 0); }); } }); };
|
将搜索功能添加如页面
将如下代码添加到合适的地方,一般为layout.ejs 最下方
1 2 3 4 5 6 7 8 9 10 11
| <% if (config.search) { %> <script type="text/javascript" src="/js/search.js"></script> <script type="text/javascript"> var search_path = "<%= config.search.path %>"; if (search_path.length == 0) { search_path = "search.xml"; } var path = "<%= config.root %>" + search_path; searchFunc(path, 'search-box', 'search-result'); </script> <% } %>
|