2026-01-22 21:39:19 +08:00
|
|
|
// 判断是否为移动端
|
|
|
|
|
function isMobile() {
|
|
|
|
|
if (window.navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {
|
|
|
|
|
return true; // 移动端
|
|
|
|
|
} else {
|
|
|
|
|
return false; // PC端
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 文章图片灯箱
|
|
|
|
|
window.ViewImage && ViewImage.init('.post-content img');
|
|
|
|
|
|
|
|
|
|
// Pure JavaScript Back to Top (High Performance)
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
var backToTopButton = document.getElementById('back-to-top');
|
|
|
|
|
if (backToTopButton) {
|
|
|
|
|
var isVisible = false;
|
|
|
|
|
var ticking = false;
|
|
|
|
|
|
|
|
|
|
function update() {
|
|
|
|
|
if (window.scrollY > 300) {
|
|
|
|
|
if (!isVisible) {
|
|
|
|
|
backToTopButton.classList.add('show');
|
|
|
|
|
isVisible = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (isVisible) {
|
|
|
|
|
backToTopButton.classList.remove('show');
|
|
|
|
|
isVisible = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ticking = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.addEventListener('scroll', function() {
|
|
|
|
|
if (!ticking) {
|
|
|
|
|
window.requestAnimationFrame(update);
|
|
|
|
|
ticking = true;
|
|
|
|
|
}
|
|
|
|
|
}, { passive: true });
|
|
|
|
|
|
|
|
|
|
backToTopButton.addEventListener('click', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
window.scrollTo({
|
|
|
|
|
top: 0,
|
|
|
|
|
behavior: 'smooth'
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// loader定时器
|
|
|
|
|
$(document).ready(function () {
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
$("#loader").addClass("hide");
|
|
|
|
|
}, 30000);
|
|
|
|
|
});
|
|
|
|
|
// 点击进入按钮
|
|
|
|
|
$("#closeloader").click(function () {
|
|
|
|
|
$("#loader").addClass("hide");
|
|
|
|
|
});
|
|
|
|
|
// nav栏样式调整
|
|
|
|
|
$('#libabys').first().attr("style", "margin-left: -5px");
|
|
|
|
|
|
|
|
|
|
$('#libabys').eq(1).attr("style", "margin-left: -5px");
|
|
|
|
|
// 友链列表版样式调整
|
|
|
|
|
$('.itp-index:odd').attr("style", "float: right;width:48%;");
|
|
|
|
|
|
|
|
|
|
//文章图片懒加载
|
2026-01-24 18:35:57 +08:00
|
|
|
if (typeof lazyLoadInit === 'function') {
|
|
|
|
|
lazyLoadInit({
|
|
|
|
|
// coverColor: "white",
|
|
|
|
|
// coverDiv: "<div style='display: flex; justify-content: center; align-items: center; height: 200px; color: #000000;'><span>优世界·一个记录生活点滴的小站</span></div>",
|
|
|
|
|
offsetBottom: 800,
|
|
|
|
|
offsetTopm: 800,
|
|
|
|
|
showTime: 1100
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
console.warn('lazyLoadInit is not defined');
|
|
|
|
|
}
|
2026-01-22 21:39:19 +08:00
|
|
|
|
|
|
|
|
async function loadBarrager() {
|
|
|
|
|
try {
|
|
|
|
|
const commentsData = await initArtalkAndGetComments();
|
|
|
|
|
if (commentsData) {
|
|
|
|
|
await createBarragerFromArtalk(commentsData);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('加载弹幕时发生错误:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 异步初始化 Artalk 并获取评论数据
|
|
|
|
|
function initArtalkAndGetComments() {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
Artalk.use((ctx) => {
|
|
|
|
|
ctx.on('list-loaded', () => {
|
|
|
|
|
console.log('评论列表加载完毕');
|
|
|
|
|
const commentsData = ctx.getComments();
|
|
|
|
|
if (commentsData) {
|
|
|
|
|
resolve(commentsData);
|
|
|
|
|
// console.log(commentsData);
|
|
|
|
|
} else {
|
|
|
|
|
reject('获取评论数据失败');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 18:35:57 +08:00
|
|
|
// 从 Artalk 评论数据生成弹幕
|
2026-01-22 21:39:19 +08:00
|
|
|
async function createBarragerFromArtalk(commentsData) {
|
2026-01-24 18:35:57 +08:00
|
|
|
// 确保弹幕容器存在
|
|
|
|
|
const barragerContainer = document.querySelector('.barrager');
|
|
|
|
|
if (!barragerContainer) {
|
|
|
|
|
console.warn('未找到弹幕容器 .barrager');
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-01-23 22:02:11 +08:00
|
|
|
|
2026-01-24 18:35:57 +08:00
|
|
|
// 1. 过滤和处理评论数据 (只保留昵称和内容)
|
|
|
|
|
const barrageList = commentsData.map(comment => {
|
|
|
|
|
// 简单清理 HTML 标签,保留纯文本 (可选)
|
|
|
|
|
const contentText = comment.content.replace(/<[^>]+>/g, "").substring(0, 50); // 限制长度
|
|
|
|
|
return {
|
|
|
|
|
info: contentText, // 弹幕内容
|
|
|
|
|
href: '#', // 链接 (可选,点击弹幕跳转)
|
|
|
|
|
speed: 10 + Math.random() * 5, // 随机速度
|
|
|
|
|
color: '#fff', // 字体颜色 (白色)
|
|
|
|
|
old_ie_color: '#000000', // 旧版 IE 颜色
|
|
|
|
|
};
|
|
|
|
|
}).filter(item => item.info.trim() !== ""); // 过滤空评论
|
|
|
|
|
|
|
|
|
|
// 如果没有评论,则不显示弹幕
|
|
|
|
|
if (barrageList.length === 0) {
|
|
|
|
|
return;
|
2026-01-23 22:02:11 +08:00
|
|
|
}
|
2026-01-22 21:39:19 +08:00
|
|
|
|
2026-01-24 18:35:57 +08:00
|
|
|
// 2. 初始化 jQuery.barrager (如果尚未初始化)
|
|
|
|
|
// 注意:这里假设 jquery.barrager.js 已经加载并挂载到 jQuery 对象上
|
|
|
|
|
// 由于 barrager 插件通常是直接操作 DOM,我们可能需要循环添加
|
|
|
|
|
|
|
|
|
|
// 简单的循环发送弹幕示例 (每隔一段时间发送一条)
|
|
|
|
|
let index = 0;
|
|
|
|
|
const sendBarrage = () => {
|
|
|
|
|
if (index >= barrageList.length) {
|
|
|
|
|
index = 0; // 循环播放
|
|
|
|
|
}
|
|
|
|
|
const item = barrageList[index];
|
|
|
|
|
// 使用 jQuery 选择器调用 barrager
|
|
|
|
|
$('body').barrager(item);
|
|
|
|
|
index++;
|
2026-01-22 21:39:19 +08:00
|
|
|
};
|
2026-01-24 18:35:57 +08:00
|
|
|
|
|
|
|
|
// 每 2 秒发送一条弹幕
|
|
|
|
|
setInterval(sendBarrage, 2000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function fetchHitokoto() {
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch('https://v1.hitokoto.cn/?c=d&c=i'); // 获取句子
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
return data.hitokoto;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取一言失败:', error);
|
|
|
|
|
return null;
|
2026-01-22 21:39:19 +08:00
|
|
|
}
|
2026-01-24 18:35:57 +08:00
|
|
|
}
|
2026-01-22 21:39:19 +08:00
|
|
|
|
2026-01-24 18:35:57 +08:00
|
|
|
// 代码块复制功能
|
2026-01-22 21:39:19 +08:00
|
|
|
function initCodeCopy() {
|
2026-01-24 18:35:57 +08:00
|
|
|
const codeBlocks = document.querySelectorAll('.post-content pre code');
|
|
|
|
|
|
|
|
|
|
codeBlocks.forEach(codeBlock => {
|
|
|
|
|
// 检查是否已经添加了复制按钮,避免重复添加
|
|
|
|
|
if (codeBlock.parentNode.querySelector('.copy-code-btn')) return;
|
2026-01-22 21:39:19 +08:00
|
|
|
|
2026-01-24 18:35:57 +08:00
|
|
|
const pre = codeBlock.parentNode;
|
|
|
|
|
pre.style.position = 'relative';
|
2026-01-22 21:39:19 +08:00
|
|
|
|
2026-01-24 18:35:57 +08:00
|
|
|
const copyBtn = document.createElement('button');
|
|
|
|
|
copyBtn.className = 'copy-code-btn';
|
|
|
|
|
copyBtn.innerHTML = '<i class="fa fa-copy"></i>'; // 使用 FontAwesome 图标
|
|
|
|
|
copyBtn.title = '复制代码';
|
|
|
|
|
|
|
|
|
|
// 样式 (建议放到 CSS 文件中)
|
|
|
|
|
copyBtn.style.position = 'absolute';
|
|
|
|
|
copyBtn.style.top = '5px';
|
|
|
|
|
copyBtn.style.right = '5px';
|
|
|
|
|
copyBtn.style.border = 'none';
|
|
|
|
|
copyBtn.style.background = 'transparent';
|
|
|
|
|
copyBtn.style.color = '#999';
|
|
|
|
|
copyBtn.style.cursor = 'pointer';
|
|
|
|
|
copyBtn.style.padding = '5px';
|
|
|
|
|
copyBtn.style.borderRadius = '4px';
|
|
|
|
|
copyBtn.style.transition = 'all 0.3s';
|
|
|
|
|
|
|
|
|
|
// Hover 效果
|
|
|
|
|
copyBtn.addEventListener('mouseenter', () => {
|
|
|
|
|
copyBtn.style.color = '#333';
|
|
|
|
|
copyBtn.style.background = 'rgba(0,0,0,0.1)';
|
|
|
|
|
});
|
|
|
|
|
copyBtn.addEventListener('mouseleave', () => {
|
|
|
|
|
copyBtn.style.color = '#999';
|
|
|
|
|
copyBtn.style.background = 'transparent';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
copyBtn.addEventListener('click', () => {
|
|
|
|
|
const code = codeBlock.innerText;
|
|
|
|
|
navigator.clipboard.writeText(code).then(() => {
|
|
|
|
|
copyBtn.innerHTML = '<i class="fa fa-check"></i>';
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
copyBtn.innerHTML = '<i class="fa fa-copy"></i>';
|
2026-01-22 21:39:19 +08:00
|
|
|
}, 2000);
|
2026-01-24 18:35:57 +08:00
|
|
|
|
|
|
|
|
Qmsg.success("代码复制成功");
|
|
|
|
|
}).catch(err => {
|
|
|
|
|
console.error('复制失败:', err);
|
|
|
|
|
copyBtn.innerHTML = '<i class="fa fa-times"></i>';
|
|
|
|
|
Qmsg.error("复制失败");
|
2026-01-22 21:39:19 +08:00
|
|
|
});
|
|
|
|
|
});
|
2026-01-24 18:35:57 +08:00
|
|
|
|
|
|
|
|
pre.appendChild(copyBtn);
|
2026-01-22 21:39:19 +08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 页面加载完成后初始化
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
initCodeCopy();
|
2026-01-23 22:02:11 +08:00
|
|
|
initDescriptionHitokoto();
|
2026-01-22 21:39:19 +08:00
|
|
|
});
|
2026-01-23 22:02:11 +08:00
|
|
|
|
|
|
|
|
// 初始化个人描述一言切换
|
|
|
|
|
function initDescriptionHitokoto() {
|
|
|
|
|
const descEl = document.querySelector('.yiyandes');
|
|
|
|
|
if (!descEl) return;
|
|
|
|
|
|
|
|
|
|
descEl.title = '点击切换一言';
|
|
|
|
|
|
|
|
|
|
descEl.addEventListener('click', async () => {
|
|
|
|
|
if (descEl.dataset.loading === 'true') return;
|
|
|
|
|
|
|
|
|
|
descEl.dataset.loading = 'true';
|
|
|
|
|
const originalText = descEl.innerText;
|
|
|
|
|
descEl.innerText = '正在获取灵感...';
|
|
|
|
|
|
|
|
|
|
const hitokoto = await fetchHitokoto();
|
|
|
|
|
|
|
|
|
|
if (hitokoto) {
|
|
|
|
|
typeWriter(descEl, hitokoto);
|
|
|
|
|
} else {
|
|
|
|
|
descEl.innerText = originalText;
|
|
|
|
|
descEl.dataset.loading = 'false';
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 打字机效果
|
|
|
|
|
function typeWriter(element, text, speed = 100) {
|
|
|
|
|
element.innerText = '';
|
|
|
|
|
element.classList.add('typing');
|
|
|
|
|
let i = 0;
|
|
|
|
|
|
|
|
|
|
function type() {
|
|
|
|
|
if (i < text.length) {
|
|
|
|
|
element.innerText += text.charAt(i);
|
|
|
|
|
i++;
|
|
|
|
|
setTimeout(type, speed);
|
|
|
|
|
} else {
|
|
|
|
|
element.dataset.loading = 'false';
|
|
|
|
|
element.classList.remove('typing');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type();
|
|
|
|
|
}
|
2026-01-24 18:35:57 +08:00
|
|
|
|
|
|
|
|
// 友链信息一键复制
|
|
|
|
|
function copySzhContent() {
|
|
|
|
|
var szhElement = document.getElementById('szh');
|
|
|
|
|
if (szhElement) {
|
|
|
|
|
var textToCopy = szhElement.innerText;
|
|
|
|
|
navigator.clipboard.writeText(textToCopy).then(function() {
|
|
|
|
|
Qmsg.success("复制成功");
|
|
|
|
|
}).catch(function(err) {
|
|
|
|
|
console.error('Could not copy text: ', err);
|
|
|
|
|
Qmsg.error("复制失败");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Theme Toggle Logic
|
|
|
|
|
function toggleTheme() {
|
|
|
|
|
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
|
|
|
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
|
|
|
|
document.documentElement.setAttribute('data-theme', newTheme);
|
|
|
|
|
localStorage.setItem('theme', newTheme);
|
|
|
|
|
|
|
|
|
|
// Notify Artalk if present
|
|
|
|
|
if (window.Artalk) {
|
|
|
|
|
Artalk.setDarkMode(newTheme === 'dark');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update Floating Tools Visibility based on current page
|
|
|
|
|
function updateFloatingToolsVisibility() {
|
|
|
|
|
const tools = document.querySelector('.floating-tools');
|
|
|
|
|
if (!tools) return;
|
|
|
|
|
|
|
|
|
|
// Hide on Homepage
|
|
|
|
|
const isHome = window.location.pathname === '/' || window.location.pathname === '/index.html';
|
|
|
|
|
if (isHome) {
|
|
|
|
|
tools.style.display = 'none';
|
|
|
|
|
} else {
|
|
|
|
|
tools.style.display = 'flex';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Hide Comment button if no comments section
|
|
|
|
|
const commentBtn = document.getElementById('to-comments');
|
|
|
|
|
if (commentBtn) {
|
|
|
|
|
const commentsSection = document.getElementById('Comments');
|
|
|
|
|
commentBtn.style.display = commentsSection ? 'flex' : 'none';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Floating Tools Initialization
|
|
|
|
|
function initFloatingTools() {
|
|
|
|
|
// Initial visibility check
|
|
|
|
|
updateFloatingToolsVisibility();
|
|
|
|
|
|
|
|
|
|
// Prevent multiple event bindings
|
|
|
|
|
if (window.floatingToolsInitialized) return;
|
|
|
|
|
window.floatingToolsInitialized = true;
|
|
|
|
|
|
|
|
|
|
// Use Event Delegation for robust handling
|
|
|
|
|
document.addEventListener('click', function(e) {
|
|
|
|
|
// Theme Toggle
|
|
|
|
|
const toggleBtn = e.target.closest('#theme-toggle');
|
|
|
|
|
if (toggleBtn) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
toggleTheme();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Jump to Comments
|
|
|
|
|
const commentBtn = e.target.closest('#to-comments');
|
|
|
|
|
if (commentBtn) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const commentsSection = document.getElementById('Comments');
|
|
|
|
|
if (commentsSection) {
|
|
|
|
|
commentsSection.scrollIntoView({ behavior: 'smooth' });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Theme Toggle (Avatar)
|
|
|
|
|
const avatar = document.querySelector('.head_author_img');
|
|
|
|
|
if (avatar) {
|
|
|
|
|
avatar.addEventListener('click', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
toggleTheme();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Listen for PJAX complete to update visibility
|
|
|
|
|
document.addEventListener('pjax:complete', function() {
|
|
|
|
|
updateFloatingToolsVisibility();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
initFloatingTools();
|
|
|
|
|
});
|