除参考butterfly主题文档进行正常配置之外,本博客还参照一些教程进行了魔改(复制)。记录一下,以便后期搞不清时查阅。

添加fps显示

来源:博客魔改日记(3)
参考:博客魔改教程总结(四)

  1. 在主题配置文件_config.butterfly.yml中找到inject项,插入代码。

    1
    2
    3
    4
    5
    6
    head:
    - <link rel="stylesheet" href="/css/fps.css?1">
    # 在.css后面添加 ?1 ,在修改此文件后改成 ?2 ,用户访问网站时,不会使用本地的缓存,而是请求新的内容。没修改的话就不用动
    - <span id="fps"></span> # 帧率检测
    bottom:
    - <script async src="/js/fps.js"></script> # 帧率检测
  2. /source/css文件夹下新建fps.css,插入代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /* 帧率检测 */
    #fps {
    position: fixed;
    /* 指定位置 */
    left: 10px;
    bottom: 10px;
    z-index: 1919810;
    }
    [data-theme="light"] #fps {
    background-color: rgba(255, 255, 255, 0.85);
    backdrop-filter: var(--backdrop-filter);
    padding: 4px;
    border-radius: 4px;
    }
    [data-theme="dark"] #fps {
    background-color: rgba(0, 0, 0, 0.72);
    backdrop-filter: var(--backdrop-filter);
    padding: 4px;
    border-radius: 4px;
    }
  3. /source/js文件夹下新建fps.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
    if (window.localStorage.getItem("fpson") == undefined || window.localStorage.getItem("fpson") == "1") {
    var rAF = function () {
    return (
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    function (callback) {
    window.setTimeout(callback, 1000 / 60);
    }
    );
    }();
    var frame = 0;
    var allFrameCount = 0;
    var lastTime = Date.now();
    var lastFameTime = Date.now();
    var loop = function () {
    var now = Date.now();
    var fs = (now - lastFameTime);
    var fps = Math.round(1000 / fs);

    lastFameTime = now;
    // 不置 0,在动画的开头及结尾记录此值的差值算出 FPS
    allFrameCount++;
    frame++;

    if (now > 1000 + lastTime) {
    var fps = Math.round((frame * 1000) / (now - lastTime));
    if (fps <= 5) {
    var kd = `<span style="color:#bd0000">卡成ppt🤢</span>`
    } else if (fps <= 15) {
    var kd = `<span style="color:red">电竞级帧率😖</span>`
    } else if (fps <= 25) {
    var kd = `<span style="color:orange">有点难受😨</span>`
    } else if (fps < 35) {
    var kd = `<span style="color:#9338e6">不太流畅🙄</span>`
    } else if (fps <= 45) {
    var kd = `<span style="color:#08b7e4">还不错哦🤣</span>`
    } else {
    var kd = `<span style="color:#39c5bb">十分流畅😁</span>`
    }
    document.getElementById("fps").innerHTML = `FPS:${fps} ${kd}`;
    frame = 0;
    lastTime = now;
    };

    rAF(loop);
    }

    loop();
    } else {
    document.getElementById("fps").style = "display:none!important"
    }

文章统计功能

来源:Hexo博客文章统计图

  1. 新建charts页面(已删除,改到about页面去了)

    1
    hexo new page charts
  2. 引入ECharts.js

    有两种引入方式。一种是全局引用,即在_config.butterfly.ymlinject中引入echarts.js文件。

    1
    2
    3
    4
    inject:
    head:
    - <script src="https://npm.elemecdn.com/echarts@4.9.0/dist/echarts.min.js"></script>
    #文章统计

    另一种为页面引入,即在需要引入文章统计图的页面中插入echarts.js文件。例如,可在/source/charts/index.md中添加以下内容。

    1
    <script src="https://npm.elemecdn.com/echarts@4.9.0/dist/echarts.min.js"></script>

    本博客采用第一种方法。

  3. 文章统计代码

    /themes/butterfly/scripts/helpers目录下新建charts.js文件,然后添加下述内容:

    更多属性见官方文档,可根据自行喜好对 ECharts 统计图进行修改。但不好意思,看不懂。只粘贴了现有的。

    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
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    const cheerio = require('cheerio')
    const moment = require('moment')

    hexo.extend.filter.register('after_render:html', function (locals) {
    const $ = cheerio.load(locals)
    const post = $('#posts-chart')
    const tag = $('#tags-chart')
    const category = $('#categories-chart')
    const htmlEncode = false

    if (post.length > 0 || tag.length > 0 || category.length > 0) {
    if (post.length > 0 && $('#postsChart').length === 0) {
    if (post.attr('data-encode') === 'true') htmlEncode = true
    post.after(postsChart(post.attr('data-start')))
    }
    if (tag.length > 0 && $('#tagsChart').length === 0) {
    if (tag.attr('data-encode') === 'true') htmlEncode = true
    tag.after(tagsChart(tag.attr('data-length')))
    }
    if (category.length > 0 && $('#categoriesChart').length === 0) {
    if (category.attr('data-encode') === 'true') htmlEncode = true
    category.after(categoriesChart(category.attr('data-parent')))
    }

    if (htmlEncode) {
    return $.root().html().replace(/&amp;#/g, '&#')
    } else {
    return $.root().html()
    }
    } else {
    return locals
    }
    }, 15)

    function postsChart (startMonth) {
    const startDate = moment(startMonth || '2020-01')
    const endDate = moment()

    const monthMap = new Map()
    const dayTime = 3600 * 24 * 1000
    for (let time = startDate; time <= endDate; time += dayTime) {
    const month = moment(time).format('YYYY-MM')
    if (!monthMap.has(month)) {
    monthMap.set(month, 0)
    }
    }
    hexo.locals.get('posts').forEach(function (post) {
    const month = post.date.format('YYYY-MM')
    if (monthMap.has(month)) {
    monthMap.set(month, monthMap.get(month) + 1)
    }
    })
    const monthArr = JSON.stringify([...monthMap.keys()])
    const monthValueArr = JSON.stringify([...monthMap.values()])

    return `
    <script id="postsChart">
    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
    var postsChart = echarts.init(document.getElementById('posts-chart'), 'light');
    var postsOption = {
    title: {
    text: '文章发布统计图',
    x: 'center',
    textStyle: {
    color: color
    }
    },
    tooltip: {
    trigger: 'axis'
    },
    xAxis: {
    name: '日期',
    type: 'category',
    boundaryGap: false,
    nameTextStyle: {
    color: color
    },
    axisTick: {
    show: false
    },
    axisLabel: {
    show: true,
    color: color
    },
    axisLine: {
    show: true,
    lineStyle: {
    color: color
    }
    },
    data: ${monthArr}
    },
    yAxis: {
    name: '文章篇数',
    type: 'value',
    nameTextStyle: {
    color: color
    },
    splitLine: {
    show: false
    },
    axisTick: {
    show: false
    },
    axisLabel: {
    show: true,
    color: color
    },
    axisLine: {
    show: true,
    lineStyle: {
    color: color
    }
    }
    },
    series: [{
    name: '文章篇数',
    type: 'line',
    smooth: true,
    lineStyle: {
    width: 0
    },
    showSymbol: false,
    itemStyle: {
    opacity: 1,
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(128, 255, 165)'
    },
    {
    offset: 1,
    color: 'rgba(1, 191, 236)'
    }])
    },
    areaStyle: {
    opacity: 1,
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(128, 255, 165)'
    }, {
    offset: 1,
    color: 'rgba(1, 191, 236)'
    }])
    },
    data: ${monthValueArr},
    markLine: {
    data: [{
    name: '平均值',
    type: 'average',
    label: {
    color: color
    }
    }]
    }
    }]
    };
    postsChart.setOption(postsOption);
    window.addEventListener('resize', () => {
    postsChart.resize();
    });
    postsChart.on('click', 'series', (event) => {
    if (event.componentType === 'series') window.location.href = '/archives/' + event.name.replace('-', '/');
    });
    </script>`
    }

    function tagsChart (len) {
    const tagArr = []
    hexo.locals.get('tags').map(function (tag) {
    tagArr.push({ name: tag.name, value: tag.length, path: tag.path })
    })
    tagArr.sort((a, b) => { return b.value - a.value })

    const dataLength = Math.min(tagArr.length, len) || tagArr.length
    const tagNameArr = []
    for (let i = 0; i < dataLength; i++) {
    tagNameArr.push(tagArr[i].name)
    }
    const tagNameArrJson = JSON.stringify(tagNameArr)
    const tagArrJson = JSON.stringify(tagArr)

    return `
    <script id="tagsChart">
    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
    var tagsChart = echarts.init(document.getElementById('tags-chart'), 'light');
    var tagsOption = {
    title: {
    text: 'Top ${dataLength} 标签统计图',
    x: 'center',
    textStyle: {
    color: color
    }
    },
    tooltip: {},
    xAxis: {
    name: '标签',
    type: 'category',
    nameTextStyle: {
    color: color
    },
    axisTick: {
    show: false
    },
    axisLabel: {
    show: true,
    color: color,
    interval: 0
    },
    axisLine: {
    show: true,
    lineStyle: {
    color: color
    }
    },
    data: ${tagNameArrJson}
    },
    yAxis: {
    name: '文章篇数',
    type: 'value',
    splitLine: {
    show: false
    },
    nameTextStyle: {
    color: color
    },
    axisTick: {
    show: false
    },
    axisLabel: {
    show: true,
    color: color
    },
    axisLine: {
    show: true,
    lineStyle: {
    color: color
    }
    }
    },
    series: [{
    name: '文章篇数',
    type: 'bar',
    data: ${tagArrJson},
    itemStyle: {
    borderRadius: [5, 5, 0, 0],
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(128, 255, 165)'
    },
    {
    offset: 1,
    color: 'rgba(1, 191, 236)'
    }])
    },
    emphasis: {
    itemStyle: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(128, 255, 195)'
    },
    {
    offset: 1,
    color: 'rgba(1, 211, 255)'
    }])
    }
    },
    markLine: {
    data: [{
    name: '平均值',
    type: 'average',
    label: {
    color: color
    }
    }]
    }
    }]
    };
    tagsChart.setOption(tagsOption);
    window.addEventListener('resize', () => {
    tagsChart.resize();
    });
    tagsChart.on('click', 'series', (event) => {
    if(event.data.path) window.location.href = '/' + event.data.path;
    });
    </script>`
    }

    function categoriesChart (dataParent) {
    const categoryArr = []
    let categoryParentFlag = false
    hexo.locals.get('categories').map(function (category) {
    if (category.parent) categoryParentFlag = true
    categoryArr.push({
    name: category.name,
    value: category.length,
    path: category.path,
    id: category._id,
    parentId: category.parent || '0'
    })
    })
    categoryParentFlag = categoryParentFlag && dataParent === 'true'
    categoryArr.sort((a, b) => { return b.value - a.value })
    function translateListToTree (data, parent) {
    let tree = []
    let temp
    data.forEach((item, index) => {
    if (data[index].parentId == parent) {
    let obj = data[index];
    temp = translateListToTree(data, data[index].id);
    if (temp.length > 0) {
    obj.children = temp
    }
    if (tree.indexOf())
    tree.push(obj)
    }
    })
    return tree
    }
    const categoryNameJson = JSON.stringify(categoryArr.map(function (category) { return category.name }))
    const categoryArrJson = JSON.stringify(categoryArr)
    const categoryArrParentJson = JSON.stringify(translateListToTree(categoryArr, '0'))

    return `
    <script id="categoriesChart">
    var color = document.documentElement.getAttribute('data-theme') === 'light' ? '#4c4948' : 'rgba(255,255,255,0.7)'
    var categoriesChart = echarts.init(document.getElementById('categories-chart'), 'light');
    var categoryParentFlag = ${categoryParentFlag}
    var categoriesOption = {
    title: {
    text: '文章分类统计图',
    x: 'center',
    textStyle: {
    color: color
    }
    },
    legend: {
    top: 'bottom',
    data: ${categoryNameJson},
    textStyle: {
    color: color
    }
    },
    tooltip: {
    trigger: 'item'
    },
    series: []
    };
    categoriesOption.series.push(
    categoryParentFlag ?
    {
    nodeClick :false,
    name: '文章篇数',
    type: 'sunburst',
    radius: ['15%', '90%'],
    center: ['50%', '55%'],
    sort: 'desc',
    data: ${categoryArrParentJson},
    itemStyle: {
    borderColor: '#fff',
    borderWidth: 2,
    emphasis: {
    focus: 'ancestor',
    shadowBlur: 10,
    shadowOffsetX: 0,
    shadowColor: 'rgba(255, 255, 255, 0.5)'
    }
    }
    }
    :
    {
    name: '文章篇数',
    type: 'pie',
    radius: [30, 80],
    roseType: 'area',
    label: {
    color: color,
    formatter: '{b} : {c} ({d}%)'
    },
    data: ${categoryArrJson},
    itemStyle: {
    emphasis: {
    shadowBlur: 10,
    shadowOffsetX: 0,
    shadowColor: 'rgba(255, 255, 255, 0.5)'
    }
    }
    }
    )
    categoriesChart.setOption(categoriesOption);
    window.addEventListener('resize', () => {
    categoriesChart.resize();
    });
    categoriesChart.on('click', 'series', (event) => {
    if(event.data.path) window.location.href = '/' + event.data.path;
    });
    </script>`
    }
  4. 在建立的charts页面使用统计图(已改到about页面)

    1
    2
    3
    4
    5
    6
    <!-- 文章发布时间统计图 -->
    <div id="posts-chart" data-start="2023-01" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
    <!-- 文章标签统计图 -->
    <div id="tags-chart" data-length="10" style="border-radius: 8px; height: 300px; padding: 10px;"></div>
    <!-- 文章分类统计图 -->
    <div id="categories-chart" data-parent="true" style="border-radius: 8px; height: 300px; padding: 10px;"></div>

    其中:

    • posts-chartdata-start="2023-01"属性表示文章发布时间统计图仅显示2023年1月及以后的文章数据。
    • tags-chartdata-length="10"属性表示仅显示排名前10的标签。
    • categories-chartdata-parent="true"属性表示有子分类时以旭日图显示分类,其他无子分类设置为false不设置该属性设置为其他非true属性情况都以饼状图显示分类。
  5. 在其他页面使用统计图

    本博客暂未引用,详见Hexo博客文章统计图

随机访问一篇文章

来源:随机访问一篇文章的实现

功能主要基于baidusitemap插件实现。

  1. 在主题配置文件_config.butterfly.yml中找到inject项,插入代码。

    1
    2
    3
    inject:
    bottom:
    - <script src="/js/randompost.js"></script> # 随机访问一篇文章
  2. /source/js文件夹下新建randompost.js,插入代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function randomPost() {
    fetch('/baidusitemap.xml').then(res => res.text()).then(str => (new window.DOMParser()).parseFromString(str, "text/xml")).then(data => {
    let ls = data.querySelectorAll('url loc');
    while (true) {
    let url = ls[Math.floor(Math.random() * ls.length)].innerHTML;
    if (location.href == url) continue;
    location.href = url;
    return;
    }
    })
    }
  3. 在主题配置文件_config.butterfly.yml中增加导航按钮即可。

    1
    2
    menu:
    随机访问: javascript:randomPost(); || fa-solid fa-shuffle

网站标题提示

来源:博客魔改教程总结(五)

  1. 在主题配置文件_config.butterfly.yml中找到inject项,插入代码。

    1
    2
    3
    inject:
    bottom:
    - <script async src="/js/title.js"></script> #网站标题提示
  2. /source/js文件夹下新建title.js,插入代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //动态标题
    var OriginTitile = document.title;
    var titleTime;
    document.addEventListener('visibilitychange', function () {
    if (document.hidden) {
    //离开当前页面时标签显示内容
    document.title = '爱你😘~别走';
    clearTimeout(titleTime);
    } else {
    //返回当前页面时标签显示内容
    document.title = '终于等到你/(ㄒoㄒ)/~~~';
    //四秒后变回正常标题
    titleTime = setTimeout(function () {
    document.title = OriginTitile;
    }, 4000);
    }
    });

加载动画

来源:Heo同款loading动画

  1. 打开/themes/butterfly/layout/includes/loading/fullpage-loading.pug文件。

    原代码为:

    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
    #loading-box
    .loading-left-bg
    .loading-right-bg
    .spinner-box
    .configure-border-1
    .configure-core
    .configure-border-2
    .configure-core
    .loading-word= _p('loading')

    script.
    const preloader = {
    endLoading: () => {
    document.body.style.overflow = 'auto';
    document.getElementById('loading-box').classList.add("loaded")
    },
    initLoading: () => {
    document.body.style.overflow = '';
    document.getElementById('loading-box').classList.remove("loaded")

    }
    }
    window.addEventListener('load',()=> { preloader.endLoading() })

    if (!{theme.pjax && theme.pjax.enable}) {
    document.addEventListener('pjax:send', () => { preloader.initLoading() })
    document.addEventListener('pjax:complete', () => { preloader.endLoading() })
    }

    删去,改为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #loading-box(onclick='document.getElementById("loading-box").classList.add("loaded")')
    .loading-bg
    div.loading-img
    .loading-image-dot

    script.
    const preloader = {
    endLoading: () => {
    document.body.style.overflow = 'auto';
    document.getElementById('loading-box').classList.add("loaded")
    },
    initLoading: () => {
    document.body.style.overflow = '';
    document.getElementById('loading-box').classList.remove("loaded")

    }
    }
    window.addEventListener('load',()=> { preloader.endLoading() })

    if (!{theme.pjax && theme.pjax.enable}) {
    document.addEventListener('pjax:send', () => { preloader.initLoading() })
    document.addEventListener('pjax:complete', () => { preloader.endLoading() })
    }
  2. 打开/themes/butterfly/layout/includes/loading/index.pug文件。

    原代码为:

    1
    2
    3
    4
    if theme.preloader.source === 1
    include ./fullpage-loading.pug
    else
    include ./pace.pug

    删去,改为:

    1
    2
    3
    4
    5
    6
    7
    if theme.preloader.source === 1
    include ./fullpage-loading.pug
    else if theme.preloader.source === 2
    include ./pace.pug
    else
    include ./fullpage-loading.pug
    include ./pace.pug
  3. /source/css中新建progress_bar.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
    .pace {
    -webkit-pointer-events: none;
    pointer-events: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
    z-index: 2000;
    position: fixed;
    margin: auto;
    top: 10px;
    left: 0;
    right: 0;
    height: 8px;
    border-radius: 8px;
    width: 4rem;
    background: #eaecf2;
    border: 1px #e3e8f7;
    overflow: hidden;
    }

    .pace-inactive .pace-progress {
    opacity: 0;
    transition: 0.3s ease-in;
    }

    .pace .pace-progress {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    -ms-box-sizing: border-box;
    -o-box-sizing: border-box;
    box-sizing: border-box;
    -webkit-transform: translate3d(0, 0, 0);
    -moz-transform: translate3d(0, 0, 0);
    -ms-transform: translate3d(0, 0, 0);
    -o-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
    max-width: 200px;
    position: absolute;
    z-index: 2000;
    display: block;
    top: 0;
    right: 100%;
    height: 100%;
    width: 100%;
    background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
    animation: gradient 1.5s ease infinite;
    background-size: 200%;
    }

    .pace.pace-inactive {
    opacity: 0;
    transition: 0.3s;
    top: -8px;
    }
    @keyframes gradient {
    0% {
    background-position: 0% 50%;
    }
    50% {
    background-position: 100% 50%;
    }
    100% {
    background-position: 0% 50%;
    }
    }
  4. 打开/themes/butterfly/source/css/_layout/loading.styl文件。

    原代码为:

    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
    if hexo-config('preloader.enable') && hexo-config('preloader.source') == 1
    .loading-bg
    position: fixed
    z-index: 1000
    width: 50%
    height: 100%
    background-color: var(--preloader-bg)

    #loading-box
    .loading-left-bg
    @extend .loading-bg

    .loading-right-bg
    @extend .loading-bg
    right: 0

    .spinner-box
    position: fixed
    z-index: 1001
    display: flex
    justify-content: center
    align-items: center
    width: 100%
    height: 100vh

    .configure-border-1
    position: absolute
    padding: 3px
    width: 115px
    height: 115px
    background: #ffab91
    animation: configure-clockwise 3s ease-in-out 0s infinite alternate

    .configure-border-2
    left: -115px
    padding: 3px
    width: 115px
    height: 115px
    background: rgb(63, 249, 220)
    transform: rotate(45deg)
    animation: configure-xclockwise 3s ease-in-out 0s infinite alternate

    .loading-word
    position: absolute
    color: var(--preloader-color)
    font-size: 16px

    .configure-core
    width: 100%
    height: 100%
    background-color: var(--preloader-bg)

    &.loaded
    .loading-left-bg
    transition: all .5s
    transform: translate(-100%, 0)

    .loading-right-bg
    transition: all .5s
    transform: translate(100%, 0)

    .spinner-box
    display: none

    @keyframes configure-clockwise
    0%
    transform: rotate(0)

    25%
    transform: rotate(90deg)

    50%
    transform: rotate(180deg)

    75%
    transform: rotate(270deg)

    100%
    transform: rotate(360deg)

    @keyframes configure-xclockwise
    0%
    transform: rotate(45deg)

    25%
    transform: rotate(-45deg)

    50%
    transform: rotate(-135deg)

    75%
    transform: rotate(-225deg)

    100%
    transform: rotate(-315deg)

    删去,改为以下代码。代码中背景颜色修改。

    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
    if hexo-config('preloader')
    .loading-bg
    display: flex;
    width: 100%;
    height: 100%;
    position: fixed;
    background: #f5f5f5;
    z-index: 1001;
    opacity: 1;
    transition: .3s;

    #loading-box
    .loading-img
    width: 100px;
    height: 100px;
    border-radius: 50%;
    margin: auto;
    border: 4px solid #f0f0f2;
    animation-duration: .3s;
    animation-name: loadingAction;
    animation-iteration-count: infinite;
    animation-direction: alternate;
    .loading-image-dot
    width: 30px;
    height: 30px;
    background: #39ce42;
    position: absolute;
    border-radius: 50%;
    border: 6px solid #fff;
    top: 50%;
    left: 50%;
    transform: translate(18px, 24px);
    &.loaded
    .loading-bg
    opacity: 0;
    z-index: -1000;

    @keyframes loadingAction
    0% {
    opacity: 1;
    }

    100% {
    opacity: .4;
    }

  5. /source/css/custom.css中新增代码,其中background中的url用于设置加载图片。

    1
    2
    3
    4
    5
    /*加载动画*/
    .loading-img {
    background: url(https://img.heyjian.cn/1.jpg) no-repeat center center;
    background-size: cover;
    }
  6. 在主题配置文件_config.butterfly.yml中找到inject项,插入代码。

    1
    2
    3
    inject:
    head:
    - <link rel="stylesheet" href="/css/custom.css?1">
  7. 在主题配置文件_config.butterfly.yml中找到preloader项。

    1
    2
    3
    4
    5
    6
    7
    8
    preloader:
    enable: true
    # source
    # 1. fullpage-loading
    # 2. pace (progress bar)
    source: 3
    # pace theme (see https://codebyzach.github.io/pace/)
    pace_css_url: /css/progress_bar.css

    其中source: 1为满屏加载但加载图片上方无胶囊动画,source: 2为有胶囊但无满屏动画,source: 3为两者皆有。

首页文章置顶滚动轮播

来源:Swiper Bar

  1. 在本地站点根目录执行下述指令,安装插件。

    1
    npm install hexo-butterfly-swiper --save
  2. 在站点配置文件_config.yml中添加下述代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    swiper:
    enable: true # 开关
    priority: 5 #过滤器优先权,数值越小,执行越早,默认为10
    enable_page: / # 填写想要应用的页面的相对路径(即路由地址),如根目录就填’/‘,分类页面就填’/categories/‘。若要应用于所有页面,就填’all’,默认为all
    timemode: date #date/updated时间显示,date为显示创建日期,updated为显示更新日期,默认为date
    layout: # 挂载容器类型
    type: id #挂载容器类型,填写id或class,不填则默认为id
    name: recent-posts #挂载容器名称
    index: 0 #填0或正整数,前提是layout.type为class,因为同一页面可能有多个class,此项用来确认究竟排在第几个顺位
    default_descr: 怎么可能没有描述呢!!! #默认文章描述
    swiper_css: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css #swiper css依赖
    swiper_js: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js #swiper js依赖
    custom_css: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiperstyle.css # 适配主题样式补丁
    custom_js: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper_init.js # swiper初始化方法
  3. 使用方法

    在文章front_matter中添加swiper_index: 1即可,其中swiper_index:后的数字为非负整数,代表置顶轮播图顺序,数字越大越靠前。

右下角增加分享分页按钮以及直达底部按钮

来源:Butterfly右下角悬浮菜单栏魔改指南

  1. 打开/themes/butterfly/layout/includes/rightside.pug文件,在一众when下面添加一个when

    1
    2
    3
    when 'share'
    button.share(type="button" title='分享链接' onclick="share()")
    i.fas.fa-share-nodes
  2. 在此文档下面的·#rightside·数组中添加share函数。

    原代码:

    1
    2
    3
    4
    #rightside
    - const { enable, hide, show } = theme.rightside_item_order
    - const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside']
    - const showArray = enable ? show && show.split(',') : ['toc','chat','comment']

    添加share函数后的代码:

    1
    2
    3
    4
    #rightside
    - const { enable, hide, show } = theme.rightside_item_order
    - const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside']
    - const showArray = enable ? show && show.split(',') : ['toc','share','chat','comment']

    其中:在hideArray里面添加会在点击齿轮按钮之后显示,在showArray里面添加按钮会直接显示。

    虽然,在主题配置文档rightside_item_order中可对右下角按钮进行排序,但由于添加了自定义按钮,为了方便,直接更改此处顺序就可以对其进行排序。

  3. 在主题配置文档的inject中的bottom项里引入下述代码,其中,该处代码必须要放在自定义分享功能js文件的前面。

    1
    2
    3
    bottom:
    - <script src="https://cdn.bootcdn.net/ajax/libs/clipboard.js/2.0.11/clipboard.min.js"></script> #分享本页引入外部js,一定要在该自定义功能js的上面
    - <script src="/js/custom.js"></script> #自定义分享功能js存放处
  4. /source/js/custom.js中插入自定义分享本页js。

    1
    2
    3
    4
    5
    6
    // 分享本页
    function share() {
    let url = window.location.origin + window.location.pathname
    new ClipboardJS(".share", { text: function() { return '标题:' + document.title + '\n链接:' + url } }); #此处可以更改,例如只复制链接,但不想改。
    btf.snackbarShow("本页面信息已成功复制至剪贴板!小伙子,尽情分享去吧o(* ̄▽ ̄*)ブ")
    }
  5. 直达底部功能在/themes/butterfly/layout/includes/rightside.pug文件最后添加代码。

    1
    2
    button#go-down(type="button" title="直达底部" onclick="btf.scrollToDest(document.body.scrollHeight, 500)")
    i.fas.fa-arrow-down

复制、粘贴、F12弹窗提醒

f12Butterfly右下角悬浮菜单栏魔改指南那扒来的。

​ 由于之前已经引用了/source/js/custom.js,因此,只需要在/source/js/custom.js中插入下述代码。

1
2
3
4
//f12提醒、复制提醒、粘贴提醒
window.onkeydown=e=>{123===e.keyCode&&btf.snackbarShow("开发者模式已打开,请记得遵循GPL协议哟(●'◡'●)")}
document.body.addEventListener("copy",(e=>{"TEXTAREA"==e.target.tagName&&""==e.target.className||btf.snackbarShow("滴\^o^/复制成功~")}))
document.body.addEventListener("paste",(e=>{btf.snackbarShow("滴\^o^/粘贴成功~")}))

控制台样式自定义

来源:博客魔改教程总结(四)

  1. 在已经建立并在主题配置文件中引用的/source/js/custom.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
    //控制台样式自定义
    var now1 = new Date();
    function createtime1() {
    var grt = new Date("01/14/2023 22:00:00"); //此处修改你的建站时间或者网站上线时间
    now1.setTime(now1.getTime() + 250);
    var days = (now1 - grt) / 1000 / 60 / 60 / 24;
    var dnum = Math.floor(days);

    var ascll = [
    `欢迎来到jianerssr的个人小屋`,
    `---便是仙禁春深,御炉香袅,临轩亲试。对天颜咫尺,定然魁甲登高第。`,
    `
    ██╗██╗ █████╗ ███╗ ██╗███████╗██████╗ ███████╗███████╗██████╗
    ██║██║██╔══██╗████╗ ██║██╔════╝██╔══██╗██╔════╝██╔════╝██╔══██╗
    ██║██║███████║██╔██╗ ██║█████╗ ██████╔╝███████╗███████╗██████╔╝
    ██ ██║██║██╔══██║██║╚██╗██║██╔══╝ ██╔══██╗╚════██║╚════██║██╔══██╗
    ╚█████╔╝██║██║ ██║██║ ╚████║███████╗██║ ██║███████║███████║██║ ██║
    ╚════╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝
    `,
    "jianerssr的个人小屋已经运行",
    dnum,
    "天啦!",
    "©2023 By jianerssr",
    ];

    setTimeout(
    console.log.bind(
    console,
    `\n%c${ascll[0]} %c ${ascll[1]} %c ${ascll[2]} %c${ascll[3]}%c ${ascll[4]}%c ${ascll[5]}\n\n%c ${ascll[6]}\n`,
    "color:#3366ff",
    "",
    "color:#3366ff",
    "color:#3366ff",
    "",
    "color:#3366ff",
    ""
    )
    );
    }
    createtime1();
    // 重写console方法
    console.log = function () { };
    console.error = function () { };
    console.warn = function () { };
  2. F12控制台处可看到效果。

文章顶部添加波浪效果

来源:butterfly文章顶部添加波浪效果

  1. 打开/themes/butterfly/layout/includes/header/index.pug文件。

    找到35include ./post-info.pug,在其下添加下述代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if is_post() #原有
    include ./post-info.pug #原有
    section.main-hero-waves-area.waves-area
    svg.waves-svg(xmlns='http://www.w3.org/2000/svg', xlink='http://www.w3.org/1999/xlink', viewBox='0 24 150 28', preserveAspectRatio='none', shape-rendering='auto')
    defs
    path#gentle-wave(d='M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z')
    g.parallax
    use(href='#gentle-wave', x='48', y='0')
    use(href='#gentle-wave', x='48', y='3')
    use(href='#gentle-wave', x='48', y='5')
    use(href='#gentle-wave', x='48', y='7')
    else if is_home() #原有
  2. /source/css/custom.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
    /* 波浪css */
    .main-hero-waves-area {
    width: 100%;
    position: absolute;
    left: 0;
    bottom: -11px;
    z-index: 5;
    }
    .waves-area .waves-svg {
    width: 100%;
    height: 5rem;
    }
    /* Animation */

    .parallax > use {
    animation: move-forever 25s cubic-bezier(0.55, 0.5, 0.45, 0.5) infinite;
    }
    .parallax > use:nth-child(1) {
    animation-delay: -2s;
    animation-duration: 7s;
    fill: #f7f9febd;
    }
    .parallax > use:nth-child(2) {
    animation-delay: -3s;
    animation-duration: 10s;
    fill: #f7f9fe82;
    }
    .parallax > use:nth-child(3) {
    animation-delay: -4s;
    animation-duration: 13s;
    fill: #f7f9fe36;
    }
    .parallax > use:nth-child(4) {
    animation-delay: -5s;
    animation-duration: 20s;
    fill: #f7f9fe;
    }
    /* 黑色模式背景 */
    [data-theme="dark"] .parallax > use:nth-child(1) {
    animation-delay: -2s;
    animation-duration: 7s;
    fill: #18171dc8;
    }
    [data-theme="dark"] .parallax > use:nth-child(2) {
    animation-delay: -3s;
    animation-duration: 10s;
    fill: #18171d80;
    }
    [data-theme="dark"] .parallax > use:nth-child(3) {
    animation-delay: -4s;
    animation-duration: 13s;
    fill: #18171d3e;
    }
    [data-theme="dark"] .parallax > use:nth-child(4) {
    animation-delay: -5s;
    animation-duration: 20s;
    fill: #18171d;
    }

    @keyframes move-forever {
    0% {
    transform: translate3d(-90px, 0, 0);
    }
    100% {
    transform: translate3d(85px, 0, 0);
    }
    }
    /*Shrinking for mobile*/
    @media (max-width: 768px) {
    .waves-area .waves-svg {
    height: 40px;
    min-height: 40px;
    }
    }