为Hexo博客添加全文搜索

本文介绍如何利用hexo-generator-search插件为Hexo博客添加本地全文搜索

原理

hexo-generator-search实际上是根据网页内容生成了一个数据文件,格式是XML或者JSON。然后通过JS代码去匹配这个文件的内容,从而达到搜索的目的。

最终效果

最终效果

步骤

安装 hexo-generator-search

$ npm install hexo-generator-search --save

配置

_config.yml中添加

search:
  path: search.xml
  field: post

使用

再次生成博客,就会发现public根目录下多了search.xml文件。

写一个搜索框:

使用Bootstrap框架的modal应该是极好的。 修改Hexo主题,(对此不了解的可以查看我的自定义Hexo主题的相关内容),在layout.ejs中添加一个modal:

<%- partial('_partial/search-modal') %>

根据Bootstrap文档,modal需要尽量作为 body 标签的直接子元素。

search-modal.ejs的代码如下:

<div class="modal fade" id="searchModal">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-body">
                <i class="fa fa-search" aria-hidden="true"></i> 搜索
                <input type="text" class="form-control" id="searchInput" placeholder="Keyword">
                <div class="search-content" id="searchResult"></div>
            </div>
        </div>
    </div>
</div>

链接加上data-toggle="modal" href="#searchModal"属性即可实现modal的展开

搜索代码:

// A local search script with the help of [hexo-generator-search](https://github.com/PaicHyperionDev/hexo-generator-search)
// Copyright (C) 2015
// Joseph Pan <http://github.com/wzpan>
// Shuhao Mao <http://github.com/maoshuhao>
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301 USA
//

var searchFunc = function(path, search_id, content_id) {
    'use strict';
    $.ajax({
        url: path,
        dataType: "xml",
        success: function( xmlResponse ) {
            // get the contents from search data
            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;
                }
                // perform local searching
                datas.forEach(function(data) {
                    var isMatch = true;
                    var content_index = [];
                    if (!data.title || data.title.trim() === '') {
                        data.title = "Untitled";
                    }
                    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;
                    // only match artiles with not empty contents
                    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;
                                }
                                // content_index.push({index_content:index_content, keyword_len:keyword_len});
                            }
                        });
                    } else {
                        isMatch = false;
                    }
                    // show search results
                    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) {
                            // cut out 100 characters
                            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);

                            // highlight all keywords
                            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;
            });
        }
    });
}

添加链接

<%- js('js/search') %>
<script>searchFunc('<%= url_for('search.xml') %>', 'searchInput', 'searchResult');</script>

高亮关键词

keywords.forEach(function(keyword){
                            var regS = new RegExp(keyword, "gi");
                            data_title = data_title.replace(regS, "<em class="search-keyword">"+keyword+"</em>");
                        });
.search-keyword{
    color: #c7254e;
}

本文原始发表于:https://wycode.cn/blog/search 转载请注明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值