点击查看更新记录

更新记录

2023-01-07:调整自动播放参数

  1. 洪哥建议将自动播放参数改为悬停是停止自动播放,离开后继续播放。

2023-01-07:调整swiper.js引入位置

  1. 将swiper.js换到全局引入
  2. 之后的页脚、顶栏、友链设计方案都用可能用到swiper实现轮播效果。

2023-01-05:修复首页轮播图样式丢失

  1. 修复swiper样式丢失问题
  2. 灯下黑。之前靠着页脚引入的一份swiper的css,一直没发现教程里没有教怎么引入依赖。
  3. 现已补全在第十步。

2023-01-03:内测版

  1. 沿用源计划-方舟:首页卡片的配色方案,建议一起使用。
  2. 首页轮播图采用液晶屏风格设计
  3. 窄屏样式已适配
点击查看参考教程
参考方向教程原贴
fontawesome图标文档fontawesome
Flex布局参数解释Flex 布局教程:语法篇 - 阮一峰的网络日志
Transition属性实现平滑过渡动画CSS3实现伪类hover离开时平滑过渡效果示例
CSS伪类实现三角形绘制纯CSS 实现绘制各种三角形(各种角度) - saucxs - 博客园
使用clip-path实现多边形剪裁。不可思议的CSS之clip-path
站内教程:iconfont引入教程Hexo引入阿里矢量图标库
swiper中文文档,查看初始化参数Swiper中文网

预览效果

点击查看预览效果

轮播图预览效果

魔改步骤

  1. 本篇讨论的轮播图的配置项可能与hexo-butterfly-swiper插件的配置项有冲突,如果您曾经安装过该插件或者该插件的衍生插件(例如anzhiyu、anzhiyupro、allbs、ihao、lyx、btmuli,一查才知道已经有这么多亚种了吗)。请确保您已经卸载了它们。
    1
    npm uninstall hexo-butterfly-swiper --save
  2. 本篇沿用了源计划-方舟:首页卡片中用到的部分方案,为保证样式完整,且避免报错,推荐先完成首页卡片的魔改后再考虑使用本方案。
  3. 本篇需要用到iconfont作为卡片底部的装饰性图标。请先完成前置教程:Hexo引入阿里矢量图标库,务必确保symbol方案能够使用后再进行下方内容。
  4. 新建[Blogroot]\themes\butterfly\scripts\helpers\ark_icon.js,这个js的作用是返回一个随机的图标值,逢年过节的还能换成喜庆点的图标,注意以下icon[]内部的图标均为我个人图标库内的图标名称。请务必记得替换成你自己的图标。且这是个内部函数,必须保证在scripts目录下,不要自作聪明建在别的目录还到inject配置项去引入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    hexo.extend.helper.register('arkIcon', function () {
    var icon = [
    '#icon-fukong',
    '#icon-fan',
    '#icon-partial-discharge',
    '#icon-menu-zizhanbaowei',
    '#icon-YunTai-unfold',
    '#icon-camera-GOTO_PRESET',
    '#icon-d3',
    '#icon-copy',
    '#icon-config'
    ]
    var index = Math.floor(Math.random()*icon.length);
    return icon[index]
    });
  5. 新建[Blogroot]\themes\butterfly\scripts\helpers\swiperbar.js,这个脚本的作用是返回在front-matter设置了swiper_index数值的文件。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    'use strict'

    hexo.extend.helper.register('swiper_list', function (locals) {
    var posts_list = hexo.locals.get('posts').data;
    var swiper_list = []
    // 若文章的front_matter内设置了index和描述,则将其放到swiper_list内
    for (var item of posts_list) {
    if (item.swiper_index) {
    swiper_list.push(item)
    }
    }
    // 对swiper_list进行处理,使其按照index大小进行排序
    function sortNumber(a, b) {
    return a.swiper_index - b.swiper_index
    }
    swiper_list = swiper_list.sort(sortNumber);
    // 排序反转,使得数字越大越靠前
    swiper_list = swiper_list.reverse();
    return swiper_list;
    })
  6. 新建[Blogroot]\themes\butterfly\layout\includes\custom\ark_swiperBar.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
    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
    .recent-post-item#swiperBar
    #ark-swiper-container
    .swiper-wrapper.ark-swiper-wrapper
    //- 文章卡片
    if theme.pjax.enable
    each item in swiper_list()
    //- 内容版块
    .swiper-slide.ark-swiper-item
    //- 封面
    .ark-swiper-item-cover
    img.article-cover(src=item.cover title='' onerror=`this.src=` + theme.swiperBar.error_img + `; this.onerror = null;`)
    //- 时间
    if (theme.swiperBar.timemode === 'updated' )
    .ark-swiper-item-time
    span='updated:'
    span= item.updated.format('YYYY-MM-DD')
    else
    .ark-swiper-item-time
    span='published:'
    span= item.date.format('YYYY-MM-DD')
    //- 标题和描述
    .ark-swiper-item-info
    a.ark-swiper-item-title(onclick=`pjax.loadUrl("` + item.path + `");` title='')
    .ark-swiper-item-title-link= item.title
    a.ark-swiper-item-description(onclick=`pjax.loadUrl("` + item.path + `");` title='')
    .ark-swiper-item-description-text!= item.description ? item.description : theme.swiperBar.default_descr
    //- 装饰图标盲盒
    svg.icon.ark-swiper-item-decoration(aria-hidden="true")
    use(xlink:href=arkIcon())
    else
    each item in swiper_list()
    //- 内容版块
    .swiper-slide.ark-swiper-item
    //- 封面
    a.ark-swiper-item-cover(href=item.path title='')
    img.article-cover(src=item.cover title='' onerror=`this.src=` + theme.swiperBar.error_img + `; this.onerror = null;`)
    //- 时间
    if (theme.swiperBar.timemode === 'updated' )
    .ark-swiper-item-time
    span='updated:'
    span= item.updated.format('YYYY-MM-DD')
    else
    .ark-swiper-item-time
    span='updated:'
    span= item.date.format('YYYY-MM-DD')
    //- 标题和描述
    .ark-swiper-item-info
    a.ark-swiper-item-title(href=item.path title='')
    .ark-swiper-item-title-link= item.title
    a.ark-swiper-item-description(href=item.path title='')
    .ark-swiper-item-description-text!= item.description ? item.description : theme.swiperBar.default_descr
    //- 装饰图标盲盒
    svg.icon.ark-swiper-item-decoration(aria-hidden="true")
    use(xlink:href=arkIcon())
    .swiper-pagination.ark-swiper-pagination
  7. [Blogroot]\themes\butterfly\layout\index.pug中引入轮播图组件,最好不要问我为啥你的文件和我的不一样。这个文件以后会经常见面的。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
      extends includes/layout.pug

    block content
    include ./includes/mixins/post-ui.pug
    #recent-posts.recent-posts
    + if theme.swiperBar.enable
    + !=partial('includes/custom/ark_swiperBar', {}, {cache: true})
    if theme.categoryBar.enable
    !=partial('includes/custom/categoryBar', {}, {cache: true})
    +postUI
    include includes/pagination.pug
  8. 新建[Blogroot]\themes\butterfly\source\css\_layout\ark_swiper_bar.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
    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
    .recent-post-item
    &#swiperBar
    width: 100%;
    position: relative
    #ark-swiper-container
    width: 100%;
    height: 200px;
    overflow: hidden;
    position: relative;
    border-radius: 15px;
    .ark-swiper-wrapper
    width: 100%;
    height: 200px;
    display: flex;
    flex-direction: row;
    .ark-swiper-item
    position: relative
    width: 100%;
    height: 200px;
    display: flex;
    flex-direction: row;
    overflow: hidden;
    border-radius: 15px;
    box-shadow: 0 0 3px inset var(--ark-post-item-box-shadow);
    .ark-swiper-item-cover
    height: 100%;
    display: flex;
    position: absolute;
    top: 0
    left: 0
    align-items: center;
    justify-content: center;
    overflow: hidden;
    z-index: 0
    img
    object-fit: cover;
    width: 100%;
    height: 100%
    z-index: 1;
    opacity: 0.8
    .ark-swiper-item-time
    width: 350px;
    color: var(--ark-post-item-font-color);
    font-size: 25px;
    text-shadow: 2px 2px 3px black;
    background: rgba(153, 54, 44,0.8);
    font-family: 'UnidreamLED';
    display: flex;
    position: absolute;
    height: 30px;
    top: calc(50% - 15px);
    left: calc(50% - 175px);
    align-items: center;
    justify-content: center;
    z-index: 2;
    span
    margin: 0 3px
    .ark-swiper-item-info
    flex-direction: column;
    background: var(--ark-post-item-screen)
    height: 100%;
    display: flex;
    position: absolute
    top: 0
    right: 0
    align-items: center;
    justify-content: space-between;
    flex-direction: column;
    overflow: hidden;
    z-index: 0;
    a.ark-swiper-item-title
    border-style: dotted;
    border-width: 0 0 3px 0;
    width: 100%;
    height: 80px;
    color: var(--ark-post-item-font-color);
    font-family: 'TaikoMagic';
    border-color: rgba(153, 54, 44,0.8);
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
    .ark-swiper-item-title-link
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
    ark_post_item_link_hover()
    .ark-swiper-item-description
    color: var(--ark-post-item-font-color);
    display: flex;
    text-align: start;
    height: 130px;
    align-items: center;
    .ark-swiper-item-description-text
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
    .ark-swiper-item-decoration
    width: 150px;
    height: 150px;
    opacity: 0.3;
    position: absolute;
    top: calc(50% - 75px);
    left: calc(50% - 75px);
    z-index: -1
    .ark-swiper-pagination
    bottom: 5px;
    left: 0;
    right: 0;
    margin: 0 auto;
    //宽屏样式
    @media screen and (min-width:768px)
    .recent-post-item
    &#swiperBar
    height: 260px;
    padding: 30px 30px
    &::before
    content: ""
    display: block
    height: 100%
    width: 100%
    position: absolute
    background: var(--ark-post-item-border)
    z-index: 3
    left: 0
    top: 0
    clip-path: polygon(50% 50%, 50% 0, calc(50% - 10px) 0, 30% 0, calc(30% - 10px) 10px, 10px 15px, 0 25px, 25px 25px, 30px 20px, calc(30% + 10px) 20px, calc(30% + 20px) 10px, calc(50% - 30px) 10px, calc(50% - 10px) 0, 50% 0, 50% 50%, 50% 0, calc(50% + 10px) 0, 70% 0, calc(70% + 10px) 10px, calc(100% - 10px) 15px, 100% 25px, calc(100% - 25px) 25px, calc(100% - 30px) 20px, calc(70% - 10px) 20px, calc(70% - 20px) 10px, calc(50% + 30px) 10px, calc(50% + 10px) 0, 50% 0, 50% 50%,50% 100%, calc(50% - 10px) 100%, 30% 100%, calc(30% - 10px) calc(100% - 10px), 10px calc(100% - 15px), 0 calc(100% - 25px), 25px calc(100% - 25px), 30px calc(100% - 20px), calc(30% + 10px) calc(100% - 20px), calc(30% + 20px) calc(100% - 10px), calc(50% - 30px) calc(100% - 10px), calc(50% - 10px) 100%, 50% 100%, 50% 50%, 50% 100%, calc(50% + 10px) 100%, 70% 100%, calc(70% + 10px) calc(100% - 10px), calc(100% - 10px) calc(100% - 15px), 100% calc(100% - 25px), calc(100% - 25px) calc(100% - 25px), calc(100% - 30px) calc(100% - 20px), calc(70% - 10px) calc(100% - 20px), calc(70% - 20px) calc(100% - 10px), calc(50% + 30px) calc(100% - 10px), calc(50% + 10px) 100%, 50% 100%, 50% 50%)
    &::after
    content: ""
    display: block
    height: 100%
    width: 100%
    position: absolute
    background: linear-gradient(to right,var(--ark-post-item-screen) 30px,#e9e9e9,#e9e9e9 60px,transparent),linear-gradient(to left,var(--ark-post-item-screen) 30px,#e9e9e9,#e9e9e9 60px,transparent)
    z-index: 3
    left: 0
    top: 0
    clip-path: polygon(50% 50%, 45px 50%, 45px 45px, 60px 45px, 65px 40px, 40px 40px, 40px calc(50% - 10px), 45px calc(50% - 10px), 45px 50%, 25px 50%, 25px calc(50% - 15px), 10px calc(50% - 15px), 10px calc(50% - 10px), 25px calc(50% - 10px), 25px calc(50% - 2.5px), 0 calc(50% - 2.5px), 0 50%, 50% 50%, 45px 50%, 45px calc(100% - 45px), 60px calc(100% - 45px), 65px calc(100% - 40px), 40px calc(100% - 40px), 40px calc(50% + 10px), 45px calc(50% + 10px), 45px 50%, 25px 50%, 25px calc(50% + 15px), 10px calc(50% + 15px), 10px calc(50% + 10px), 25px calc(50% + 10px), 25px calc(50% + 2.5px), 0 calc(50% + 2.5px), 0 50%, 50% 50%, calc(100% - 45px) 50%, calc(100% - 45px) 45px, calc(100% - 60px) 45px, calc(100% - 65px) 40px, calc(100% - 40px) 40px, calc(100% - 40px) calc(50% - 10px), calc(100% - 45px) calc(50% - 10px), calc(100% - 45px) 50%, calc(100% - 25px) 50%, calc(100% - 25px) calc(50% - 15px), calc(100% - 10px) calc(50% - 15px), calc(100% - 10px) calc(50% - 10px), calc(100% - 25px) calc(50% - 10px), calc(100% - 25px) calc(50% - 2.5px), 100% calc(50% - 2.5px), 100% 50%, 50% 50%, calc(100% - 45px) 50%, calc(100% - 45px) calc(100% - 45px), calc(100% - 60px) calc(100% - 45px), calc(100% - 65px) calc(100% - 40px), calc(100% - 40px) calc(100% - 40px), calc(100% - 40px) calc(50% + 10px), calc(100% - 45px) calc(50% + 10px), calc(100% - 45px) 50%, calc(100% - 25px) 50%, calc(100% - 25px) calc(50% + 15px), calc(100% - 10px) calc(50% + 15px), calc(100% - 10px) calc(50% + 10px), calc(100% - 25px) calc(50% + 10px), calc(100% - 25px) calc(50% + 2.5px), 100% calc(50% + 2.5px), 100% 50%, 50% 50%)
    #ark-swiper-container
    .ark-swiper-wrapper
    .ark-swiper-item
    .ark-swiper-item-cover
    width: calc(50% + 100px);
    clip-path: polygon(0 0,100% 0,calc(100% - 200px) 100%,0 100%);
    .ark-swiper-item-time
    transform: rotateZ(-45deg);
    .ark-swiper-item-info
    width: calc(50% + 100px);
    clip-path: polygon(100% 0,100% 100%,0 100%,200px 0 );
    padding: 0 0 0 140px;
    a.ark-swiper-item-title
    padding: 15px 20px 0 60px;
    font-size: 20px;
    line-height: 25px;
    .ark-swiper-item-title-link
    -webkit-line-clamp: 2
    .ark-swiper-item-description
    padding: 10px 20px 10px 10px;
    font-size: 16px;
    line-height: 30px;
    .ark-swiper-item-description-text
    -webkit-line-clamp: 3

    @media screen and (max-width:768px)
    .recent-post-item
    &#swiperBar
    height: 200px;
    padding: 0px 0px
    #ark-swiper-container
    .ark-swiper-wrapper
    .ark-swiper-item
    .ark-swiper-item-cover
    width: calc(50% + 50px);
    clip-path: polygon(0 0,100% 0,calc(100% - 100px) 100%,0 100%);
    .ark-swiper-item-time
    transform: rotateZ(-60deg);
    .ark-swiper-item-info
    width: calc(50% + 50px);
    clip-path: polygon(100% 0,100% 100%,0 100%,100px 0 );
    padding: 0 0 0 60px;
    a.ark-swiper-item-title
    padding: 10px 16px 0 45px;
    font-size: 16px;
    line-height: 20px;
    .ark-swiper-item-title-link
    -webkit-line-clamp: 2
    .ark-swiper-item-description
    padding: 0px 15px 10px 5px;
    font-size: 14px;
    line-height: 20px;
    .ark-swiper-item-description-text
    -webkit-line-clamp: 4
  9. 还需要新建[Blogroot]\themes\butterfly\source\js\custom\swiper_init.js,作为swiper的初始化方案。这里另外新建文件而不是直接在pug里插入script标签是为了实现defer异步。毕竟swiper的js有144KB。更多参数可以自行查看Swiper中文网来添加。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //首页顶部推荐文章轮播图
    var ark_swiper = new Swiper("#ark-swiper-container", {
    direction: "horizontal", //横向切换
    loop: true,
    grabCursor : true,//鼠标悬停时显示抓手
    updateOnWindowResize: true,
    slidesPerView: 1,
    spaceBetween: 30,
    mousewheel: true,
    pagination: {
    el: ".swiper-pagination",
    clickable: true,
    },
    autoplay: {
    delay: 2000,//2秒切换一次
    pauseOnMouseEnter: true, //鼠标进入停止切换,离开恢复切换
    },
    });
  10. 修改[Blogroot]\themes\butterfly\layout\includes\head.pug,新增swiper的css依赖项。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
      //- google_adsense
    !=partial('includes/head/google_adsense', {}, {cache: true})

    //- analytics
    !=partial('includes/head/analytics', {}, {cache: true})

    //- font
    if theme.blog_title_font && theme.blog_title_font.font_link
    link(rel='stylesheet' href=url_for(theme.blog_title_font.font_link) media="print" onload="this.media='all'")

    + //- swiper_css
    + if theme.swiperBar.enable
    + link(rel='stylesheet' href=url_for(theme.swiperBar.swiper_css) media="print" onload="this.media='all'")
  11. 修改[Blogroot]\themes\butterfly\layout\includes\additional-js.pug,把js依赖也引入进去。这步记得留个印象。因为后续设计想法里,友链、页脚、顶栏菜单我都打算用到swiper去实现切换效果。所以就不加一个swiperBar的开关配置项来控制是否引入了。省的后面遇到灯下黑。请五部牢记9、10、11三步的操作。以后的教程会经常和它们见面的。
    1
    2
    3
    4
    5
      div
    script(src=url_for(theme.asset.utils))
    script(src=url_for(theme.asset.main))
    + script(defer src=url_for(theme.swiperBar.swiper_js))
    + script(defer data-pjax src=url_for(theme.swiperBar.swiper_init_js))
  12. 在主题配置文件[Blogroot]/_config.butterfly.yml中添加配置项用以控制轮播图。配置项释义用过插件hexo-butterfly-swiper的应该都了解了,我就不另做解释了。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 源计划-方舟:首页轮播图
    # see https://akilar.top/posts/658f52d0/
    swiperBar:
    enable: true # 开关
    timemode: updated #date/updated
    error_img: /img/loading.gif #默认封面。记得换成自己的。
    default_descr: 就算再怎么看我也不知道怎么描述它好啦!
    swiper_css: https://npm.elemecdn.com/swiper@8.4.2/swiper-bundle.min.css #swiper css依赖
    swiper_js: https://npm.elemecdn.com/swiper@8.4.2/swiper-bundle.min.js #swiper js依赖
    swiper_init_js: /js/custom/swiper_init.js # swiper初始化方法

小结

如果在配置时遇到实现不了的问题。那我建议你放弃。源计划-方舟不是为零基础的小白设计的魔改方案。
但是如果你有更多赛博风格化的想法,可以和我一起讨论,如果我觉得有趣的话就把它写出来。
当然,大部分情况下我更喜欢一意孤行的自己写下去。
我预备把它作为我今年的生日作。
至少在生日到来前,要把首页的版块改完。
最近爆肝的程度有点夸张。希望在灵感逃走前我已经把它们抓起来写到代码里了。