2324 字
12 分钟
给博客来个大升级(第二弹)
2026-02-11
AI 智能总结

博客系统更新日志#

v0.9.1-TESTA1 - 最大、最重要、最高可用的更新#

新增功能#

1. 设置面板重构#

  • 音乐选项卡

    • 新增”音乐”选项卡,支持自定义音乐播放列表
    • 可添加、删除、排序歌曲
    • 支持实时预览和保存
  • 导航栏管理优化

    • 导航栏选项名称与实际路由匹配(文章集、展板等)
    • 支持实时显示/隐藏导航链接,无需刷新(因 人 而 异)
  • 点击外部关闭优化

    • 采用与主题色面板一致的关闭机制
    • 点设置面板外任何位置即可关闭
    • 支持 ESC 键关闭

2. 音乐播放器#

  • 自定义播放列表

    • 通过设置面板添加自定义歌曲
    • 支持歌曲名称、艺术家、音频链接
    • 播放列表保存在 localStorage
    • 修改后立即生效
  • 滚动条美化

    • 播放列表滚动条:5px 宽度,透明轨道
    • 悬停时变为主题色
    • 支持 Chrome/Safari/Edge 和 Firefox
  • 默认播放列表

    • 使用 SoundHelix 提供的免费示例音乐
    • 可通过设置面板完全自定义

3. 友链页面扩展#

  • 新增外站推荐部分

    • 在友链页面添加”外站推荐”区域
    • 支持分类管理外部站点
    • 独立的统计卡片显示外站数量
    • 使用相同的卡片样式保持一致性
  • 导航栏名称更新

    • “友链” 改为 “友链&外站”

4. 文章页面优化#

  • 移除聚光灯模式按钮
    • 人性化
    • 聚光灯和激光笔功能
    • 字体字号随心用
    • 无障碍体验
    • 支持AI总结(深度思考32B模型)

技术改进#

设置面板架构#

  • 使用 float-panel 类实现统一的面板行为
  • 通过 setClickOutsideToClose 函数处理外部点击
  • 使用 float-panel-closed 类控制显示/隐藏

导航栏动态控制#

// 实时应用导航栏设置
function applyNavbarSettings() {
const settings = JSON.parse(localStorage.getItem('effectsSettings'));
// 根据设置显示/隐藏导航链接
links.forEach(link => {
link.style.display = settings.navbarLinks[key] ? '' : 'none';
});
}

滚动条样式适应(谁知道呢)#

/* Webkit 浏览器 */
.playlist-items::-webkit-scrollbar {
width: 5px;
}
.playlist-items::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.15);
border-radius: 2.5px;
}
/* Firefox */
.playlist-items {
scrollbar-width: thin;
scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
}

配置文件更新#

friends.ts#

// 外站链接配置
export const externalSites: {
name: string;
desc: string;
avatar: string;
url: string;
category?: string;
}[] = [
// 外站链接列表
];
[LinkPreset.friend]: {
name: "友链&外站",
url: "/friends/",
}

用户体验改进#

  1. 操作反馈

    • 设置修改后立即生效
    • 无需刷新页面即可看到变化
  2. 界面一致性

    • 所有面板使用统一的打开/关闭机制
    • 滚动条样式统一美化
    • 保持与整体设计风格一致
  3. 数据持久化

    • 音乐播放列表保存在 localStorage
    • 导航栏设置保存在 localStorage
    • 跨会话保持用户配置

阅读功能大升级#

新增功能#

选项卡式界面设计#

  • 将功能分为两个选项卡,界面更清晰
  • 阅读设置选项卡:字体大小、行距、无障碍功能
  • 辅助工具选项卡:聚光灯、激光笔等演示工具
  • 选项卡切换流畅,带动画效果

1. 聚光灯模式#

  • 跟随鼠标的聚光灯效果,帮助专注阅读
  • 快捷键:Ctrl+Shift+S
  • 设置自动保存到 localStorage

2. 激光笔功能#

  • 鼠标位置显示红色发光点
  • 适合在线演示和教学
  • 快捷键:Ctrl+Shift+L
  • 可与聚光灯同时使用

3. 无障碍阅读功能#

易读模式#
  • 增加字间距(letter-spacing: 0.05em)
  • 增加词间距(word-spacing: 0.1em)
  • 增大段落和标题间距
  • 特别适合阅读障碍用户
高对比度模式#
  • 全局对比度增强 20%
  • 文本颜色强化
  • 自动适配深色/浅色主题
  • 帮助视力较弱的用户
专注模式#
  • 非悬停段落透明度降低至 40%
  • 鼠标悬停段落完全显示
  • 标题始终完全显示
  • 平滑过渡动画

技术实现#

聚光灯实现#

// 使用 radial-gradient 创建聚光灯效果
background: radial-gradient(
circle ${radius}px at ${x}px ${y}px,
transparent 0%,
rgba(0, 0, 0, 0.85) 100%
);

激光笔实现#

// 使用 fixed 定位 + 发光效果
box-shadow:
0 0 20px rgba(255, 0, 0, 0.8),
0 0 40px rgba(255, 0, 0, 0.4);

无障碍模式#

/* 易读模式 */
.accessibility-mode {
letter-spacing: 0.05em;
word-spacing: 0.1em;
}
/* 高对比度 */
.high-contrast-mode {
filter: contrast(1.2);
}
/* 专注模式 */
.focus-mode p {
opacity: 0.4;
transition: opacity 0.3s ease;
}
.focus-mode p:hover {
opacity: 1;
}

用户体验优化#

  1. 设置持久化:所有设置自动保存到 localStorage
  2. 快捷键支持:提供键盘快捷键,提高效率
  3. 不影响交互:聚光灯和激光笔使用 pointer-events: none
  4. 性能优化:使用 CSS transform,性能优异
  5. 响应式设计:适配各种屏幕尺寸

浏览器兼容性#

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+

模态框突破父容器限制#

更新#

本次更新对博客系统进行了全面的用户体验优化,重点解决了模态框组件被父容器限制的技术难题,并添加了多项实用功能。

问题#

在 Web 开发中,模态框(Modal)组件经常会遇到一个棘手的问题:父容器的 CSS 属性限制

当父容器设置了以下属性时,子元素的 position: fixed 会失效:

  • transform
  • perspective
  • filter
  • backdrop-filter
  • will-change
  • contain

在我们的博客系统中,文章内容区域(.markdown-content)使用了多种 CSS 效果,导致模态框无法正确定位到屏幕中央,而是被限制在父容器内部。

传统解决方案的局限#

方案一:提升 z-index#

.modal {
z-index: 99999 !important;
}

问题:只能解决层级问题,无法解决定位问题。

方案二:使用 Portal(React)#

ReactDOM.createPortal(modal, document.body)

问题:Svelte 没有内置的 Portal API。

方案三:调整父容器样式#

.parent {
transform: none !important;
}

问题:会破坏现有的视觉效果。

我们的解决方案:Svelte 响应式 + DOM 操作#

经过多次尝试,得出一个完美的解决方案:利用 Svelte 的响应式系统,在运行时将模态框元素移动到 document.body

核心代码实现#

<script lang="ts">
import { onMount, onDestroy } from 'svelte';
export let show = false;
let modalElement: HTMLDivElement;
// 响应式
$: if (show && modalElement) {
// 将模态框移动到 body
document.body.appendChild(modalElement);
document.body.style.overflow = 'hidden';
} else if (!show && typeof document !== 'undefined') {
document.body.style.overflow = '';
}
onDestroy(() => {
if (typeof document !== 'undefined') {
document.body.style.overflow = '';
}
});
</script>
{#if show}
<div
bind:this={modalElement}
class="modal-root"
on:click={close}
>
<div class="modal-content" on:click|stopPropagation>
<!-- 内容 -->
</div>
</div>
{/if}
<style>
.modal-root {
/* 使用 !important 确保样式不被覆盖 */
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 999999 !important;
/* 背景和模糊 */
background: rgba(0, 0, 0, 0.6) !important;
backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important;
/* 居中布局 */
display: flex !important;
align-items: center !important;
justify-content: center !important;
}
</style>

技术要点解析#

1. Svelte 响应式语句 $:#

$: if (show && modalElement) {
document.body.appendChild(modalElement);
}

这是 Svelte 的响应式语法,当 showmodalElement 变化时自动执行。这样我们可以在模态框显示时,动态地将其移动到 document.body

2. bind:this 绑定#

<div bind:this={modalElement}>

获取 DOM 元素的引用,这样我们才能操作它。

3. 事件冒泡控制#

<div on:click={close}>
<div on:click|stopPropagation>
  • 外层:点击遮罩关闭
  • 内层:stopPropagation 阻止事件冒泡,点击内容不关闭

4. 使用 !important 强制样式#

由于元素会被移动到 body,可能受到全局样式影响,使用 !important 确保样式生效。

5. 滚动锁定#

document.body.style.overflow = 'hidden';

模态框打开时禁止页面滚动,提升用户体验。 这就是本博客所有文章“分享”逻辑,详见↓

其他重要更新#

1. 文章互动功能#

收藏功能#

function addFavorite() {
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const shortcut = isMac ? 'Cmd+D' : 'Ctrl+D';
alert(`请按 ${shortcut} 将本页添加到书签`);
}

分享模态框 - 飞机票设计#

采用机场登机牌的设计风格:

  • 渐变色头部
  • 虚线分隔
  • 圆形镂空效果
  • 真实的 CODE128 条码
  • 扫描线动画
import JsBarcode from 'jsbarcode';
function generateBarcode() {
const barcodeData = `${slug}-${Date.now()}`.substring(0, 20);
JsBarcode(barcodeCanvas, barcodeData, {
format: 'CODE128',
width: 2,
height: 60,
displayValue: false,
background: 'transparent',
lineColor: isDark ? '#ffffff' : '#000000'
});
}

PDF 导出功能#

使用浏览器原生打印功能,配合专门的打印样式:

@media print {
#navbar, #sidebar, .post-actions {
display: none !important;
}
.markdown-content {
font-size: 12pt !important;
line-height: 1.6 !important;
}
.markdown-content a[href]:after {
content: " (" attr(href) ")";
}
}

2. 阅读设置#

同样使用”逃脱父容器”技术实现:

<div class="settings-root">
<div class="settings-content">
<!-- 字体大小、行距调节 -->
</div>
</div>

设置会保存到 localStorage,下次访问自动应用。

3. 时光流逝组件#

独立的卡片组件,分钟更新制,显示:

  • 今日已过去
  • 本周已过去
  • 本月已过去
  • 今年已过去

4. 评论系统#

集成 Giscus,基于 GitHub Discussions:

技术栈#

  • 框架: Astro + Svelte
  • 样式: Tailwind CSS + 自定义 CSS
  • 条码生成: JsBarcode
  • 二维码生成: qrcode
  • 评论系统: Giscus
  • 部署: Vercel

性能优化#

  1. 按需加载:使用 client:load 指令
  2. CSS 动画:优先使用 CSS 而非 JavaScript
  3. 防抖节流:避免频繁的 DOM 操作
  4. 懒加载:图片和组件按需加载

总结#

本次更新的核心是突破父容器限制的技术实现。使得Fuwari的内容不在受限于一个HTML渲染器! 那么,本人的关键词系统将会在后续按照此方法更新!

希望这篇文章能帮助遇到类似问题的开发者!


技术关键词: Svelte, Modal, Portal, CSS Position, DOM Manipulation, Responsive Design

最后更新: 2026-02-11

作者: xhc861

给博客来个大升级(第二弹)
作者
xhc861
发布于
2026-02-11
许可协议
CC BY-NC-SA 4.0

评论区

请添加歌曲
前往右上角设置按钮添加