前言
今天花了些时间为博客增加了站内搜索功能,并且对主题进行了较大幅度的修改。
大致看上去就是这样的,当然,因为是截图,看不到动画效果。
本文做些记录。
搜索
之前肖高阳为我推荐了hexo-generator-search.
他的hexo所用的主题是Next,该主题是自带了这个插件的,只需要改下配置文件即可。
也就是说倘若你的主题没有集成该插件,需要自己安装配置。
Install
1 2 3 4 5
| ### npm npm install hexo-generator-search --save
### yarn yarn add hexo-generator-search --dev
|
Options
修改根目录下的_config.yml
1 2 3 4 5 6 7 8 9 10
| search: path: search.xml field: post ### path - 指定生成的索引数据的文件名。默认为 search.xml 。 field - 指定索引数据的生成范围。可选值包括: post - 只生成博客文章(post)的索引(默认); page - 只生成其他页面(page)的索引; all - 生成所有文章和页面的索引。
|
如果以上步骤都正确的话,会生成一个search.xml
文件。
通过你的预览地址/search.xml即可以预览
搜索框
1 2 3 4 5
| <div id="site_search"> <input type="text" id="local-search-input" name="q" results="0" placeholder="search my blog..." class="form-control"/> <div id="local-search-result"></div> </div>
|
将搜索框放置在你需要插入的地方
搜索函数
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
| var searchFunc = function(path, search_id, content_id) { 'use strict'; $.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 $input = document.getElementById(search_id); var $resultContent = document.getElementById(content_id); $input.addEventListener('input', function(){ var str='<ul class=\"search-result-list\">'; var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/); $resultContent.innerHTML = ""; if (this.value.trim().length <= 0) { return; } datas.forEach(function(data) { var isMatch = true; var content_index = []; 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_title != '' && 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; } } }); } if (isMatch) { str += "<li><a href='"+ data_url +"' class='search-result-title'>"+ data_title +"</a>"; 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 regS = new RegExp(keyword, "gi"); match_content = match_content.replace(regS, "<em class=\"search-keyword\">"+keyword+"</em>"); });
str += "<p class=\"search-result\">" + match_content +"...</p>" } str += "</li>"; } }); str += "</ul>"; $resultContent.innerHTML = str; }); } }); };
var path = "<%= config.root %>" + "search.xml"; searchFunc(path, 'local-search-input', 'local-search-result');
|
以下是于18年3月3日对搜索函数的更新。今天发现了博客的搜索结果点击还是停留在当前页面,发现上面搜索函数中的
1
| url: $( "url" , this).text()
|
没有获取到搜索结果的url,结果为空。我看了插件作者当初写的文章(本文末尾)的链接,确乎是上面的代码。不过已经不能工作了。
对这个搜索函数略做修改,又可以正常work了,贴下代码
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
| var searchFunc = function(path, search_id, content_id) { 'use strict'; $.ajax({ url: path, dataType: "xml", success: function( xmlResponse ) {
var datas = $( "entry", xmlResponse ).map(function() { return { title: $( "title", this ).text(), content: $("content",this).text(), url: $( "link" , this).attr("href") }; }).get(); var $input = document.getElementById(search_id); var $resultContent = document.getElementById(content_id); $input.addEventListener('input', function(){ var str='<ul class=\"search-result-list\">'; var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/); $resultContent.innerHTML = ""; if (this.value.trim().length <= 0) { return; }
datas.forEach(function(data) { var isMatch = true; var content_index = []; 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_title != '' && 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; } } }); } if (isMatch) {
str += "<li><a href='"+ data_url +"' class='search-result-title'>"+ data_title +"</a>"; console.log(data_url); console.log("=====命中=====", data);
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 regS = new RegExp(keyword, "gi"); match_content = match_content.replace(regS, "<em class=\"search-keyword\">"+keyword+"</em>"); });
str += "<p class=\"search-result\">" + match_content +"...</p>" } str += "</li>"; } }); str += "</ul>"; $resultContent.innerHTML = str; }); } }); };
var path = "<%= config.root %>" + "search.xml"; searchFunc(path, 'local-search-input', 'local-search-result');
|
将以上的搜索框和搜索函数放在适当的地方即可,我是放在layout.ejs
文件中的。
这样就完成了搜索框的核心部分了。这里我给出我定制过后的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
| @media screen and (max-width: 1000px) { #site_search{ display: none; } } @media screen and (min-width: 1000px){ #site_search{ position:fixed; z-index:4; white-space: normal; word-break: break-all; } #local-search-input{ display: flex; justify-content: center; align-items: center; opacity: 0.5; width: 250px; }
#local-search-input:focus{ opacity: 0.8; width: 540px; animation: car .5s ease-in; } #local-search-result{ background: white; color:black; opacity: .95; width: 570px; max-height: 600px; overflow: auto; }
.search-result{ max-height: 140px; overflow: hidden; } }
@keyframes car { 0%{ width: 250px; }
50%{ width: 1000px; }
100%{ opacity: 0.8; width: 540px; } }
|
主题改造
在我的第一篇博文叶尖滴落的星球中,提到过本博客是使用的huno,它是为Hexo编写的一个响应式的主题,该主题基于Uno。
到此刻,已经大半年过去了,我也写下了接近90篇博文。中途也对huno主题进行了数次修改,以符合我的需求。
在修改的过程中,发现源码中的不少地方写得不够合理。现在我的博客和当初也已经相差挺大了。
或许今后再优化更多过后,我会开源一个Suno的主题
现在博客PC端和移动端差距挺大的。
考虑到看我博客的大多数是程序员,来自PC的访问更多。
再加之手机相比PC硬件上差距还是很大,移动端,动画除了chrome都有些卡顿,于是就克制了一下,在移动端删除了首页动画…
参考
jQuery-based Local Search Engine for Hexo