AI 正在绞尽脑汁想思路 ING···
AI 摘要
DeepSeek & Kimi

§ 背景

Shoka 主题原版没有轮播图功能。hexo-shoka-swiper 是一个专为 Shoka 主题设计的轮播图插件,基于 Swiper 库,提供两种使用场景:

  1. 首页推广轮播(全局)—— 在首页展示带有 swiper_index front-matter 的文章卡片
  2. 文章内轮播(按文章)—— 通过 {% swiper %} / {% slide %} 标签在文章中嵌入图片/视频画廊

插件由 akilarlxh 和 llxlr 共同开发,llxlr 负责后续维护和 Pjax 适配增强。

仓库llxlr/hexo-shoka-swiper | 版本:0.1.11 | 许可:Apache-2.0

§ 安装

pnpm add hexo-shoka-swiper

依赖:Swiper CSS/JS 通过插件的 CDN(jsDelivr)自动加载,无需额外安装。依赖 nunjucks-date(Nunjucks 模板中日期格式化)。

§ 架构设计

🖥️ 客户端运行时🔨 构建时(Hexo generate)window.__SWIPER_CONFIG__暴露全局配置swiper_init.js首次加载初始化 Swiperpjax:send → 销毁实例pjax:success → 重建 Swiperafter_generate filter遍历 posts,筛选 swiper_index按 swiper_index 降序排列Nunjucks 渲染 slider.njk → HTML通过 injector 注入 HTML + CSS + JS

§ 首页推广轮播

§ 配置

_config.shoka.yml 中:

swiper:
  enable: true                # 总开关
  enable_page: all            # 显示页面:all 或指定路径
  exclude:                    # 排除路径列表
  timemode: date              # 卡片日期:date 或 updated
  layout:
    type: id                  # 注入容器类型:id 或 class
    name: main                # 容器选择器
    index: 0                  # class 模式下的索引
  insertposition: afterbegin  # DOM 插入位置
  swiper_title: 推荐阅读       # 标题文字
  default_descr: 再怎么看我也不知道怎么描述它的啦!  # 默认描述
  error_img: /images/loading.gif  # 封面图加载失败时的占位图
  swiper_css:                 # 可选:自定义 Swiper CSS CDN
  swiper_js:                  # 可选:自定义 Swiper JS CDN
  custom_css:                 # 可选:自定义样式 CDN
  custom_js:                  # 可选:自定义初始化脚本 CDN

§ 文章配置

在文章 Front Matter 中添加:

---
title: 值得一读的好文章
swiper_index: 10              # 数值越大越靠前
description: 这篇文章真的很棒  # 卡片描述文字
cover: /images/cover.jpg      # 卡片封面图
swiper_type: video            # 可选:视频卡片
swiper_video: /videos/demo.mp4
swiper_video_poster: /images/poster.jpg
swiper_video_embed: <iframe src="..."></iframe>  # 或嵌入视频
link: /other-post/            # 可选:自定义卡片链接
---

§ 数据流

文章 Front Matter
  swiper_index: 10
  cover: /images/cover.jpg
  description: "文章描述"
      ↓ after_generate filter 收集
swiper_list (按 swiper_index 降序排列)
      ↓ Nunjucks 渲染 lib/slider.njk
HTML(.blog-slider 容器,含 .blog-slider__wrp > .blog-slider__item)
      ↓ injector 注入 + swiper_init.js 初始化
Swiper 实例(fade 效果 + pagination 圆点 + Pjax 生命周期管理)

§ Pjax 适配

hexo-shoka-swiper 对 Pjax 进行了完整适配,这是本插件最核心的增强:

// swiper_init.js 核心逻辑(简化版)
(function () {
  function initSwiper() {
    if (window.swiper?.destroy) {
      window.swiper.destroy(true, true);  // 1. 先销毁旧实例
      window.swiper = null;
    }
    const el = document.querySelector(".blog-slider");
    if (!el) return;                       // 2. DOM 不存在则跳过
    window.swiper = new Swiper(".blog-slider", { ... });  // 3. 创建新实例
  }
  function pjaxMount() {
    const cfg = window.__SWIPER_CONFIG__;
    if (!cfg) return;
    const cpage = location.pathname;
    if (cfg.epage !== "all" && cfg.epage !== cpage) return;  // 路径匹配
    const parent = cfg.get_layout();
    if (parent && !parent.querySelector(".blog-slider")) {
      parent.insertAdjacentHTML(cfg.insertposition, cfg.html);  // 重新注入 HTML
    }
    initSwiper();
  }
  initSwiper();  // 首次加载
  document.addEventListener("pjax:send", () => {
    window.swiper?.destroy?.(true, true);   // Pjax 前清理
    window.swiper = null;
  });
  document.addEventListener("pjax:success", pjaxMount);  // Pjax 后重建
})();

关键设计要点

要点说明
pjax:send 中销毁在 DOM 被替换前释放内存,避免操作即将消失的元素
HTML 重新注入Pjax 替换 .pjax 后轮播容器消失,需要重新注入
window.__SWIPER_CONFIG__首次加载的 inline 脚本暴露配置到全局,Pjax 时读取
路径匹配支持 all 或精确路径,排除列表过滤
视频管理slide 切换时暂停所有视频,仅播放当前 slide 的视频(400ms 延迟,匹配 fade 过渡)

§ 文章内轮播 Tag

文章内轮播通过两对标签实现:{% swiper %} 容器 + {% slide %} 子项。

§ 基本语法

{% swiper style:gallery ratio:16:9 %}
{% slide cover:/images/photo1.jpg %}
这是第一张照片的描述
{% endslide %}
{% slide cover:/images/photo2.jpg link:https://example.com %}
第二张,点击可跳转
{% endslide %}
{% slide video:/videos/demo.mp4 poster:/images/poster.jpg %}
带封面的视频
{% endslide %}
{% slide embed:<iframe src="..."></iframe> %}
嵌入视频(YouTube / Bilibili)
{% endslide %}
{% endswiper %}

§ 参数说明

{% swiper %} 容器参数

参数说明
stylegallery (默认) / card画廊模式(大图 + 导航箭头)/ 卡片模式(小卡 + fade + 竖排圆点)
ratio16:9 (默认) / 4:3 / 1:1媒体区域宽高比

{% slide %} 子项参数

参数说明
cover图片 URL(图片 slide)
video视频 URL(视频 slide)
poster视频封面图
embed嵌入 iframe HTML(如 YouTube / Bilibili)
link点击 slide 的跳转链接
typeimagevideo(默认自动检测)

内容(位于 {% slide %}...{% endslide %} 之间):支持 Markdown 的描述文本,渲染后显示在 slide 底部。

§ 自动注入

文章内轮播的 Swiper CSS/JS 资源在首次使用时自动注入到 <head><body>,无需额外配置。每个 swiper 容器获得唯一 ID(as_N_xxxxxx),同一页面可放置多个独立轮播。

§ Pjax 兼容

文章内轮播通过 window.__articleSwipers 数组管理所有实例:

  • pjax:send:遍历数组,逐个 destroy(),然后清空
  • pjax:success:扫描新页面中的 .as-swiper 容器,重新初始化

§ 样式定制

插件的 CSS(swiperstyle.css)包含完整的响应式设计:

  • 桌面端:大图轮播 + 图文卡片 + 导航箭头 + pagination 圆点
  • 移动端(≤600px):紧凑布局,文字缩小,导航箭头隐藏
  • 暗黑模式:通过 [data-theme=dark] 选择器适配
  • 动画:active slide 的标题和描述有分层淡入动画(staggered fade-in)

如需覆盖默认样式,可通过插件的 custom_css 配置项指定自定义样式表路径。

§ 资源文件结构

hexo-shoka-swiper/
├── index.js              # 插件入口
├── lib/
│   ├── swiper.min.css    # Swiper 核心 CSS
│   ├── swiper.min.js     # Swiper 核心 JS
│   ├── swiperstyle.css   # 自定义样式(响应式 + 暗黑模式)
│   ├── swiper_init.js    # 初始化脚本(含 Pjax 适配)
│   ├── slider.njk        # 首页轮播 Nunjucks 模板
│   └── swiper.njk        # 文章内轮播 Nunjucks 模板(gallery / card)
└── images/
    └── loading.gif       # 默认加载占位图

§ 相关文章

§ 参考链接

阅读次数

请我喝[茶]~( ̄▽ ̄)~*

星旅人 微信支付

微信支付

星旅人 支付宝

支付宝


在提问之前,你应该学会如何提问