我使用的主题是chic

修改主题markdown的高亮代码

我当前使用的主题是不支持jsx的,所以对于react代码不能友好支持。所以使用hexo-prism-plugin修改了高亮部分

  • 坑: 我安装了 hexo-prism-plugin 之后发现还是无法高亮 jsx 代码, 后来发现还要要安装 hexo-inject 模块
  • npm install hexo-prism-plugin hexo-inject --save
  • 修改_config.yml
highlight:
  enable: false  # 关闭默认的highlight

prism_plugin:
  mode: 'preprocess'    # realtime/preprocess
  theme: 'base16-ateliersulphurpool.light' # 主题
  line_number: false    # default false
  # custom_css: 'path/to/your/custom.css'  

为主题图片添加大图

主题无法对图片进行放大,图片最大也只是 780 * 562, 体验上不是很好,这里我使用了fancybox 进行修改

下载fancybox的文件

  • jquery.fancybox.min.js, jquery.min.js 放入 theme/chic/source/js 目录下

  • jquery.fancybox.min.css 放入 theme/chic/source/css/_lib/目录下

  • 修改 chic/_config.yml, 添加代码

    fancybox: 
      enable: true
      jquery: /js/jquery.min.js
      fancyjs: /js/jquery.fancybox.min.js
  • 修改 Chic/layout/_partial/head.ejs 添加以下代码

<% if(theme.fancybox.enable!==null&&theme.fancybox.enable===true){ %>
    <script type="text/javascript"  src="<%- url_for(theme.fancybox.jquery) %>"></script>
    <script type="text/javascript"  src="<%- url_for(theme.fancybox.fancyjs) %>"></script>
<% } %>
  • Chic/source/css/style.styl 添加,
@import "_lib/jquery.fancybox.min.css"

这里添加css 不知道为什么不可以直接 跟上面添加js 一样,我找了很久都没找到解决方案,只能够在style 下强行添加css

  • 最后在 source/js/script.js 的document.ready()的回调回调函数添加 以下代码就可以
$("a.group").fancybox({
    'transitionIn'    :    'elastic',
    'transitionOut'    :    'elastic',
    'speedIn'        :    600, 
    'speedOut'        :    200, 
    'overlayShow'    :    false
});

使用

这里强行使用<a class="group">链接 包裹这img 表示使用fancybox

<a class="group" rel="group1" href="图片url">
    <img src="图片url" />    
</a>

添加力扣页面

我这里是想自定义添加一个新的页面,主要放自己练习算法时的解题思路,叫力扣,但又不想跟原来发表的文章混在一起

  • 添加文件夹 source/algorithm, 只有一个文件index.md
# index.md
---
title: 力扣
date: 2020-04-08 16:09:43
layout: algorithm
---
  • Chic/layout 添加 algorithm.ejs
<%- partial('_page/algorithm', {pagination: config.archive, index: true}) %>
  • Chic/layout/_page 添加 algorithm.ejs
// Chic/layout/_page/algorithm.ejs
<div class="post-wrap algorithm-page archive">
    <div class="tags-algorithm">
        // 这里就是算法 tag, 我只筛选出 tag包含 algorithm- 的那些
        <%site.tags.forEach(item=>{%>
            <% if(item.name.includes("algorithm-")) { %>
                <a class="tags-item" href="<%-url_for(item.path)%>"><%- item.name.split("algorithm-")[1] %><span class="nums"><%-item.length%></%-item.length%></span></%-></a>
            <% } %>
        <%})%> 1 < div> <div class=""archive">" 每页条数 <% var perpage="config.algorithm_generator.per_page" %> 这里我直接获取当前页面是第几页,没有page的话就是第一页 currentpage="url.match(/page\/(.*)\//)" ? url.match( page\ (.*)\ )[1] : last_year="'';" 然后我过滤掉 只是type="=" 'algorithm'的那些文章, 这个type, 在我们新键文章的时候跟title,tag那些写在一起 posts="site.posts.filter((item)" => item.type && 'algorithm') 做一个排序, 按最新的排 posts.data="posts.data.sort((a," b)=">" b.date - a.date) 选择当前页面的文章 posts.slice((currentpage 1) * perpage, ).each(function (post) { cur_year="post.date.year();" if(last_year !="=" cur_year){ <h3><%- %>< h3> } <article <a href=""<%-" url_for(post.path) %>"><%="post.title" a> <span date(post.date, theme.date_format) span> article> }) 分页 if(math.ceil(posts.length perpage) > <nav <%- paginator({ prev_next: false, end_size: 1, mid_size: 2, total: math.ceil(posts.length nav> div>< code></%})%>></%></%>

这里有个坑,我们点击 /algorithm/page/2 的时候会报当前页面存在,我通过 hexo-generator-category 找到类似的解决方案,
我通过文档的生成器写了一个类似的解决方案

  • Chic/script 下添加 algorithm.js, 这里为了搞一个分页出来而已
var pagination = require('hexo-pagination'); // 要安装模块啊
hexo.extend.generator.register('algorithm', function(locals){
    // 这里不能对locals.post 进行更改,一旦发生更改,网站变量 site.posts 的内容也会跟着更改,这里不知道是为什么,我纠结了很久
    let allPost = locals.posts; 

    return pagination('/algorithm', allPost, {
        perPage: this.config.algorithm_generator.per_page, // 在 _config.yml 添加 algorithm_generator: 配置 类似 category_generator
        layout: ['algorithm', 'archive', 'index'], // 如果algorith这个layout,没有就会用 archive, 如此类推
        format: 'page' + '/%d/',
        data: {
            __index: true
        }
    });

});
  • 最后只要修改一下 Chic/layout/_page/archive.ejs 文件跟上面类似第三部就行了, 这里说一下 config ,可以从最外层 _config.yml进行配置

文章搜索

  • 先执行 npm install hexo-generator-search -s, 这个插件是为了生成search.json, 他包含的是文章的基本信息
  • 然后就是写 html 和 css了,我这里使用的是模态框,所以可以根据form 表单提交后唤出modal,然后进行ajax对search.json进行查询.
  • 我们根据关键字对文章content进行匹配,匹配有的加入数组,然后对匹配成功的那些数据进行字符截取,另外对关键字做highlight操作

配置 _config.yml

这里需要配置一下 root 下的 _config.yml, 添加以下代码

# search
search:
  enable: true
  path: search.json
  field: post
  content: true

添加modal

我这里直接写在了Chic/layout/layout.ejs, 我们只需要控制这个modaldisplay属性就好了

html

<!-- Chic/layout.ejs -->
 <div id="u-search">
        <div class="modal">
            <div class="modal-header">
                <div class="container">
                    <form id="u-search-modal-form" class="u-search-modal-form">
                        <button type="submit" class="form-submit-btn">
                            <img src="<%- url_for(theme.searchImg) %>" class="search-btn-img" />
                        </button>
                        <input placeholder="搜索文章。。。" class="form-input" id="modal-form-input">
                    </form>
                    <a class="modal-close">x</a>
                </div>
                <div class="search-loading">
                    <div class="search-loading-bar"></div>
                </div>
            </div>
            <div class="modal-body">
                <!-- ul 格式如下 -->
                <!-- <ul class="modal-results">
                    <li class="result-item">
                        <a class="result-item-detail">
                            <span class="title">页面配置</span>
                            <span class="content">
                                content
                            </span>
                        </a>
                    </li>
                </ul> -->
            </div>
        </div>
        <div class="modal-overlay"></div>
    </div>

我把他放在了Chic/source/css/_lib/search.css

这个要在 Chic\source\css\style.styl 引用,添加代码

@import "_lib/search.css"
点击查看样式,这里是search.css 代码
    #u-search {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        padding: 60px 20px;
        z-index: 1001;
    }


    #u-search .modal {
        position: fixed;
        height: 80%;
        width: 100%;
        max-width: 640px;
        left: 50%;
        top: 0;
        margin: 64px 0px 0px -320px;
        background: #fff;
        z-index: 3;
        border-radius: 4px;
        overflow: hidden;
    }

    #u-search .modal-header {
        position: relative;
        width: 100%;
        height: 64px;
        z-index: 3;
        border-top-left-radius: 4px;
        border-top-right-radius: 4px;
        font-size: 16px;
        box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1);
        background: #fff;
        transition: all 0.28s ease;
        -moz-transition: all 0.28s ease;
        -webkit-transition: all 0.28s ease;
        -o-transition: all 0.28s ease;
    }

    #u-search .modal-header .container{
        display: flex;
        flex-direction: row;
        align-items: center;
        padding: 0px;
    }

    #u-search .modal-header .container .u-search-modal-form {
        display: flex;
        flex-direction: row;
        align-items: center;
        flex: 1;
    }

    #u-search .u-search-modal-form .form-submit-btn {
        width: 50px;
        height: 64px;
        background: none;
        border: none;
        outline: none;
        margin:  0 5px 0 5px ;
    }

    #u-search .u-search-modal-form .form-submit-btn img {
        width: 33px;
        height: 33px;
    }

    #u-search .modal-header .container .u-search-modal-form .form-input {
        flex: 1;
        margin-right: 15px;
        border: none;
        padding: 10px 10px;
        outline: none;
    }


    #u-search .modal-header .modal-close {
        display: block;
        width: 55px;
        height: 64px;
        top: 0;
        right: 0;
        color: #2196f3;
        cursor: pointer;
        text-align: center;
        line-height: 64px;
        vertical-align: middle;
        transition: all 0.28s ease;
        -moz-transition: all 0.28s ease;
        -webkit-transition: all 0.28s ease;
        -o-transition: all 0.28s ease;
        z-index: 2;
        font-size: 22px;
    }

    #u-search .modal-header .search-loading {
        position: absolute;
        bottom: 0;
        left: 0;
        width: 100%;
        height: 2px;
        background: transparent;
        z-index: 1;

    }

    #u-search .modal-header .search-loading .search-loading-bar {
        transition: all 0.28s ease;
        -moz-transition: all 0.28s ease;
        -webkit-transition: all 0.28s ease;
        -o-transition: all 0.28s ease;
        position: relative;
        display: none;
        width: 0%;
        height: 100%;
        background: #2196f3;

    }

    #u-search .modal .modal-body {
        padding: 15px;
        height: calc(100% - 85px);
        overflow: auto;

    }

    #u-search .modal .modal-body::-webkit-scrollbar{
        width: 5px;
        height: 5px;
        /**/
    }
    #u-search .modal .modal-body::-webkit-scrollbar-track{
        background: rgb(239, 239, 239);
        border-radius:2px;
    }
    #u-search .modal .modal-body::-webkit-scrollbar-thumb{
        background: #bfbfbf;
        border-radius:10px;
    }
    #u-search .modal .modal-body::-webkit-scrollbar-thumb:hover{
        background: #333;
    }
    #u-search .modal .modal-body::-webkit-scrollbar-corner{
        background: #179a16;
    }

    #u-search .modal .modal-body .modal-results {
        list-style: none;
        padding-left: 0;
        margin: 0px;
    }

    #u-search .modal .modal-body .modal-results .result-item {
        padding: 15px;
    }

    #u-search .modal .modal-body .modal-results .result-item:hover {
        background: #e8f4fd;
    }

    #u-search .modal .modal-body .modal-results .result-item .result-item-detail {
        display: flex;
        flex-direction: column;
    }

    #u-search .modal .modal-body .modal-results .result-item .result-item-detail .title {
        color: #6e6e6e;
        font-weight: 700;
        font-size: 18px;
        margin-bottom: 10px;
    }

    #u-search .modal .modal-body .modal-results .result-item .result-item-detail .content {
        display: block;
        white-space: inherit;
        word-break: break-all;
        text-overflow: ellipsis;
        font-size: 14px;
        color: rgba(85,85,85,0.65);
        letter-spacing: 1px;
        user-select: none;
    }

    #u-search .search-keyword {
        color: #0c7cd5;
        text-decoration: underline;
        font-weight: bold;
        font-style:normal
    }

    #u-search .modal-body .no-result {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }

    #u-search .modal-overlay {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,0.7);
        z-index: 1;
    }

    @media screen and (max-width: 680px) {
        #u-search {
            padding: 0px;
            display: none;
        }

        #u-search .modal {
            box-shadow: none;
            max-width: none;
            top: 0;
            left: 0;
            margin: 0;
            height: 100%;
            border-radius: 0;
        }
        #u-search .modal-header {
            border-radius: 0;
            padding: 0px;
        }
    } 

    .modal-active {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
    }

    /* 以下是搜索框 */
    .search {
        margin-right: 6px;
        display: flex;
        flex-direction: row;
        align-items: center;
    }

    .search .form-search {
        padding: 10px 8px;
    }

    .search .form-search .input {
        display: block;
        line-height: 1.3;
        color: #555;
        background: #e8e8e8;
        padding: 5px 8px;
        box-shadow: none;
        box-sizing: border-box;
        font-size: 1rem;
        border-radius: 8px;
        border: none;
        outline: none;
    }        

    .search .search-btn {
        width: 22px;
        height: 22px;
        line-height: 22px;
        margin-right: 5px;
    }

    .search .search-btn .search-btn-img {
        height: 100%;
        width: 100%;
    }


    @media screen and (max-width: 479px) {

        .navbar-mobile-right {
            display: flex;
            flex-direction: row;
            align-items: center;
        }

        .search .search-btn {
            cursor: pointer;
        }

        .search .form-search {
            display: none;
        }

        .mobile-search {
            position: absolute;
            top: 0px;
            left: 0px;
            right: 50px;
            padding-left: 15px;
            background: #fff;
            height: 80px;
            display: flex;
            flex-direction: row;
            margin-right: 15px;
        }

        .mobile-search .form-search {
            display: block; 
            flex: 1;
        }

        .mobile-search .input {
            width: 100%;
        } 
    }

增加搜索框

我把该文件放在了 Chic/layout/_partial/search.ejs

<% if(config.search && config.search.enable ) { %>
    <div class="search ">
        <div class="search-btn" onClick="searchToggle()">
            <img src="<%- url_for(theme.searchImg) %>" class="search-btn-img" />
        </div>
        <form class="form-search">
            <input class="input" placeholder="搜索文章" autocomplete="off" id="<%= name %>-search-input"/>
        </form>
    </div>
<% } %>

我们在 Chic\layout\_partial\header.ejs 添加这个搜索框, 要在pc的menu, 和mobile的menu添加,

<% var defaultName = 'pc' %>
<%- partial('_partial/search', { name: defaultName }) %>

// 这里是 mobile 的menu
<div class="navbar-mobile-right">
    <% var type = 'mobile' %>
    <%- partial('_partial/search', { name: type }) %>
    <div class="menu-toggle" onclick="mobileBtn()">&#9776; 目录</div>
</div>

添加搜索框的js, 搜索代码

创建搜索代码

点击查看代码
<script>
    function searchToggle() {
        const width = $(document.body).width()
        if(width > 479) {
            return;
        }
        const search = $('.search');
        const searchForm = $('.form-search')

        if(!search.hasClass("mobile-search")) {
            search.addClass("mobile-search");
        } else {
            search.removeClass("mobile-search");
        } 
    }

    function search(searchInputEl, formEl, flag) {
        const path = "<%= config.root %>" + "<%= config.search.path %>"; // 可以在public 下查看这个search.json
        $(formEl).submit(function(e){
            e.preventDefault();
            let target = null
            if(searchInputEl == null) {
                const screenWidth = $(document.body).width();
                target = screenWidth > 479 ? $('#pc-search-input') : $('#mobile-search-input');
                console.log(target);
            } else {
                target = $(searchInputEl)
            }

            if(!flag && target.val() === '') {
                return ;
            }

            $("#u-search").fadeIn(500, function() {
                $("body > .wrapper").addClass("modal-active");

                $.ajax({
                    url: path,
                    dataType: "json",
                    beforeSend: function (xhr) {
                        $input = target.val();
                        $(".form-input").val($input);
                        const loadingBar = $('.search-loading-bar') 
                        loadingBar.css({
                            width:'100%',
                            display: 'block'
                        });
                    },
                    success: function( datas ) {
                        // console.log(datas);
                        const $resultPanel = $(".modal-body")[0];
                        let str = `<ul class="modal-results">`;
                        var keywords = $(".form-input").val().trim().toLowerCase().split(/[\s\-]+/);
                        $resultPanel.innerHTML = "";
                        let hasResult = false
                        let text = `<div class="no-result">找不到与关键词相关的内容....</div>`;

                        if ($(".form-input").val().trim().length <= 0) {
                            // 没有结果
                            $resultPanel.innerHTML = text;
                            return;
                        }
                        datas.forEach(function (data) {
                            var isMatch = true;
                            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 {
                                        hasResult = true
                                        if (index_content < 0) {
                                            index_content = 0;
                                        }
                                        if (i == 0) {
                                            first_occur = index_content;
                                        }
                                    }
                                });
                            } else {
                                isMatch = false;
                            }
                            // show search results
                            if (isMatch) {
                                str += `<li class='result-item'><a href='${data_url}' class='result-item-detail'> <span class="title">${data_title}</span>`;
                                var content = data.content.trim().replace(/<[^>]+>/g, "");
                                if (first_occur >= 0) {
                                    // cut out 200 characters
                                    var start = first_occur - 40;
                                    var end = first_occur + 160;

                                    if (start < 0) {
                                        start = 0;
                                    }

                                    if (start == 0) {
                                        end = 200;
                                    }

                                    if (end > content.length) {
                                        end = content.length;
                                    }

                                    var match_content = content.substring(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 += `<span class="content"> ${match_content} ...</span></a>`;
                                }
                                str += "</li>";
                            }
                        });
                        str += "</ul>";
                        if(hasResult) {
                            $resultPanel.innerHTML = str;
                        } else {
                            $resultPanel.innerHTML = text;
                        }

                    },
                    complete: function() {
                        setTimeout(() => {
                                const loadingBar = $('.search-loading-bar') 
                                loadingBar.css({
                                    width:'0%',
                                    display: 'none'
                                });
                        }, 300)
                    }
                });
            })

        });
    }

    $(document).ready(function() {
        $('.modal-close').click(function () { 
            $("#u-search").fadeOut();
            $("body > .wrapper").removeClass("modal-active")
        })

        $('.modal-overlay').click(function() {
            $("#u-search").fadeOut();
            $("body > .wrapper").removeClass("modal-active")
        })
        search(null, ".form-search", false)
        search("#u-search-modal-form .form-input", ".u-search-modal-form", true)
    })
</script>

themes\Chic\layout\_partial\head.ejs中添加上面的以下代码,表示启动js

<%# search %>

<% if(config.search && config.search.enable ) { %>
    <%- partial('_plugins/search.ejs') %>
<% } %>

以上就是创建搜索框的全过程了,当然了我上面写的有点乱,可以自行整理一下