阅读时间约 40 分钟

网站功能更新文档

功能更新文档

Posted by LuckyE on August 21, 2023
Jekyll

bundle exec jekyll serve --livereload

阅读进度指示器

footer.html

<!-- 阅读进度条 -->
<script src="/js/reading-progress.js"></script>

hux-blog.css

/* 阅读进度条样式 - 强制优先级 */
.reading-progress-bar {
    position: fixed !important;
    top: 0 !important;
    left: 0 !important;
    height: 6px !important; /* 增加高度 */
    background-color: #0085a1 !important; /* 醒目的粉色 */
    width: 0% !important;
    z-index: 99999 !important; /* 超高z-index */
    transition: width 0.2s ease !important;
    box-shadow: 0 0 8px rgba(0, 133, 161, 0.8) !important; /* 增加发光效果 */
    opacity: 0.9 !important;
}

reading-progress.js

// 阅读进度条功能
document.addEventListener('DOMContentLoaded', function() {
    console.log("DOM加载完成,初始化进度条");
  
    // 创建进度条元素(总是创建新的,确保样式正确)
    var oldBar = document.getElementById('reading-progress-bar');
    if (oldBar) {
        oldBar.parentNode.removeChild(oldBar); // 移除旧元素
    }
  
    var progressBar = document.createElement('div');
    progressBar.id = 'reading-progress-bar';
    progressBar.className = 'reading-progress-bar';
    document.body.insertBefore(progressBar, document.body.firstChild);
  
    console.log("进度条元素已创建:", progressBar);
  
    // 强制设置初始样式
    progressBar.style.position = "fixed";
    progressBar.style.top = "0";
    progressBar.style.left = "0";
    progressBar.style.height = "6px";
    progressBar.style.backgroundColor = "#0085a1";
    progressBar.style.width = "0%";
    progressBar.style.zIndex = "99999";
    progressBar.style.transition = "width 0.2s ease";
    progressBar.style.boxShadow = "0 0 8px rgba(0, 133, 161, 0.8)";
  
    // 更新进度条函数
    function updateProgressBar() {
        var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
        var height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
        var scrolled = (winScroll / height) * 100;
      
        // 输出调试信息
        // console.log("滚动位置:", winScroll, "总高度:", height, "进度:", scrolled.toFixed(1) + "%");
        progressBar.style.width = scrolled + "%";
    }
  
    // 添加事件监听器
    window.addEventListener('scroll', updateProgressBar);
    window.addEventListener('resize', updateProgressBar);
  
    // 初始化进度条
    console.log("初始化进度条状态");
    updateProgressBar();
  
    // // 测试可见性
    // console.log("测试进度条可见性");
    // var testWidth = 20;
    // var testInterval = setInterval(function() {
    //     progressBar.style.width = testWidth + "%";
    //     testWidth += 20;
      
    //     if (testWidth > 100) {
    //         clearInterval(testInterval);
    //         setTimeout(function() {
    //             progressBar.style.width = "0%";
    //             updateProgressBar();
    //         }, 1000);
    //     }
    // }, 300);
}
);

default.html

<!-- 阅读进度条 -->
    <div class="reading-progress-bar" id="reading-progress-bar"></div>

阅读时间估计

intro-header.html

<!-- 阅读时间估计 -->
<span class="meta reading-time"><i class="fa fa-clock-o" aria-hidden="true"></i> 阅读时间约 36 分钟</span>

hux-blog.css

/* 阅读时间样式 */
.reading-time {
  margin-left: 10px;
}

@media only screen and (max-width: 767px) {
  .reading-time {
      display: block;
      margin-left: 0;
      margin-top: 5px;
  }
}

返回顶部

post.html

<!-- 返回顶部按钮 -->
                <div id="back-top" class="back-to-top">
                    <a href="javascript:void(0);" title="返回顶部">
                        <i class="fa fa-arrow-up"></i>
                    </a>
                </div>

hux-blog.css

/* 返回顶部按钮 */
.back-to-top {
  position: fixed;
  left: 20px;
  bottom: 50%;
  transform: translateY(50%);
  z-index: 9999; /* 确保按钮在最上层 */
  width: 40px;
  height: 40px;
  background-color: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  opacity: 0.7;
  transition: all 0.3s ease;
  display: block;
}

.back-to-top a {
  display: flex;
  width: 100%;
  height: 100%;
  color: #fff;
  align-items: center;
  justify-content: center;
}

.back-to-top:hover {
  opacity: 1;
  transform: translateY(50%) scale(1.1);
  box-shadow: 0 0 10px rgba(0,0,0,0.3);
}

/* 移动设备适配 */
@media (max-width: 768px) {
  .back-to-top {
      left: 10px;
      width: 35px;
      height: 35px;
  }
}

back-to-top.js

// 返回顶部按钮功能
(function() {
    var backTop = document.getElementById('back-top');
  
    if (!backTop) return;
  
    // 点击返回顶部
    backTop.addEventListener('click', function(e) {
        e.preventDefault();
      
        // 平滑滚动到顶部
        window.scrollTo({
            top: 0,
            behavior: 'smooth'
        });
    });
  
    // 根据滚动位置调整按钮透明度
    window.addEventListener('scroll', function() {
        if (window.pageYOffset > 300) {
            backTop.style.opacity = "1.0";
        } else {
            backTop.style.opacity = "0.4";  // 靠近顶部时更透明
        }
    });
})();

全局黑暗模式

dark-mode.css

/* 深色模式的样式 */
:root {
  /* 浅色模式变量 */
  --bg-color: #fff;
  --text-color: #404040;
  --heading-color: #404040;
  --link-color: #337ab7;
  --link-hover-color: #0085a1;
  --selection-bg: #0085a1;
  --selection-color: #fff;
  --blockquote-bg: #f5f5f5;
  --blockquote-color: gray;
  --code-bg: #f2f2f2;
  --code-color: #555;
  --border-color: #eee;
  --navbar-bg: rgba(255, 255, 255, 0.9);
  --navbar-text: #404040;
  --card-bg: #fff;
  --post-heading-color: white; /* 文章头图上的文字颜色 */
  --footer-bg: white;
  --footer-text: #777;
  --catalog-active: #0085a1;
  --shadow-color: rgba(0, 0, 0, 0.1);
}

/* 深色模式 */
[data-theme="dark"] {
  --bg-color: #202124;
  --text-color: #e8eaed;
  --heading-color: #e8eaed;
  --link-color: #8ab4f8;
  --link-hover-color: #62a9ff;
  --selection-bg: #404040;
  --selection-color: #e8eaed;
  --blockquote-bg: #303134;
  --blockquote-color: #b1b1b3;
  --code-bg: #303134;
  --code-color: #f8f8f2;
  --border-color: #4e4e4e;
  --navbar-bg: rgba(32, 33, 36, 0.9);
  --navbar-text: #e8eaed;
  --card-bg: #303134;
  --post-heading-color: #e8eaed; /* 深色模式下文章头图上的文字颜色 */
  --footer-bg: #202124;
  --footer-text: #9aa0a6;
  --catalog-active: #62a9ff;
  --shadow-color: rgba(0, 0, 0, 0.5);
}

/* 全局背景和文字颜色 */
[data-theme="dark"] body {
  background-color: var(--bg-color);
  color: var(--text-color);
}

/* 导航栏样式 */
[data-theme="dark"] .navbar-custom {
  background-color: var(--navbar-bg);
}

[data-theme="dark"] .navbar-custom .nav li a,
[data-theme="dark"] .navbar-brand {
  color: var(--navbar-text);
}

/* 链接样式 */
[data-theme="dark"] a {
  color: var(--link-color);
}

[data-theme="dark"] a:hover,
[data-theme="dark"] a:focus {
  color: var(--link-hover-color);
}

/* 文章和段落 */
[data-theme="dark"] .post-container {
  color: var(--text-color);
}

/* 引用块 */
[data-theme="dark"] blockquote {
  background-color: var(--blockquote-bg);
  color: var(--blockquote-color);
  border-left-color: var(--link-hover-color);
}

/* 代码块样式 */
[data-theme="dark"] pre,
[data-theme="dark"] code {
  background-color: var(--code-bg);
  color: var(--code-color);
}

/* 侧边栏 */
[data-theme="dark"] .sidebar-container {
  background-color: var(--bg-color);
  color: var(--text-color);
}

/* 分割线 */
[data-theme="dark"] hr {
  border-color: var(--border-color);
}

/* 文章目录 */
[data-theme="dark"] .side-catalog .catalog-body .active {
  border-radius: 4px;
  background-color: var(--code-bg);
}

[data-theme="dark"] .side-catalog .catalog-body .active a {
  color: var(--catalog-active) !important;
}

/* 页脚 */
[data-theme="dark"] footer {
  background-color: var(--footer-bg);
  color: var(--footer-text);
}

/* 表格 */
[data-theme="dark"] table {
  border-color: var(--border-color);
}

[data-theme="dark"] table > tbody > tr:nth-child(odd) > td,
[data-theme="dark"] table > tbody > tr:nth-child(odd) > th {
  background-color: var(--code-bg);
}

/* 深色模式图片调整亮度 */
[data-theme="dark"] img:not(.no-darkmode) {
    filter: brightness(.8) contrast(1.2);
}

/* 深色模式切换按钮样式 */
.darkmode-toggle {
    cursor: pointer;
    font-size: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s ease;
}

.darkmode-toggle i {
    margin-right: 5px;
}

/* 过渡效果 */
body, a, .navbar-custom, .post-container, blockquote, pre, code, .sidebar-container, footer {
    transition: all 0.3s ease;
}

nav.html

<!-- 在搜索图标之前添加深色模式切换按钮 -->
<li class="darkmode-toggle">
  <a href="javascript:void(0)" id="darkmode-toggle" title="切换深色/浅色模式">
    <i class="fa fa-moon-o" id="darkmode-icon"></i>
  </a>
</li>
<li class="search-icon">
  <a href="javascript:void(0)">
    <i class="fa fa-search"></i>
  </a>
</li>

dark-mode.js

// 深色模式实现脚本
(function() {
    // DOM 元素加载完成后执行
    document.addEventListener('DOMContentLoaded', function() {
        // 获取切换按钮和图标元素
        const darkModeToggle = document.getElementById('darkmode-toggle');
        const darkModeIcon = document.getElementById('darkmode-icon');
      
        // 检查本地存储中的主题设置
        const savedTheme = localStorage.getItem('theme');
        // 检测系统偏好
        const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
      
        // 初始化主题设置
        let currentTheme;
      
        // 如果有保存的设置,使用保存的设置;否则根据系统偏好设置
        if (savedTheme) {
            currentTheme = savedTheme;
        } else {
            currentTheme = prefersDarkMode ? 'dark' : 'light';
        }
      
        // 应用当前主题
        applyTheme(currentTheme);
      
        // 更新按钮图标状态
        updateDarkModeIcon(currentTheme);
      
        // 添加点击事件
        if (darkModeToggle) {
            darkModeToggle.addEventListener('click', function() {
                // 切换主题
                const newTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
              
                // 保存到本地存储
                localStorage.setItem('theme', newTheme);
              
                // 应用新主题
                applyTheme(newTheme);
              
                // 更新按钮图标
                updateDarkModeIcon(newTheme);
            });
        }
      
        // 监听系统主题变化
        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) {
            // 只有没有手动设置过的才自动跟随系统
            if (!localStorage.getItem('theme')) {
                const newTheme = e.matches ? 'dark' : 'light';
                applyTheme(newTheme);
                updateDarkModeIcon(newTheme);
            }
        });
      
        // 应用主题函数
        function applyTheme(theme) {
            document.documentElement.setAttribute('data-theme', theme);
        }
      
        // 更新图标函数
        function updateDarkModeIcon(theme) {
            if (!darkModeIcon) return;
          
            if (theme === 'dark') {
                darkModeIcon.classList.remove('fa-moon-o');
                darkModeIcon.classList.add('fa-sun-o');
            } else {
                darkModeIcon.classList.remove('fa-sun-o');
                darkModeIcon.classList.add('fa-moon-o');
            }
        }
    });
})();

在head.html中引用CSS和JS文件

<link rel="stylesheet" href="/css/dark-mode.css">

<script src="/js/dark-mode.js"></script>

<font style="color:rgb(59, 59, 59);">功能特性</font>

  1. <font style="color:rgb(59, 59, 59);">自动/手动切换</font><font style="color:rgb(59, 59, 59);">:根据系统设置自动切换,同时支持手动点击切换</font>
  2. <font style="color:rgb(59, 59, 59);">记忆功能</font><font style="color:rgb(59, 59, 59);">:使用localStorage保存用户的主题偏好</font>
  3. <font style="color:rgb(59, 59, 59);">平滑过渡</font><font style="color:rgb(59, 59, 59);">:添加了CSS过渡效果,使切换更平滑</font>
  4. <font style="color:rgb(59, 59, 59);">响应式设计</font><font style="color:rgb(59, 59, 59);">:在所有设备上保持良好体验</font>
  5. <font style="color:rgb(59, 59, 59);">图标变化</font><font style="color:rgb(59, 59, 59);">:根据当前模式自动切换月亮/太阳图标</font>


Testimonials

What readers say

先看读者反馈,再直接在当前页面继续讨论。公共留言需要 Waline 服务端;配置后访客只填昵称即可发布。

这类长文如果结构清楚,我会一路读到底。这里最好的地方是把概念、公式和代码示例放在同一篇里。

L
Lin 算法读者

数据库和工程文档的风格很实用,截图、SQL 和说明都能直接拿去复盘项目。

M
Mia 工程笔记党

强化学习相关文章密度很高,但排版如果更清楚,回看体验会更好。这个新版方向是对的。

R
Ryo 深夜学习者

我更喜欢能快速扫到标签、修改时间和文章重点的首页,现在这种卡片视图会比纯列表更容易选读。

C
Chen 知识整理控

代码块只要语言标识和层级做好,技术博客的专业感会立刻上来。

A
Ava 前端同行

评论区不用社交账号强绑定会更愿意留言,尤其是这种偏学习记录的网站。

N
Noah 匿名访客

Quick Identity

Pick a preset and leave a note

留言方式:先选择一个预设身份,再在下方输入评论。当前若显示“需要配置 Waline”,说明站点还缺少可写评论后端。

当前未选择预设身份

Live Discussion Waline 配置完成后,真实评论会加载在下方,移动端和主题切换会同步处理。
WALINE
Loading comments…