mirror of
https://git.beihong.wang/wangbeihong/blog-source.git
synced 2026-04-24 06:43:05 +08:00
initial
This commit is contained in:
55
usr/themes/HarmonyHues/assets/js/article-toc.js
Executable file
55
usr/themes/HarmonyHues/assets/js/article-toc.js
Executable file
@@ -0,0 +1,55 @@
|
||||
/* ------------------------------------
|
||||
* Harmony Hues主题
|
||||
*
|
||||
* @author 星语社长
|
||||
* @link https://biibii.cn
|
||||
* @update 2024-7-6 18:00:04
|
||||
* --------------------------------- */
|
||||
$(document).ready(function () {
|
||||
// 获取所有标题的锚点元素
|
||||
var headings = $('[id^="cl-"]');
|
||||
// 获取所有目录项
|
||||
var catalogItems = $('.atoc-list a');
|
||||
|
||||
// 设置 active 类的函数
|
||||
setActiveCatalogItem = () => {
|
||||
var scrollPosition = $(window).scrollTop() + 100; // 当前滚动位置 + 100px 偏移
|
||||
|
||||
// 遍历所有标题锚点
|
||||
headings.each(function () {
|
||||
var heading = $(this);
|
||||
var headingId = heading.attr('id'); // 获取标题的 ID
|
||||
var catalogItem = $('a[data-target="' + headingId + '"]'); // 获取对应的目录项
|
||||
|
||||
// 检查当前标题是否在视口中
|
||||
if (heading.offset().top <= scrollPosition) {
|
||||
// 移除所有目录项的 active 类
|
||||
catalogItems.removeClass('active');
|
||||
// 为当前目录项添加 active 类
|
||||
catalogItem.addClass('active');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setActiveCatalogItem(); // 初始化时设置 active 类
|
||||
|
||||
// 监听页面滚动事件
|
||||
$(window).scroll(() => {
|
||||
setActiveCatalogItem();
|
||||
});
|
||||
|
||||
// 不在文章视口消失
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
const $toc = $('.widget-toc-main');
|
||||
entry.isIntersecting ? $toc.show() : $toc.hide();
|
||||
});
|
||||
});
|
||||
|
||||
// 检查目标元素是否存在
|
||||
const targetElement = document.querySelector('#post');
|
||||
if (targetElement) {
|
||||
observer.observe(targetElement);
|
||||
}
|
||||
|
||||
});
|
||||
1
usr/themes/HarmonyHues/assets/js/article-toc.min.js
vendored
Executable file
1
usr/themes/HarmonyHues/assets/js/article-toc.min.js
vendored
Executable file
@@ -0,0 +1 @@
|
||||
$(document).ready(function(){var t=$('[id^="cl-"]'),e=$(".atoc-list a");setActiveCatalogItem=(()=>{var a=$(window).scrollTop()+100;t.each(function(){var t=$(this),o=t.attr("id"),c=$('a[data-target="'+o+'"]');t.offset().top<=a&&(e.removeClass("active"),c.addClass("active"))})}),setActiveCatalogItem(),$(window).scroll(()=>{setActiveCatalogItem()});const a=new IntersectionObserver(t=>{t.forEach(t=>{const e=$(".widget-toc-main");t.isIntersecting?e.show():e.hide()})}),o=document.querySelector("#post");o&&a.observe(o)});
|
||||
39
usr/themes/HarmonyHues/assets/js/codecopy.js
Executable file
39
usr/themes/HarmonyHues/assets/js/codecopy.js
Executable file
@@ -0,0 +1,39 @@
|
||||
/* ------------------------------------
|
||||
* Harmony Hues主题
|
||||
*
|
||||
* @author 星语社长
|
||||
* @link https://biibii.cn
|
||||
* @update 2024-12-19 19:28:41
|
||||
* --------------------------------- */
|
||||
$(document).ready(function () {
|
||||
// 为所有 .pre-copy 按钮绑定点击事件
|
||||
$('.pre-copy').on('click', function () {
|
||||
// 缓存当前按钮和代码内容
|
||||
const $copyButton = $(this);
|
||||
const codeContent = $copyButton.closest('.pre-container').find('code').text();
|
||||
|
||||
// 使用 Clipboard API 复制内容
|
||||
navigator.clipboard.writeText(codeContent)
|
||||
.then(() => {
|
||||
// 复制成功,更新按钮文本
|
||||
$copyButton.text("复制成功");
|
||||
setTimeout(() => $copyButton.text("复制"), 1000); // 1 秒后恢复
|
||||
})
|
||||
.catch((err) => {
|
||||
// 复制失败,尝试使用旧版方法
|
||||
const tempTextarea = $('<textarea>');
|
||||
$('body').append(tempTextarea);
|
||||
tempTextarea.val(codeContent).select();
|
||||
const isSuccess = document.execCommand('copy');
|
||||
tempTextarea.remove();
|
||||
|
||||
if (isSuccess) {
|
||||
$copyButton.text("复制成功");
|
||||
setTimeout(() => $copyButton.text("复制"), 1000);
|
||||
} else {
|
||||
alert('复制失败,请手动复制代码。');
|
||||
console.error('复制失败:', err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
1
usr/themes/HarmonyHues/assets/js/codecopy.min.js
vendored
Executable file
1
usr/themes/HarmonyHues/assets/js/codecopy.min.js
vendored
Executable file
@@ -0,0 +1 @@
|
||||
$(document).ready(function(){$(".pre-copy").on("click",function(){const e=$(this),t=e.closest(".pre-container").find("code").text();navigator.clipboard.writeText(t).then(()=>{e.text("复制成功"),setTimeout(()=>e.text("复制"),1e3)}).catch(o=>{const c=$("<textarea>");$("body").append(c),c.val(t).select();const n=document.execCommand("copy");c.remove(),n?(e.text("复制成功"),setTimeout(()=>e.text("复制"),1e3)):(alert("复制失败,请手动复制代码。"),console.error("复制失败:",o))})})});
|
||||
133
usr/themes/HarmonyHues/assets/js/comment-tools.js
Executable file
133
usr/themes/HarmonyHues/assets/js/comment-tools.js
Executable file
@@ -0,0 +1,133 @@
|
||||
/* ------------------------------------
|
||||
* Harmony Hues主题
|
||||
*
|
||||
* @author 星语社长
|
||||
* @link https://biibii.cn
|
||||
* @update 2024-12-20 22:16:26
|
||||
* --------------------------------- */
|
||||
$(document).ready(function () {
|
||||
// 表情包数据
|
||||
const emojis = [
|
||||
{
|
||||
name: 'Heo',
|
||||
path: '/usr/themes/HarmonyHues/assets/emoji/Heo',
|
||||
list: { '3dyanjing': '3D眼镜', 'lpl': 'LPL加油', 'aoye': '熬夜', 'baozha': '爆炸', 'buhaoyisi': '不好意思', 'qinqin': '亲亲', 'sanbing': '伞兵', 'yiqiangxiao': '倚墙笑', 'toutoukan': '偷偷看', 'zaijian': '再见', 'chujiaren': '出家人', 'jiaban': '加班', 'mianqiangxiao': '勉强笑', 'weixian': '危险', 'fahongbao': '发红包', 'chishou': '吃手', 'chigua': '吃瓜', 'tuxie': '吐血', 'chaojia': '吵架', 'youhou': '呦吼', 'ziyaxiao': '呲牙笑', 'hashiqi': '哈士奇', 'hashiqishiquyishi': '哈士 奇失去意识', 'hashiqishiwang': '哈士奇失望', 'kuqi': '哭泣', 'changge': '唱歌', 'xihuan': '喜欢', 'heiha': '嘿哈', 'daxiao': '大笑', 'shiwang': '失望', 'toutu': '头秃', 'fendou': '奋斗', 'haoqi': '好奇', 'haode': '好的', 'haixiu': '害羞', 'xiaochou': '小丑', 'xiaotou': '小偷', 'ganga': '尴尬', 'yingyuan': '应援', 'kaixin': '开心', 'yinqibushi': '引起不适', 'weixiao': '微笑', 'sikao': '思考', 'exin': '恶心', 'jingxia': '惊吓', 'jingya': '惊讶', 'gandong': '感动', 'fennu': '愤怒', 'wokanhaoni': '我看好你', 'shoujixiangji': '手机相机', 'damie': '打咩', 'dapai': '打牌', 'tuosai': '托腮', 'fue': '扶额', 'koubi': '抠鼻', 'taiyanjing': '抬眼镜', 'wuzuixiao': '捂嘴笑', 'wulian': '捂脸', 'cahan': '擦汗', 'doujiyan': '斗鸡眼', 'zhihuideyanshen': '智慧的眼神', 'yuebing': '月饼', 'youmeiyougaocuo': '有没有搞错', 'leiben': '泪奔', 'shensi': '深思', 'huaji': '滑稽', 'huajiheshui': '滑稽喝水', 'huajinaicha': '滑稽奶茶', 'huajiningmeng': '滑稽柠檬', 'huajikuanghan': '滑稽狂汗', 'huajibeizi': '滑稽被子', 'fannao': '烦恼', 'xiongmao': '熊猫', 'xiongmaochangge': '熊猫唱歌', 'xiongmaoxihuan': '熊猫喜欢', 'xiongmaoshiwang': '熊猫失望', 'niunianjinbao': '牛年进宝', 'goutou': '狗头', 'goutouweibo': '狗头围脖', 'goutoushiwang': '狗头失望', 'goutoupangci': '狗头胖次', 'goutouhua': '狗头花', 'goutoucao': '狗头草', 'zhutou': '猪头', 'shengbing': '生病', 'dianhua': '电话', 'yiwen': '疑问', 'tengtong': '疼痛', 'kanchuanyiqie': '看穿 一切', 'xuanyun': '眩晕', 'shuijiao': '睡觉', 'jinyan': '禁言', 'xiaoku': '笑哭', 'jiujie': '纠结', 'lvmao': '绿帽', 'shuaku': '耍酷', 'huzi': '胡子', 'caigou': '菜狗', 'caigouhua': '菜狗花', 'beida': '被打', 'liekai': '裂开', 'songfu': '送福', 'songhua': '送花', 'yinxian': '阴险', 'nanyizhixin': '难以置信', 'guilian': '鬼脸', 'heixian': '黑线', 'guzhang': '鼓掌' }
|
||||
},
|
||||
{
|
||||
name: 'GIF',
|
||||
path: '/usr/themes/HarmonyHues/assets/emoji/GIF',
|
||||
list: { 'gif_1': '熊猫头流泪表情包', 'gif_2': '向话吗', 'gif_3': "又关我什么事", 'gif_4': "很高兴为你服务", 'gif_5': "你不准玩微信", 'gif_6': "好了,孩子们", 'gif_7': "你有点蔡徐坤", 'gif_8': "蔡徐坤的肯定", 'gif_9': "这人真棒", 'gif_10': "蔡徐坤偷听", 'gif_11': "du瘾发作", 'gif_12': "甄子丹的嘲笑", 'gif_13': "原神启动", 'gif_14': "鲲之蔑视" }
|
||||
}
|
||||
];
|
||||
|
||||
// 获取 DOM 元素
|
||||
const emojiBox = $('.emoji-box');
|
||||
const emojiBtn = $('#emoji-btn');
|
||||
const textarea = $('#textarea')[0];
|
||||
|
||||
// 生成表情包分类和列表
|
||||
const generateEmojis = () => {
|
||||
const emojiBar = $('<ul class="emoji-bar"></ul>');
|
||||
const emojiLists = [];
|
||||
|
||||
// 遍历表情包数据
|
||||
emojis.forEach((category, index) => {
|
||||
const { name, path, list } = category;
|
||||
|
||||
// 创建表情包分类标题
|
||||
emojiBar.append(`<li class="d-inline-block p-2" data-type="${name}" data-index="${index}">${name}</li>`);
|
||||
|
||||
// 创建表情包列表
|
||||
const emojiList = $('<ul class="emoji-dropdown scroll-cover p-2"></ul>').attr('data-type', name);
|
||||
|
||||
// 生成表情包项
|
||||
const emojiItems = Object.entries(list).map(([emojiKey, emojiName]) => {
|
||||
if (name === 'GIF') {
|
||||
return `<li class="emoji-item p-2" data-text="" data-type="${name}"><img class="gif-img lazy" data-original="${path}/${emojiKey}.webp" alt="${emojiName}" title="${emojiName}"></li>`;
|
||||
}
|
||||
|
||||
return `<li class="emoji-item p-2" data-text="${emojiKey}" data-type="${name}"><img class="lazy" data-original="${path}/${emojiKey}.webp" alt="${emojiName}" title="${emojiName}"></li>`;
|
||||
});
|
||||
|
||||
// 将表情包项添加到列表
|
||||
emojiList.append(emojiItems.join(''));
|
||||
emojiLists.push(emojiList);
|
||||
});
|
||||
|
||||
// 将分类标题和列表添加到容器
|
||||
emojiBox.append(emojiLists).append(emojiBar);
|
||||
|
||||
// 默认显示第一个分类的表情包列表
|
||||
emojiBox.find('.emoji-dropdown').hide().first().show();
|
||||
};
|
||||
|
||||
// 插入文本到光标位置
|
||||
const insertTextAtCursor = (textarea, text) => {
|
||||
const startPos = textarea.selectionStart;
|
||||
const endPos = textarea.selectionEnd;
|
||||
const textBefore = textarea.value.substring(0, startPos);
|
||||
const textAfter = textarea.value.substring(endPos, textarea.value.length);
|
||||
const insertedText = text; // 插入的文本
|
||||
textarea.value = textBefore + insertedText + textAfter;
|
||||
textarea.selectionStart = textarea.selectionEnd = startPos + insertedText.length;
|
||||
$(textarea).trigger('change');
|
||||
textarea.focus();
|
||||
};
|
||||
|
||||
// 监听表情按钮点击事件
|
||||
emojiBtn.on('click', function (e) {
|
||||
e.stopPropagation();
|
||||
// 检测是否存在表情包内容
|
||||
if (emojiBox.find('.emoji-bar').length === 0) {
|
||||
generateEmojis(); // 如果不存在,生成表情包内容
|
||||
emojiBox.find('.emoji-bar > li').first().addClass('emoji-active');
|
||||
}
|
||||
$(this).parent().toggleClass('active');
|
||||
$(this).next('.emoji-box').fadeToggle();
|
||||
|
||||
// 重新初始化 LazyLoad
|
||||
$(".emoji-item img.lazy").lazyload({
|
||||
effect: "fadeIn",
|
||||
threshold: 200,
|
||||
load: function () {
|
||||
// 图片加载完成后添加 loaded 类
|
||||
$(this).addClass("loaded");
|
||||
}
|
||||
});
|
||||
|
||||
// 手动触发 LazyLoad 的加载逻辑
|
||||
$(".emoji-item img.lazy").trigger("appear");
|
||||
});
|
||||
|
||||
// 监听表情点击事件
|
||||
emojiBox.on('click', '.emoji-item', function (e) {
|
||||
e.stopPropagation();
|
||||
const emojiText = $(this).attr('data-text'); // 获取表情文本
|
||||
const emojiType = $(this).attr('data-type'); // 获取表情包分类
|
||||
let content = `:(owo=${emojiText})`; // 表情包文本格式
|
||||
if (emojiType === 'GIF') {
|
||||
const emojiName = $(this).find('img').attr('alt'); // 获取GIF表情名称
|
||||
const gifUrl = $(this).find('img').attr('src');
|
||||
content = ``
|
||||
}
|
||||
insertTextAtCursor(textarea, content); // 插入文本
|
||||
emojiBtn.parent().removeClass('active');
|
||||
$(this).closest('.emoji-box').fadeOut();
|
||||
});
|
||||
|
||||
// 监听分类标题点击事件,切换表情包列表
|
||||
emojiBox.on('click', '.emoji-bar li', function () {
|
||||
const type = $(this).data('type');
|
||||
emojiBox.find('.emoji-dropdown').hide(); // 隐藏所有表情包列表
|
||||
emojiBox.find(`.emoji-dropdown[data-type="${type}"]`).show(); // 显示当前分类的表情包列表
|
||||
$(this).addClass('emoji-active').siblings().removeClass('emoji-active'); // 高亮当前分类标题
|
||||
});
|
||||
|
||||
// 监听文档点击事件,隐藏表情框
|
||||
$(document).on('click', function (e) {
|
||||
if (!$(e.target).closest('.emoji-box').length && !$(e.target).is('#emoji-btn')) {
|
||||
$('.emoji-box').fadeOut();
|
||||
emojiBtn.parent().removeClass('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
1
usr/themes/HarmonyHues/assets/js/comment-tools.min.js
vendored
Executable file
1
usr/themes/HarmonyHues/assets/js/comment-tools.min.js
vendored
Executable file
@@ -0,0 +1 @@
|
||||
$(document).ready(function(){const i=[{name:"Heo",path:"/usr/themes/HarmonyHues/assets/emoji/Heo",list:{"3dyanjing":"3D眼镜",lpl:"LPL加油",aoye:"熬夜",baozha:"爆炸",buhaoyisi:"不好意思",qinqin:"亲亲",sanbing:"伞兵",yiqiangxiao:"倚墙笑",toutoukan:"偷偷看",zaijian:"再见",chujiaren:"出家人",jiaban:"加班",mianqiangxiao:"勉强笑",weixian:"危险",fahongbao:"发红包",chishou:"吃手",chigua:"吃瓜",tuxie:"吐血",chaojia:"吵架",youhou:"呦吼",ziyaxiao:"呲牙笑",hashiqi:"哈士奇",hashiqishiquyishi:"哈士 奇失去意识",hashiqishiwang:"哈士奇失望",kuqi:"哭泣",changge:"唱歌",xihuan:"喜欢",heiha:"嘿哈",daxiao:"大笑",shiwang:"失望",toutu:"头秃",fendou:"奋斗",haoqi:"好奇",haode:"好的",haixiu:"害羞",xiaochou:"小丑",xiaotou:"小偷",ganga:"尴尬",yingyuan:"应援",kaixin:"开心",yinqibushi:"引起不适",weixiao:"微笑",sikao:"思考",exin:"恶心",jingxia:"惊吓",jingya:"惊讶",gandong:"感动",fennu:"愤怒",wokanhaoni:"我看好你",shoujixiangji:"手机相机",damie:"打咩",dapai:"打牌",tuosai:"托腮",fue:"扶额",koubi:"抠鼻",taiyanjing:"抬眼镜",wuzuixiao:"捂嘴笑",wulian:"捂脸",cahan:"擦汗",doujiyan:"斗鸡眼",zhihuideyanshen:"智慧的眼神",yuebing:"月饼",youmeiyougaocuo:"有没有搞错",leiben:"泪奔",shensi:"深思",huaji:"滑稽",huajiheshui:"滑稽喝水",huajinaicha:"滑稽奶茶",huajiningmeng:"滑稽柠檬",huajikuanghan:"滑稽狂汗",huajibeizi:"滑稽被子",fannao:"烦恼",xiongmao:"熊猫",xiongmaochangge:"熊猫唱歌",xiongmaoxihuan:"熊猫喜欢",xiongmaoshiwang:"熊猫失望",niunianjinbao:"牛年进宝",goutou:"狗头",goutouweibo:"狗头围脖",goutoushiwang:"狗头失望",goutoupangci:"狗头胖次",goutouhua:"狗头花",goutoucao:"狗头草",zhutou:"猪头",shengbing:"生病",dianhua:"电话",yiwen:"疑问",tengtong:"疼痛",kanchuanyiqie:"看穿 一切",xuanyun:"眩晕",shuijiao:"睡觉",jinyan:"禁言",xiaoku:"笑哭",jiujie:"纠结",lvmao:"绿帽",shuaku:"耍酷",huzi:"胡子",caigou:"菜狗",caigouhua:"菜狗花",beida:"被打",liekai:"裂开",songfu:"送福",songhua:"送花",yinxian:"阴险",nanyizhixin:"难以置信",guilian:"鬼脸",heixian:"黑线",guzhang:"鼓掌"}},{name:"GIF",path:"/usr/themes/HarmonyHues/assets/emoji/GIF",list:{gif_1:"熊猫头流泪表情包",gif_2:"向话吗",gif_3:"又关我什么事",gif_4:"很高兴为你服务",gif_5:"你不准玩微信",gif_6:"好了,孩子们",gif_7:"你有点蔡徐坤",gif_8:"蔡徐坤的肯定",gif_9:"这人真棒",gif_10:"蔡徐坤偷听",gif_11:"du瘾发作",gif_12:"甄子丹的嘲笑",gif_13:"原神启动",gif_14:"鲲之蔑视"}}],a=$(".emoji-box"),o=$("#emoji-btn"),n=$("#textarea")[0],e=()=>{const o=$('<ul class="emoji-bar"></ul>'),n=[];i.forEach((i,a)=>{const{name:e,path:t,list:s}=i;o.append(`<li class="d-inline-block p-2" data-type="${e}" data-index="${a}">${e}</li>`);const u=$('<ul class="emoji-dropdown scroll-cover p-2"></ul>').attr("data-type",e),g=Object.entries(s).map(([i,a])=>"GIF"===e?`<li class="emoji-item p-2" data-text="" data-type="${e}"><img class="gif-img lazy" data-original="${t}/${i}.webp" alt="${a}" title="${a}"></li>`:`<li class="emoji-item p-2" data-text="${i}" data-type="${e}"><img class="lazy" data-original="${t}/${i}.webp" alt="${a}" title="${a}"></li>`);u.append(g.join("")),n.push(u)}),a.append(n).append(o),a.find(".emoji-dropdown").hide().first().show()},t=(i,a)=>{const o=i.selectionStart,n=i.selectionEnd,e=i.value.substring(0,o),t=i.value.substring(n,i.value.length),s=a;i.value=e+s+t,i.selectionStart=i.selectionEnd=o+s.length,$(i).trigger("change"),i.focus()};o.on("click",function(i){i.stopPropagation(),0===a.find(".emoji-bar").length&&(e(),a.find(".emoji-bar > li").first().addClass("emoji-active")),$(this).parent().toggleClass("active"),$(this).next(".emoji-box").fadeToggle(),$(".emoji-item img.lazy").lazyload({effect:"fadeIn",threshold:200,load:function(){$(this).addClass("loaded")}}),$(".emoji-item img.lazy").trigger("appear")}),a.on("click",".emoji-item",function(i){i.stopPropagation();const a=$(this).attr("data-text"),e=$(this).attr("data-type");let s=`:(owo=${a})`;if("GIF"===e){const i=$(this).find("img").attr("alt"),a=$(this).find("img").attr("src");s=``}t(n,s),o.parent().removeClass("active"),$(this).closest(".emoji-box").fadeOut()}),a.on("click",".emoji-bar li",function(){const i=$(this).data("type");a.find(".emoji-dropdown").hide(),a.find(`.emoji-dropdown[data-type="${i}"]`).show(),$(this).addClass("emoji-active").siblings().removeClass("emoji-active")}),$(document).on("click",function(i){$(i.target).closest(".emoji-box").length||$(i.target).is("#emoji-btn")||($(".emoji-box").fadeOut(),o.parent().removeClass("active"))})});
|
||||
755
usr/themes/HarmonyHues/assets/js/harmonyhues.js
Executable file
755
usr/themes/HarmonyHues/assets/js/harmonyhues.js
Executable file
@@ -0,0 +1,755 @@
|
||||
/* ------------------------------------
|
||||
* Harmony Hues主题
|
||||
*
|
||||
* @author 星语社长
|
||||
* @link https://biibii.cn
|
||||
* @update 2024-7-6 18:00:04
|
||||
* --------------------------------- */
|
||||
$(document).ready(function () {
|
||||
// 使用防抖技术优化事件
|
||||
const debounce = (func, wait) => {
|
||||
var timeout;
|
||||
return function () {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function () {
|
||||
func.apply(context, args);
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
// 节流函数,减少滚动事件触发频率
|
||||
const throttle = (func, wait) => {
|
||||
let timeout = null;
|
||||
return function () {
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(() => {
|
||||
func.apply(this, arguments);
|
||||
timeout = null;
|
||||
}, wait);
|
||||
}
|
||||
};
|
||||
};
|
||||
/*---------------------点击“回到顶部”按钮时平滑滚动到顶部st---------------------*/
|
||||
$('#nav-backtop').click(function () {
|
||||
$('html, body').animate({ scrollTop: 0 }, 200);
|
||||
return false;
|
||||
});
|
||||
/*---------------------点击“回到顶部”按钮时平滑滚动到顶部end---------------------*/
|
||||
|
||||
/*---------------------夜间模式切换事件st---------------------*/
|
||||
const THEMES = {
|
||||
LIGHT: 'light',
|
||||
DARK: 'dark',
|
||||
SYSTEM: 'system'
|
||||
};
|
||||
|
||||
// 设置主题
|
||||
function setTheme(theme = THEMES.LIGHT) {
|
||||
let effectiveTheme = theme;
|
||||
|
||||
if (theme === THEMES.SYSTEM) {
|
||||
effectiveTheme = getSystemTheme(); // 获取系统主题
|
||||
}
|
||||
|
||||
$('html').attr('data-theme', effectiveTheme);
|
||||
setCookie('theme', theme, 7); // 过期时间为 7 天
|
||||
setCookie('system_theme', effectiveTheme, 1); // 过期时间为 1 天
|
||||
}
|
||||
|
||||
// 获取系统主题
|
||||
function getSystemTheme() {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? THEMES.DARK : THEMES.LIGHT;
|
||||
}
|
||||
|
||||
// 设置 Cookie
|
||||
function setCookie(name, value, days) {
|
||||
const expires = new Date();
|
||||
expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
|
||||
document.cookie = `${name}=${value}; expires=${expires.toUTCString()}; path=/`;
|
||||
}
|
||||
|
||||
// 按钮点击事件
|
||||
$('.theme-toggle').on('click', 'button', function () {
|
||||
const theme = $(this).attr('title');
|
||||
switch (theme) {
|
||||
case '浅色模式':
|
||||
setTheme(THEMES.LIGHT);
|
||||
break;
|
||||
case '深色模式':
|
||||
setTheme(THEMES.DARK);
|
||||
break;
|
||||
case '跟随系统':
|
||||
setTheme(THEMES.SYSTEM);
|
||||
break;
|
||||
}
|
||||
setActiveButton($(this));
|
||||
});
|
||||
|
||||
// 设置激活按钮
|
||||
function setActiveButton(button) {
|
||||
$('.theme-toggle button').removeClass('active');
|
||||
button.addClass('active');
|
||||
}
|
||||
|
||||
// 初始化时设置激活按钮
|
||||
function initActiveButton() {
|
||||
const currentTheme = getCookie('theme') || THEMES.LIGHT;
|
||||
let activeButton;
|
||||
if (currentTheme === THEMES.LIGHT) {
|
||||
activeButton = $('.theme-toggle button[title="浅色模式"]');
|
||||
} else if (currentTheme === THEMES.DARK) {
|
||||
activeButton = $('.theme-toggle button[title="深色模式"]');
|
||||
} else if (currentTheme === THEMES.SYSTEM) {
|
||||
activeButton = $('.theme-toggle button[title="跟随系统"]');
|
||||
} else {
|
||||
activeButton = $('.theme-toggle button[title="浅色模式"]');
|
||||
}
|
||||
setActiveButton(activeButton);
|
||||
}
|
||||
|
||||
// 获取 Cookie
|
||||
function getCookie(name) {
|
||||
const cookies = document.cookie.split(';');
|
||||
for (let cookie of cookies) {
|
||||
const [cookieName, cookieValue] = cookie.trim().split('=');
|
||||
if (cookieName === name) {
|
||||
return cookieValue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 初始化
|
||||
initActiveButton();
|
||||
|
||||
// 监听系统主题变化
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
setTheme(THEMES.SYSTEM);
|
||||
});
|
||||
/*---------------------夜间模式切换事件end---------------------*/
|
||||
|
||||
/*---------------------滚动事件st---------------------*/
|
||||
// 滚动进度条
|
||||
const updateScrollProgress = () => {
|
||||
const scrollTop = $(window).scrollTop();
|
||||
const docHeight = $(document).height();
|
||||
const winHeight = $(window).height();
|
||||
const scrollPercent = Math.round((scrollTop / (docHeight - winHeight)) * 100);
|
||||
if (scrollPercent > 0) {
|
||||
$('#nav-backtop').toggleClass('top-to-active', scrollPercent >= 90);
|
||||
$('.back-to-top').show();
|
||||
$('#nav-backtop>.top-to-text').text(scrollPercent >= 90 ? "回到顶部" : scrollPercent);
|
||||
} else {
|
||||
$('.back-to-top').hide();
|
||||
}
|
||||
}
|
||||
// 滚动Nav背景
|
||||
let $isNav = false;
|
||||
if ($('#navbar').hasClass('nav-ui-one')) {
|
||||
$isNav = true;
|
||||
}
|
||||
toggleNavOnScroll = (navSelector, classOne, classTwo, scrollThreshold = 100) => {
|
||||
if ($isNav) { return; }
|
||||
|
||||
const $nav = $(navSelector);
|
||||
const currentScrollTop = $(this).scrollTop();
|
||||
|
||||
if (currentScrollTop > scrollThreshold) {
|
||||
// 向下滚动超过阈值,切换到 classOne
|
||||
if ($nav.hasClass(classTwo)) {
|
||||
$nav.removeClass(classTwo).addClass(classOne);
|
||||
}
|
||||
} else {
|
||||
// 回到顶部,切换到 classTwo
|
||||
if ($nav.hasClass(classOne)) {
|
||||
$nav.removeClass(classOne).addClass(classTwo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时更新进度
|
||||
updateScrollProgress();
|
||||
toggleNavOnScroll('#navbar', 'nav-ui-one', 'nav-ui-two', 100);
|
||||
/*---------------------滚动事件end---------------------*/
|
||||
|
||||
/*---------------------滚动进事件集合st---------------------*/
|
||||
$(window).scroll(function () {
|
||||
/*滚动进度条*/
|
||||
throttle(updateScrollProgress(), 100);
|
||||
/*滚动Nav背景*/
|
||||
throttle(toggleNavOnScroll('#navbar', 'nav-ui-one', 'nav-ui-two', 50), 100);
|
||||
});
|
||||
/*---------------------滚动进事件集合end---------------------*/
|
||||
|
||||
/*---------------------手机端导航栏st---------------------*/
|
||||
let startY = 0;
|
||||
let currentY = 0;
|
||||
let dragging = false;
|
||||
|
||||
// 点击菜单按钮打开/关闭侧边栏
|
||||
$('#menu-line').click(function (event) {
|
||||
event.stopPropagation();
|
||||
const $navComponents = $('#nav-components');
|
||||
|
||||
// 如果导航组件已经存在,则关闭它
|
||||
if ($navComponents.length) {
|
||||
closeSidebar();
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取导航组件元素
|
||||
const $mobileNav = $('#mobile-nav');
|
||||
|
||||
// 添加背景虚化
|
||||
$mobileNav.append(`<div id="mobile-nav-bg" class="pop-tool-overlay-bg"></div>`);
|
||||
|
||||
// 克隆导航内容
|
||||
const navContent = $('.nav-inner > ul').clone();
|
||||
|
||||
// 添加样式
|
||||
navContent.find('.sub-menu').addClass('mt-1');
|
||||
navContent.find('.sub-menu>ul').addClass('row p-1 ml-2');
|
||||
navContent.find('.sub-menu>ul>li').addClass('col-4 p-1');
|
||||
navContent.find('.nav-item').addClass('pb-3');
|
||||
navContent.find('.nav-item>.nav-a').addClass('font-weight-bold');
|
||||
navContent.find('.nav-item>.nav-a').prepend('<i class="iconfont icon-xingqiu font-weight-normal mr-1"></i>');
|
||||
|
||||
// 创建导航组件
|
||||
$mobileNav.append(`<div id="nav-components" class="mobile-aside px-3 py-2"><div class="mx-auto"><i class="back-box mb-2"></i></div><div id="mobile-close-btn" class="mobile-close-btn m-2"><i class="iconfont icon-guanbi"></i></div>${navContent.prop('outerHTML')}</div>`);
|
||||
|
||||
// 延迟添加 .open 类,确保动画生效
|
||||
requestAnimationFrame(() => {
|
||||
$('#mobile-nav-bg').css({
|
||||
'opacity': '1',
|
||||
'visibility': 'visible',
|
||||
'transform': 'rotate(0) scale(1)'
|
||||
});
|
||||
$('#nav-components').addClass('open');
|
||||
});
|
||||
|
||||
// body关闭滚动
|
||||
$('body').css('overflow', 'hidden');
|
||||
});
|
||||
|
||||
// 点击文档关闭侧边栏(如果点击区域不在侧边栏内)
|
||||
$(document).click(function (event) {
|
||||
if ($('#nav-components').hasClass('open') && !$(event.target).closest('#nav-components').length && !$(event.target).closest('#menu-line').length) {
|
||||
closeSidebar();
|
||||
}
|
||||
});
|
||||
|
||||
// 阻止侧边栏内部点击事件冒泡
|
||||
$('#nav-components').click(function (event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// 触摸开始时记录初始位置
|
||||
$(document).on('touchstart', function (event) {
|
||||
if ($('#nav-components').hasClass('open')) {
|
||||
startY = event.originalEvent.touches[0].pageY;
|
||||
currentY = startY;
|
||||
dragging = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 触摸移动时更新侧边栏位置
|
||||
$(document).on('touchmove', function (event) {
|
||||
if (dragging) {
|
||||
currentY = event.originalEvent.touches[0].pageY;
|
||||
const offset = currentY - startY;
|
||||
if (offset > 0) {
|
||||
$('#nav-components').css('transform', `translateY(${offset}px)`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 触摸结束时判断是否关闭侧边栏
|
||||
$(document).on('touchend', function () {
|
||||
if (dragging) {
|
||||
const offset = currentY - startY;
|
||||
const threshold = $('#nav-components').height() / 2;
|
||||
|
||||
if (offset > threshold) {
|
||||
closeSidebar();
|
||||
} else {
|
||||
$('#nav-components').css('transform', '');
|
||||
}
|
||||
dragging = false;
|
||||
}
|
||||
});
|
||||
|
||||
// 点击关闭按钮关闭侧边栏
|
||||
$(document).on('click', '#mobile-close-btn', function () {
|
||||
closeSidebar();
|
||||
});
|
||||
|
||||
// 关闭侧边栏的函数
|
||||
const closeSidebar = () => {
|
||||
const $navComponents = $('#nav-components');
|
||||
const $mobileNavBg = $('#mobile-nav-bg');
|
||||
|
||||
// 移除 open 类并添加关闭动画
|
||||
$navComponents.removeClass('open');
|
||||
|
||||
// 淡出背景
|
||||
$mobileNavBg.css({
|
||||
'opacity': 0,
|
||||
'visibility': 'hidden'
|
||||
});
|
||||
|
||||
// 动画结束后清理侧边栏
|
||||
$navComponents.one('transitionend', function () {
|
||||
$navComponents.remove();
|
||||
$mobileNavBg.remove();
|
||||
$('body').css('overflow', '');
|
||||
});
|
||||
};
|
||||
/*---------------------手机端导航栏end---------------------*/
|
||||
|
||||
/*---------------------搜索框按钮开始---------------------*/
|
||||
// 点击搜索按钮时,显示搜索面板
|
||||
$('#search-btn').click(function () {
|
||||
$('.main-search').addClass('open');
|
||||
$('body').css('overflow', 'hidden');
|
||||
});
|
||||
|
||||
// 点击搜索关闭按钮时,隐藏搜索面板
|
||||
$('.search-box').on('click', '#search-close-btn', function () {
|
||||
$('.main-search').removeClass('open');
|
||||
$('body').css('overflow', '');
|
||||
});
|
||||
/*---------------------搜索框按钮结束---------------------*/
|
||||
|
||||
/*---------------------通用面板函数开始---------------------*/
|
||||
// 生成二维码
|
||||
const generateQRCodeBase64 = (text, size = 200) => {
|
||||
// 创建临时容器
|
||||
const container = document.createElement('div');
|
||||
|
||||
// 生成二维码
|
||||
$(container).qrcode({
|
||||
text: text,
|
||||
width: size,
|
||||
height: size
|
||||
});
|
||||
|
||||
// 获取canvas元素
|
||||
const canvas = container.querySelector('canvas');
|
||||
if (!canvas) {
|
||||
console.error("二维码生成失败:未创建canvas元素");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// 转换为Base64
|
||||
return canvas.toDataURL('image/png');
|
||||
} catch (error) {
|
||||
console.error("Base64转换失败:", error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// 创建不同类型的面板
|
||||
const createPanel = (type, content, closeBtnId) => {
|
||||
return $('<div class="main-' + type + '">' +
|
||||
'<div class="pop-tool-overlay-bg"></div>' +
|
||||
'<div class="card p-2 p-md-4 pop-tool-box ' + type + '-box no-animation">' +
|
||||
content + (type == 'poster' ? '' : '<div id="' + closeBtnId + '" class="close-btn"><i class="iconfont icon-guanbi"></i></div>') +
|
||||
'</div>' +
|
||||
'</div>');
|
||||
};
|
||||
|
||||
// 显示面板
|
||||
const showPanel = (panelSelector, createFunc) => {
|
||||
if ($(panelSelector).length === 0) {
|
||||
$('body').append(createFunc());
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
$(panelSelector).addClass('open');
|
||||
$('body').css('overflow', 'hidden');
|
||||
});
|
||||
};
|
||||
|
||||
// 隐藏并移除面板
|
||||
const hidePanel = (panel) => {
|
||||
panel.removeClass('open');
|
||||
$('body').css('overflow', '');
|
||||
setTimeout(function () {
|
||||
panel.remove();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// 点击关闭按钮时,隐藏对应的面板
|
||||
$(document).on('click', '.close-btn,.pop-close-btn', function () {
|
||||
const panel = $(this).closest('.main-poster, .main-reward, .main-share');
|
||||
hidePanel(panel);
|
||||
});
|
||||
|
||||
// 搜索框+赞赏面板+分享面板,点击文档其他地方时,隐藏赞赏面板
|
||||
$(document).click(function (event) {
|
||||
const $target = $(event.target);
|
||||
// 隐藏搜索框
|
||||
if (!$target.closest('.search-box, #search-btn').length && $('.search-box').is(':visible')) {
|
||||
$('.main-search').removeClass('open');
|
||||
$('body').css('overflow', '');
|
||||
}
|
||||
// 隐藏海报面板
|
||||
if (!$target.closest('.poster-box, #poster-btn, .down-btn-box').length && $('.poster-box').is(':visible')) {
|
||||
hidePanel($('.main-poster'));
|
||||
}
|
||||
// 隐藏赞赏面板
|
||||
if (!$target.closest('.reward-box, #reward-btn').length && $('.reward-box').is(':visible')) {
|
||||
hidePanel($('.main-reward'));
|
||||
}
|
||||
// 隐藏分享面板
|
||||
if (!$target.closest('.share-box, #share-btn').length && $('.share-box').is(':visible')) {
|
||||
hidePanel($('.main-share'));
|
||||
}
|
||||
});
|
||||
|
||||
// 防止事件冒泡
|
||||
$(document).click(function (event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
/*---------------------通用面板函数结束---------------------*/
|
||||
/*---------------------海报按钮开始---------------------*/
|
||||
// 创建海报面板
|
||||
const createPosterBox = () => {
|
||||
// 获取当前日期
|
||||
var weekdays = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
|
||||
var currentDate = new Date();
|
||||
var day = currentDate.getDate();
|
||||
const formattedDay = (day < 10) ? '0' + day : day;
|
||||
const dayOfWeek = currentDate.getDay();
|
||||
|
||||
// 获取文章一些信息
|
||||
const _ARTICLE_LOGO_URL = $('#logo>img').attr('src');
|
||||
const _ARTICLE_AUTHOR = $('.author-left>name>a').first().text();
|
||||
const _ARTICLE_CATEGORY = $('.post-category > a').first().text();
|
||||
|
||||
return createPanel('poster',
|
||||
`<div id="posterCapture" class="poster-post-box p-3">
|
||||
<div class="poster-cover"><img src="${decodeURIComponent(_ARTICLE_COVER_URL)}" /></div>
|
||||
<div class="poster-content d-flex flex-row align-items-start mt-4">
|
||||
<div class="poster-date text-center px-2 py-1 flex-shrink-0">
|
||||
<div style="font-size: 1rem;color:red;">${weekdays[dayOfWeek]}</div>
|
||||
<div class="font-weight-bold" style="font-size:1.5rem;">${formattedDay}</div>
|
||||
</div>
|
||||
<div class="poster-post-content flex-grow-1">
|
||||
<h5 class="poster-post-title font-weight-bold">${decodeURIComponent(_ARTICLE_NAME)}</h5>
|
||||
<p class="poster-post-text m-0">作者:${_ARTICLE_AUTHOR} | 分类:${_ARTICLE_CATEGORY}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="poster-footer d-flex flex-row justify-content-between align-items-center p-2 mt-4" style="color:var(--poster-text-color);">
|
||||
<div class="poster-footer-left">
|
||||
<div><img style="width:auto;height:25px;" src="${_ARTICLE_LOGO_URL}"> | 文章海报</div>
|
||||
<div style="font-size:0.9rem;">扫码识别前往查看更多内容👉</div>
|
||||
</div>
|
||||
<div class="poster-footer-right flex-shrink-0">
|
||||
<img style="height:50px;" src="${generateQRCodeBase64(decodeURIComponent(_ARTICLE_URL))}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="down-btn-box">
|
||||
<div class="post-tools d-flex justify-content-center">
|
||||
<div class="post-tools-item"><button class="btn" id="poster-download-btn" title="保存海报"><i class="iconfont icon-baocun"></i></button></div>
|
||||
<div class="post-tools-item"><button class="btn pop-close-btn" id="poster-close-btn" title="关闭海报"><i class="iconfont icon-guanbi"></i></button></div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
'poster-close-btn'
|
||||
);
|
||||
};
|
||||
|
||||
// 点击海报按钮时,显示海报面板
|
||||
$('#poster-btn').click(function () {
|
||||
showPanel('.main-poster', createPosterBox);
|
||||
});
|
||||
|
||||
// 保存海报
|
||||
$(document).on('click', '#poster-download-btn', function () {
|
||||
htmlToImage.toPng(document.querySelector("#posterCapture")).then(function (dataUrl) {
|
||||
var link = document.createElement('a');
|
||||
link.download = decodeURIComponent(_ARTICLE_NAME) + '-海报图片.png';
|
||||
link.href = dataUrl;
|
||||
link.click();
|
||||
});
|
||||
});
|
||||
/*---------------------海报按钮结束---------------------*/
|
||||
|
||||
/*---------------------赞赏按钮开始---------------------*/
|
||||
// 创建赞赏面板
|
||||
const createRewardBox = () => {
|
||||
return createPanel('reward',
|
||||
'<div class="reward-content d-flex justify-content-center">' +
|
||||
'<div class="reward-qr d-flex flex-column align-items-center"><img src="' + decodeURIComponent(_WXQR) + '" atl="微信支付" /><span>微信</span></div>' +
|
||||
'<div class="reward-qr d-flex flex-column align-items-center"><img src="' + decodeURIComponent(_ZFBQR) + '" atl="支付宝支付" /><span>支付宝</span></div>' +
|
||||
'</div>',
|
||||
'reward-close-btn'
|
||||
);
|
||||
};
|
||||
|
||||
// 点击赞赏按钮时,显示赞赏面板
|
||||
$('#reward-btn').click(function () {
|
||||
showPanel('.main-reward', createRewardBox);
|
||||
});
|
||||
/*---------------------赞赏按钮结束---------------------*/
|
||||
|
||||
/*---------------------分享按钮开始---------------------*/
|
||||
const baseUrls = {
|
||||
qq: "http://connect.qq.com/widget/shareqq/index.html?url=",
|
||||
weibo: "http://service.weibo.com/share/share.php?url=",
|
||||
twitter: "https://twitter.com/intent/tweet?url=",
|
||||
wechat: "javascript:void(0);"
|
||||
};
|
||||
|
||||
// 创建分享面板
|
||||
const createShareBox = () => {
|
||||
return createPanel('share',
|
||||
'<p class="p-2">' + decodeURIComponent(_ARTICLE_URL) + '</p>' +
|
||||
'<div class="share-a d-flex flex-row justify-content-center">' +
|
||||
'<a class="share-item d-flex align-items-center justify-content-center" href="' + baseUrls.qq + decodeURIComponent(_ARTICLE_URL) + '&title=' + decodeURIComponent(_ARTICLE_NAME) + '" title="QQ分享"><i class="iconfont icon-qq"></i></a>' +
|
||||
'<a class="share-item d-flex align-items-center justify-content-center" href="' + baseUrls.weibo + decodeURIComponent(_ARTICLE_URL) + '&title=' + decodeURIComponent(_ARTICLE_NAME) + '" title="微博分享"><i class="iconfont icon-weibo"></i></a>' +
|
||||
'<a class="share-item d-flex align-items-center justify-content-center" href="' + baseUrls.twitter + decodeURIComponent(_ARTICLE_URL) + '&text=' + decodeURIComponent(_ARTICLE_NAME) + '" title="推特分享"><i class="iconfont icon-tuite"></i></a>' +
|
||||
'<a id="share-wechat" class="share-item d-flex align-items-center justify-content-center" href="' + baseUrls.wechat + '" title="朋友圈分享"><i class="iconfont icon-pengyouquan"></i></a>' +
|
||||
'<a id="share-zdyqr" class="share-item d-flex align-items-center justify-content-center" href="' + baseUrls.wechat + '" title="生成二维码"><i class="iconfont icon-erweima"></i></a>' +
|
||||
'</div>',
|
||||
'share-close-btn'
|
||||
);
|
||||
};
|
||||
|
||||
// 点击分享按钮时,显示分享面板
|
||||
$('#share-btn').click(function () {
|
||||
showPanel('.main-share', createShareBox);
|
||||
});
|
||||
|
||||
// 通用二维码切换函数
|
||||
function toggleQRCode(buttonId, qrClass, titleText) {
|
||||
const otherClass = qrClass === 'wechat-qrcode' ? 'zdyqr-qrcode' : 'wechat-qrcode';
|
||||
|
||||
$(document).on('click', buttonId, function () {
|
||||
const $qrElement = $(`.${qrClass}`);
|
||||
const $otherElement = $(`.${otherClass}`);
|
||||
const $shareBox = $('.share-box');
|
||||
|
||||
if ($qrElement.length) {
|
||||
$qrElement.remove();
|
||||
} else {
|
||||
// 移除另一种二维码
|
||||
$otherElement.remove();
|
||||
|
||||
// 生成二维码HTML
|
||||
const articleUrl = decodeURIComponent(_ARTICLE_URL);
|
||||
const qrHTML = `
|
||||
<div class="${qrClass} text-center my-4">
|
||||
<img src="${generateQRCodeBase64(articleUrl)}"
|
||||
alt="分享二维码"
|
||||
title="${encodeURIComponent(_ARTICLE_NAME)}">
|
||||
<div class="mt-2">${titleText}</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$shareBox.append(qrHTML);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化两种二维码切换
|
||||
toggleQRCode('#share-wechat', 'wechat-qrcode', '微信扫码分享');
|
||||
toggleQRCode('#share-zdyqr', 'zdyqr-qrcode', '扫码分享');
|
||||
/*---------------------分享按钮结束---------------------*/
|
||||
|
||||
/*---------------------动态计时器开始---------------------*/
|
||||
/**
|
||||
* 数字跳动动画函数(jQuery版)
|
||||
* @param {Object} options 配置选项
|
||||
* @param {number} options.start - 起始值
|
||||
* @param {number} options.end - 结束值
|
||||
* @param {string} options.selector - jQuery选择器
|
||||
* @param {number} [options.duration=1500] - 动画时长(ms)
|
||||
* @param {function} [options.easing] - 缓动函数
|
||||
* @param {function} [options.format] - 数字格式化函数
|
||||
*/
|
||||
const animateNumber = (options) => {
|
||||
const config = $.extend({
|
||||
duration: 1500,
|
||||
easing: t => t * (2 - t), // easeOutQuad
|
||||
format: n => n.toLocaleString()
|
||||
}, options);
|
||||
|
||||
const $element = $(config.selector);
|
||||
if (!$element.length) {
|
||||
console.error('元素未找到:', config.selector);
|
||||
return;
|
||||
}
|
||||
|
||||
let startTime = null;
|
||||
const range = config.end - config.start;
|
||||
const isLargeNumber = Math.abs(range) > 10000;
|
||||
|
||||
const animate = timestamp => {
|
||||
startTime = startTime || timestamp;
|
||||
const elapsed = timestamp - startTime;
|
||||
const progress = Math.min(elapsed / config.duration, 1);
|
||||
const eased = config.easing(progress);
|
||||
|
||||
let current = config.start + range * eased;
|
||||
|
||||
// 大数字优化处理
|
||||
if (isLargeNumber) {
|
||||
const remaining = config.end - current;
|
||||
current = Math.abs(remaining) > 1000
|
||||
? config.end - remaining * (1 + Math.random() / 3)
|
||||
: current;
|
||||
}
|
||||
|
||||
$element.text(config.format(Math.floor(current)));
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(animate);
|
||||
} else {
|
||||
$element.text(config.format(config.end));
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
/*---------------------动态计时器结束---------------------*/
|
||||
/*---------------------懒加载开始---------------------*/
|
||||
// 基础配置
|
||||
var lazyLoadConfig = {
|
||||
effect: "fadeIn",
|
||||
threshold: 200,
|
||||
container: window,
|
||||
failure_limit: 30
|
||||
};
|
||||
|
||||
// 通用加载处理函数
|
||||
function handleLazyLoad(loadedClass, removedClass) {
|
||||
return function () {
|
||||
$(this).addClass(loadedClass).removeClass(removedClass);
|
||||
};
|
||||
}
|
||||
|
||||
// 初始化懒加载
|
||||
$("img.lazy").lazyload($.extend({}, lazyLoadConfig, {
|
||||
load: handleLazyLoad("loaded", "lazy")
|
||||
}));
|
||||
|
||||
$(".hh-widget img.widget-lazy").lazyload($.extend({}, lazyLoadConfig, {
|
||||
load: handleLazyLoad("loaded", "widget-lazy")
|
||||
}));
|
||||
/*---------------------懒加载结束---------------------*/
|
||||
/*---------------------顶部导航栏滚动隐藏与显示开始---------------------*/
|
||||
let lastScrollTop = 0;
|
||||
const navbar = $("#navbar");
|
||||
const sidebarSticky = $(".sidebar-sticky");
|
||||
const scrollThreshold = 100; // 滚动阈值设为100px
|
||||
|
||||
$(window).scroll(function () {
|
||||
const currentScroll = $(this).scrollTop();
|
||||
|
||||
// 当滚动距离小于阈值时强制显示导航栏
|
||||
if (currentScroll < scrollThreshold) {
|
||||
navbar.removeClass("nav-hidden").addClass("nav-visible");
|
||||
lastScrollTop = currentScroll;
|
||||
return;
|
||||
}
|
||||
|
||||
// 滚动方向判断
|
||||
if (Math.abs(currentScroll - lastScrollTop) > 5) { // 增加5px容差防止误判
|
||||
if (currentScroll > lastScrollTop) {
|
||||
// 向下滚动超过阈值时隐藏
|
||||
navbar.removeClass("nav-visible").addClass("nav-hidden");
|
||||
sidebarSticky.addClass("visible-top");
|
||||
} else {
|
||||
// 向上滚动时立即显示
|
||||
navbar.removeClass("nav-hidden").addClass("nav-visible");
|
||||
sidebarSticky.removeClass("visible-top");
|
||||
}
|
||||
}
|
||||
lastScrollTop = currentScroll;
|
||||
});
|
||||
/*---------------------顶部导航栏滚动隐藏与显示结束---------------------*/
|
||||
/*---------------------一些插件集合str---------------------*/
|
||||
// 动画延迟函数
|
||||
function applyAnimationDelay(selector, delayFactor) {
|
||||
$(selector).each(function (index) {
|
||||
var delay = (index * delayFactor) + 's';
|
||||
$(this).css('animation-delay', delay);
|
||||
});
|
||||
}
|
||||
|
||||
// 导航栏菜单动画
|
||||
applyAnimationDelay('.nav-menu>.nav-item', 0.15);
|
||||
|
||||
// 侧边栏添加动画,但不包括具有 .no-animation 类的元素
|
||||
applyAnimationDelay('.hh-widget:not(.no-animation)', 0.3);
|
||||
|
||||
// 选择所有.card元素,但不包括具有 .no-animation 类的元素
|
||||
applyAnimationDelay('.card:not(.no-animation)', 0.3);
|
||||
|
||||
// 友情链接添加动画
|
||||
applyAnimationDelay('.links-card', 0.3);
|
||||
|
||||
// 轮播图
|
||||
if (typeof Swiper !== 'undefined') {
|
||||
var indexSwiper = new Swiper('.swiper-container', {
|
||||
direction: 'horizontal', // 水平切换
|
||||
loop: true, // 循环模式
|
||||
autoplay: 5000, // 自动轮播间隔时间
|
||||
speed: 1000, // 切换速度
|
||||
autoplayDisableOnInteraction: false, // 用户操作swiper之后,是否禁止autoplay。默认为true:停止。
|
||||
pagination: '.swiper-pagination', // 分页器
|
||||
paginationClickable: true, // 分页器可点击
|
||||
prevButton: '.swiper-button-prev', // 上一页
|
||||
nextButton: '.swiper-button-next', // 下一页
|
||||
roundLengths: true, // 将slide的宽和高取整,以防止某些分辨率的屏幕上出现模糊
|
||||
parallax: true, // 开启视差效果
|
||||
lazyLoading: true, // 懒加载
|
||||
});
|
||||
|
||||
$('.swiper-container').mouseenter(function () {
|
||||
indexSwiper.stopAutoplay();
|
||||
}).mouseleave(function () {
|
||||
indexSwiper.startAutoplay();
|
||||
});
|
||||
|
||||
$('.swiper-container').hover(function () {
|
||||
indexSwiper.stopAutoplay();
|
||||
}, function () {
|
||||
indexSwiper.startAutoplay();
|
||||
});
|
||||
}
|
||||
|
||||
// 灯箱
|
||||
if (typeof ViewImage !== 'undefined') {
|
||||
window.ViewImage && ViewImage.init('.post-content img[show-img],.comment-list img');
|
||||
}
|
||||
|
||||
// SVG图标
|
||||
showSvg();
|
||||
|
||||
// 首页底部时间之旅
|
||||
if ($('.timejourney-progress').length > 0) {
|
||||
// 元素存在,获取 data-percentage 属性值
|
||||
var percentage = $('.timejourney-progress').data('percentage');
|
||||
const percentageNum = percentage ? percentage : 0;
|
||||
|
||||
// 设置进度条的宽度
|
||||
$('.timejourney-progress').css({
|
||||
'width': percentageNum + '%',
|
||||
'transition': 'width ' + (percentageNum / 10 + 1) + 's ease-in-out'
|
||||
});
|
||||
|
||||
// 动态计时器
|
||||
animateNumber({
|
||||
start: 0,
|
||||
end: percentageNum,
|
||||
duration: (percentageNum / 10 * 1000 + 1500),
|
||||
selector: '#timejourney-progress',
|
||||
format: n => `${n}%`
|
||||
});
|
||||
}
|
||||
/*---------------------一些插件集合end---------------------*/
|
||||
});
|
||||
1
usr/themes/HarmonyHues/assets/js/harmonyhues.min.js
vendored
Executable file
1
usr/themes/HarmonyHues/assets/js/harmonyhues.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
73
usr/themes/HarmonyHues/assets/js/svg-icon.js
Executable file
73
usr/themes/HarmonyHues/assets/js/svg-icon.js
Executable file
File diff suppressed because one or more lines are too long
3
usr/themes/HarmonyHues/assets/js/svg-icon.min.js
vendored
Executable file
3
usr/themes/HarmonyHues/assets/js/svg-icon.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user