惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
Google Online Security Blog
Google Online Security Blog
月光博客
月光博客
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
M
MIT News - Artificial intelligence
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
aimingoo的专栏
aimingoo的专栏
博客园 - 三生石上(FineUI控件)
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
The Cloudflare Blog
Blog — PlanetScale
Blog — PlanetScale
F
Full Disclosure
G
Google Developers Blog
罗磊的独立博客
Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Y
Y Combinator Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
A
About on SuperTechFans
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队
GbyAI
GbyAI
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
The Register - Security
The Register - Security
U
Unit 42
D
Docker
Martin Fowler
Martin Fowler
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
博客园_首页
Google DeepMind News
Google DeepMind News

半方池水半方田

小球称重问题及其引申的思考 蓝色的结构色 病毒是不是生物? 把博客发布交给 GitHub Actions 省外居民身份证的补换领(苏州) hexo-filter-titlebased-link:构建你的数字花园 Vercel 应用实践学习 通过与 Keycloak 配合实现博客文章的受限访问功能 非公开的文章 Soft Mode 非公开的文章 Strict Mode 试试用代码块在 Hexo 中插入实况照片 动态图片测试 Hexo-Butterfly 主题 Preloader 加载页定制 Keycloak 的部署以及 Hexo-Butterfly 网页应用的接入 Authentik 的部署记录 Waline 自建 Auth 认证 记一次行李托运理赔流程(南航) Docker 镜像的制作、拉取与运行 Hexo-Butterfly 主题中对 Algolia 搜索框 Power By 的定制 Hexo 动态加载配置(钩子函数) 设计原则 VSCode 中的配置 Spring AI 中使用 PGVector 实现向量存储 提示词工程速查手册 2025 WePlay 上海两日游 和随机数生成相关的题目 一起撸串(字符串) 树状数组上手了就十分简单 缓存置换算法的实现与 Java 中相关的数据结构 关于海量数据的若干问题 访问者模式填补单分派语言的缺陷 备忘录模式:拍下照片
随机访问文章的实现(Sitemap+本地缓存优化)
wuanqin · 2026-04-08 · via 半方池水半方田

|总字数:855|阅读时长:4分钟|浏览量:|

|出链:0|入链:1

一份古老的代码传承至今,已经有很多的版本…这里介绍我的版本。

随机访问文章的实现思路

随机文章跳转的基本原理就三步:

  • 提前准备好一张站点列表
  • 读取列表,并随机挑一个出来
  • 访问目标地址

站点列表的准备

站点列表可以自己准备,或者使用插件 hexo-generator-sitemap 来生成。

站点列表的样子:

1
2
3
4
5
6
https://blog.uuanqin.top/p/18bbd410/
https://blog.uuanqin.top/p/c7d4d021/
https://blog.uuanqin.top/pages/copyright/index.html
https://blog.uuanqin.top/p/51890a9/
https://blog.uuanqin.top/p/91b7dad/
https://blog.uuanqin.top/pages/about/index.html

优化点

为了保证函数的精简和高效,本文代码有以下优化点:

  • 不重复请求 sitemap.txt,而是利用浏览器本地缓存(带过期)加速网站列表的获取
  • 随机跳转有不依赖任何框架的 CSS 简单提示
  • 随机跳转时将保持 url 参数,如想移除,可自行在REMOVED_PARAMS中填入。

Hexo-Butterfly 主题的使用

这里以菜单栏按钮为例。_config.butterfly.yml 中配置如下:

1
2
3
4
5
6
7
8

menu:
随机: javascript:randomPost(); || iconfont icon-suijibofang

inject:
head:

- <script src="/js/random.js"></script>

random.js 实现如下:

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



const RANDOM_CONFIG = {
SITEMAP_URL: '/sitemap.txt',
PATH_FILTER: '/p/',
CACHE_KEY: 'random_post_data',
CACHE_TIME: 24 * 60 * 60 * 1000,
FALLBACK_URL: '/',
REMOVED_PARAMS: []
};

async function randomPost() {

const showNotice = (msg) => {
let snack = document.getElementById('random-snack');
if (!snack) {
snack = document.createElement('div');
snack.id = 'random-snack';

Object.assign(snack.style, {
position: 'fixed', bottom: '30px', left: '50%', transform: 'translateX(-50%)',
backgroundColor: '#333', color: '#fff', padding: '10px 20px', borderRadius: '5px',
zIndex: '9999', fontSize: '14px', transition: 'opacity 0.3s'
});
document.body.appendChild(snack);
}
snack.innerText = msg;
snack.style.opacity = '1';
setTimeout(() => snack.style.opacity = '0', 2000);
};

try {
let urls = [];
const cached = localStorage.getItem(RANDOM_CONFIG.CACHE_KEY);
const now = Date.now();


if (cached) {
const { data, timestamp } = JSON.parse(cached);
if (now - timestamp < RANDOM_CONFIG.CACHE_TIME) urls = data;
}

if (urls.length === 0) {
showNotice('正在同步文章列表…');
const res = await fetch(RANDOM_CONFIG.SITEMAP_URL);
if (!res.ok) throw new Error();
const text = await res.text();

urls = text.split('\n')
.map(l => l.trim())
.filter(l => l !== '')
.map(u => {
try {
let p = new URL(u).pathname;
return p.endsWith('/') ? p : p + '/';
} catch(e) { return null; }
})
.filter(p => p && p.includes(RANDOM_CONFIG.PATH_FILTER));

localStorage.setItem(RANDOM_CONFIG.CACHE_KEY, JSON.stringify({ data: urls, timestamp: now }));
}


const current = window.location.pathname.endsWith('/') ? window.location.pathname : window.location.pathname + '/';
const candidates = urls.filter(p => p !== current);

if (candidates.length === 0) {
showNotice('没有发现其他文章,正在返回主页…');
setTimeout(() => location.href = RANDOM_CONFIG.FALLBACK_URL, 1500);
return;
}

const targetPath = candidates[Math.floor(Math.random() * candidates.length)];


const params = new URLSearchParams(window.location.search);
RANDOM_CONFIG.REMOVED_PARAMS.forEach(p => params.delete(p));

const search = params.toString() ? '?' + params.toString() : '';
const finalUrl = targetPath + search + window.location.hash;

showNotice('正在穿越到随机文章…');
setTimeout(() => location.href = finalUrl, 800);

} catch (err) {
console.error('RandomPost Error:', err);
showNotice('跳转失败,正在返回主页…');
setTimeout(() => location.href = RANDOM_CONFIG.FALLBACK_URL, 1500);
}
}

本文参考

版权声明 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 半方池水半方田

封面生成即梦 AI - 图片 5.0 Lite

Prompt扁平2D卡通插画,「随机文章」封面图,颜色鲜明,元素丰富,主次分明,无文字,包含循环箭头和骰子元素,画面活泼有趣

赞助

  • 微信

    微信

  • 支付宝

    支付宝


avatar

wuanqin

只能懂一点点

最新文章

蓝色的结构色