主题改动总结(v1.6.5)

主题与文档

  • 修改 theme.yaml
    • 作者:阿狄
    • 主页:https://chengquan.icu
    • 描述补充:“Customized by 阿狄”
    • issues/repo 更新为 Gitee:
      • issues:https://gitee.com/lfc_6666/theme-fucheng/issues
      • repo:https://gitee.com/lfc_6666/theme-fucheng
  • 更新 README.md
    • 增加功能特性、使用指南、更新日志、联系方式
    • 完整说明“星空入口页面”和“公告栏小部件”的使用与配置

文章列表与布局重构

  • templates/modules/post-list.html
    • 新增文章元信息(日期、分类、标签)
    • 摘要智能提取:优先“总结/小结/Summary”,否则截取前 100 字
    • 去除不必要的“more...”按钮
  • templates/assets/css/post-list-layout.css
    • 对角切图、左右交错布局
    • 悬停放大与卡片上浮效果
    • 响应式与深色模式适配
    • 新增 .article-list-container 居中外框
  • templates/index.html
    • 文章列表从 recent-posts 中分离,作为独立的 .article-list-container 居中展示
    • .content-area 设为“无背景、无边线、无阴影”
  • templates/category.htmltemplates/tag.html
    • 与首页统一,均复用 modules/post-list.html 的文章列表布局

归档与导航优化

  • templates/archives.html
    • 时间线弹窗增强:以图文卡片形式展示文章
    • timeline-post 注入 data-cover,JS 读取渲染卡片
  • templates/assets/zhheo/custom.css
    • 归档页导航栏字体统一为白色
    • 新增瞬间页头部与细节样式

瞬间与星空(拆分为两个页面)

  • 新的瞬间列表页:templates/moments.html
    • 去除顶部大图,简洁头部 + “返回星空”按钮
  • 星空入口页:templates/page_space.html
    • Three.js 3D 粒子星云背景
    • 金色发光粒子:数量与瞬间条数一致,一一对应
    • 粒子随机分布、圆形高光、呼吸式脉动发光
    • 点击粒子弹出瞬间弹窗(支持图文与时间展示)
    • 增加提示:“点击发光的金色粒子,探索瞬间”
    • 修复数据注入与作用域:window.allMoments 全局注入;确保 Three.js 初始化后创建金色粒子
    • 补齐弹窗关闭(×)按钮

鼠标星星拖尾特效(Canvas + rAF + 节流 + PJAX 清理)

  • 引入位置(全局布局末尾统一加载,确保 DOM 可用):
    <!-- 鼠标星星拖尾特效 -->
    <script th:src="${assets_link + '/js/mouse-star.js' + theme_version}"></script>
  • 核心绘制五角星路径(基于三角函数的点计算):
  function star(x, y, r, l, rot) {
    ctx.beginPath();
    for (let i = 0; i < 5; i++) {
      ctx.lineTo(
        Math.cos(((18 + i * 72 - rot) * Math.PI) / 180) * r + x,
        -Math.sin(((18 + i * 72 - rot) * Math.PI) / 180) * r + y
      );
      ctx.lineTo(
        Math.cos(((54 + i * 72 - rot) * Math.PI) / 180) * l + x,
        -Math.sin(((54 + i * 72 - rot) * Math.PI) / 180) * l + y
      );
    }
    ctx.closePath();
  }
  • 动画主循环(requestAnimationFrame,空队列自动停止):
  function animate() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    if (arr.length > 0) {
      draw();
      update();
      animationId = requestAnimationFrame(animate);
    } else {
      isAnimating = false;
    }
  }
  • 性能策略(上限 50 个星星 + 16ms 事件节流 ≈ 60fps):
  function addStars(e) {
    // 限制最大星星数量,避免内存泄漏
    if (arr.length > 50) {
      arr.shift(); // 移除最老的星星
    }
    arr.push({
  let lastTime = 0;
  const throttleDelay = 16; // 约 60fps
  window.addEventListener("mousemove", (e) => {
    const now = Date.now();
    if (now - lastTime >= throttleDelay) {
      addStars(e);
      lastTime = now;
    }
  });
  • PJAX 兼容:切页时停止动画、清空画布、回收数据
  document.addEventListener('pjax:send', function() {
    if (animationId) {
      cancelAnimationFrame(animationId);
      animationId = null;
    }
    isAnimating = false;
    arr = [];
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });

PJAX 生命周期管理(脚本重挂载、懒加载更新、销毁副作用)

  • 初始化与 send 阶段(销毁滚动监听、播放器、typed 实例等):
        var pjax = new Pjax({
            elements: 'a:not([target="_blank"])',
            selectors: pjaxSelectors,
            cacheBust: false,
            analytics: false,
            scrollRestoration: false
        })
        
        document.addEventListener('pjax:send', function () {
            // removeEventListener toc scroll
            window.removeEventListener('scroll', window.tocScrollFn)
            typeof preloader === 'object' && preloader.initLoading()
            if (window.aplayers) {
                for (let i = 0; i < window.aplayers.length; i++) {
                    if (!window.aplayers[i].options.fixed) {
                        window.aplayers[i].destroy()
                    }
                }
            }
            typeof typed === 'object' && typed.destroy()
            //reset readmode
            const $bodyClassList = document.body.classList
            $bodyClassList.contains('read-mode') && $bodyClassList.remove('read-mode')
        })
  • complete 阶段(重挂带 data-pjax 的脚本、更新懒加载/Prism、结束预加载):
        document.addEventListener('pjax:complete', function () {
            window.refreshFn()
            document.querySelectorAll('script[data-pjax]').forEach(item => {
                        const newScript = document.createElement('script')
                        const content = item.text || item.textContent || item.innerHTML || ""
                        Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
                        newScript.appendChild(document.createTextNode(content))
                        item.parentNode.replaceChild(newScript, item)
                    }
            )
            GLOBAL_CONFIG.lazyload.enable && window.lazyLoadInstance.update()
            typeof Prism === 'object' && Prism.highlightAll()
            typeof preloader === 'object' && preloader.endLoading()
        })

侧边栏与小部件

  • 新增公告栏小部件:templates/modules/widgets/aside/announcement.html
    • 自适应内容高度、暖橙渐变、铃铛动画
    • 支持富文本与可选操作按钮
  • 新增简化简介卡片:templates/modules/widgets/aside/profile-simple.html
    • 更紧凑的个人简介展示

其它变更

  • 新增 templates/assets/css/archive-timeline.css(归档时间线样式)
  • 分类/标签页统一接入 modules/post-list.html
  • 清理不需要的页面模板与文档:
    • templates/login.htmltemplates/signup.htmltemplates/password-reset.html
    • LOGIN_PAGE_GUIDE.md

本地开发热更新关键配置(JAR 部署场景)

对于本地 JAR 运行的 Halo(非 Docker),要使 HTML/CSS/JS 的改动无需重启生效:

  • 关闭 Thymeleaf 缓存(注意位置在 spring 下)
  • work-dir 指向 Halo 工作根目录(包含 themes/plugins/logs 等)

示例(application.yaml):

spring:
  thymeleaf:
    cache: false

halo:
  work-dir: I:\cloud_data\chengquanicu\halo\data

说明:

  • 模板 .html / CSS / JS:浏览器刷新(静态资源建议 Ctrl+F5 强刷)
  • theme.yaml / settings.yaml:需重启 JAR(主题元配置变更)

—— Made with ❤️ by 阿狄