[collapse title=”新增页脚Dev样式 页脚开发历时” color=”indigo”]
<!-- 页脚运行时间 -->
<div class="github-badge-big">
<span class="badge-subject"><i class="fa fa-clock-o"></i> 项目历时:</span>
<span class="badge-value bg-apricots">
<span id="footer_running_days" class="odometer"></span> 天
<span id="footer_running_hours"></span> 小时
<span id="footer_running_mins"></span> 分钟
<span id="footer_running_secs"></span> 秒
</span>
<i class="footer-love-icon2">♥</i>
</div>
<!-- 备案号 放在项目历时下方 -->
<div class="github-badge-big">
<span class="badge-subject"><i class="fa fa-id-card"></i> 备案号 </span>
<a href="https://beian.miit.gov.cn/" target="_blank" one-link-mark="yes">苏ICP备1234567890号</a>
</div>
<script no-pjax="">
// 页脚项目历时(完全同步公告写法)
(function() {
const dEl = document.getElementById("footer_running_days");
const hEl = document.getElementById("footer_running_hours");
const mEl = document.getElementById("footer_running_mins");
const sEl = document.getElementById("footer_running_secs");
if (!dEl) return;
// 这里和你公告的 PROJECT_START_TIME 保持一致
const start = new Date(2026, 3, 20);
function update() {
const diff = Date.now() - start;
const d = Math.floor(diff / 86400000);
const h = Math.floor((diff % 86400000) / 3600000);
const m = Math.floor((diff % 3600000) / 60000);
const s = Math.floor((diff % 60000) / 1000);
dEl.textContent = d;
hEl.textContent = h < 10 ? '0' + h : h;
mEl.textContent = m < 10 ? '0' + m : m;
sEl.textContent = s < 10 ? '0' + s : s;
}
update();
if (!window.footerRunTimeInterval) window.footerRunTimeInterval = setInterval(update, 1000);
})();
// 页脚爱心动画 + 点击飘字
function initFooterLove() {
const loveIcon = document.querySelector(".footer-love-icon2");
const footer = document.getElementById("footer");
if (!loveIcon || !footer) return;
loveIcon.replaceWith(loveIcon.cloneNode(true));
const newLove = document.querySelector(".footer-love-icon2");
Object.assign(newLove.style, {
display: "inline-block",
color: "#ffffff",
fontSize: "18px",
transition: "color 0.3s ease",
cursor: "pointer",
marginLeft: "6px"
});
if (!document.querySelector('#heartBeatStyle')) {
const style = document.createElement("style");
style.id = "heartBeatStyle";
style.textContent = `
@keyframes heartBeatReal2 {
0% { transform: scale(1); }
15% { transform: scale(1.2); }
30% { transform: scale(1); }
45% { transform: scale(1.2); }
60% { transform: scale(1); }
100% { transform: scale(1); }
}
`;
document.head.appendChild(style);
}
footer.addEventListener("mouseenter", () => {
newLove.style.color = "#e62445";
newLove.style.animation = "heartBeatReal2 1.2s ease infinite";
});
footer.addEventListener("mouseleave", () => {
newLove.style.color = "#ffffff";
newLove.style.animation = "none";
});
const random = (min, max) => Math.random() * (max - min) + min;
newLove.addEventListener("click", e => {
e.preventDefault();
window.getSelection?.removeAllRanges?.();
let cur = parseInt(localStorage.getItem("loveClickCount") || 0);
cur++;
localStorage.setItem("loveClickCount", cur);
if (window.updateLoveCount) window.updateLoveCount();
const rect = newLove.getBoundingClientRect();
const pop = document.createElement("span");
pop.innerText = "+1";
Object.assign(pop.style, {
position: "fixed",
left: `${rect.left + rect.width / 2 - 8}px`,
top: `${rect.top - 6}px`,
zIndex: "99999999",
color: "#e62445",
fontWeight: "bold",
fontSize: "16px",
pointerEvents: "none",
opacity: "1"
});
document.body.appendChild(pop);
const moveX = random(-6, 6);
const rotate = random(-25, 25);
const duration = 1200;
const start = performance.now();
function animate() {
const t = performance.now() - start;
const p = Math.min(t / duration, 1);
const k = 1 - Math.pow(1 - p, 3);
pop.style.transform = `translate(${moveX * k}px, ${-35 * k}px) rotate(${rotate * k}deg)`;
pop.style.opacity = 1 - k;
p < 1 ? requestAnimationFrame(animate) : pop.remove();
}
requestAnimationFrame(animate);
});
newLove.addEventListener("mousedown", e => e.preventDefault());
newLove.ondragstart = () => false;
}
document.addEventListener('DOMContentLoaded', initFooterLove);
window.addEventListener('load', initFooterLove);
document.addEventListener('pjax:success', initFooterLove);
document.addEventListener('pjax:end', initFooterLove);
</script>
[/collapse]
[collapse title=”新增公告进度条 公告爱心点赞特效” color=”indigo”]
<!-- ======================================
🔥 【顶部可配置区域 - 改这里就够了】
🧊 进度条颜色:
bg-orange 橙色 | bg-blue 蓝色 | bg-red 红色 | bg-green 绿色
🧊 爱心清零:控制台输入 resetlove()
====================================== -->
<script no-pjax="">
// DDL 死线
const TEXT_TITLE1 = "斩杀线 6月22日";
const PROGRESS_START = [2026, 3, 20];
const PROGRESS_END = [2026, 5, 22];
// DDL进度条颜色
const PROGRESS_BAR_COLOR = "bg-orange";
// 开发进度
const TEXT_TITLE2 = "Demo开发进度";
const DEV_PROGRESS = 30;
const DEV_HOVER_TEXT = "急急急,你别急";
// 开发进度条颜色 直白命名
const DEV_BAR_COLOR = "bg-blue";
// 项目历时
const PROJECT_START_TIME = [2026, 3, 20];
// 全局爱心更新函数(两边共用)
window.updateLoveCount = function() {
const count = localStorage.getItem('loveClickCount') || 0;
window.loveCountState = parseInt(count);
const el = document.getElementById('loveCount');
if (el) el.textContent = count;
};
// 爱心清零
window.resetlove = function() {
if (confirm('确定清零爱心计数?')) {
localStorage.removeItem('loveClickCount');
window.updateLoveCount();
alert('✅ 已清零');
}
};
</script>
<!-- 进度条 + 项目历时 -->
<div class="progress-wrapper" style="padding:0">
<div class="progress-info" style="display:flex;justify-content:space-between;align-items:center">
<div class="progress-label" style="white-space:nowrap;"><script>document.write(TEXT_TITLE1)</script></div>
<div id="yearprogress_text_container">
<span id="yearprogress_progresstext"></span>
<span id="yearprogress_progresstext_full"></span>
</div>
</div>
<div class="progress">
<div id="yearprogress_progressbar" class="progress-bar">
<div class="bubble-container">
<div class="bubble"></div><div class="bubble"></div><div class="bubble"></div>
<div class="bubble"></div><div class="bubble"></div><div class="bubble"></div>
<div class="bubble"></div><div class="bubble"></div><div class="bubble"></div>
<div class="bubble"></div>
</div>
</div>
</div>
</div>
<div class="progress-wrapper" style="padding:0;margin-top:8px;">
<div class="progress-info" style="display:flex;justify-content:space-between;align-items:center">
<div class="progress-label" style="white-space:nowrap;"><script>document.write(TEXT_TITLE2)</script></div>
<!-- 开发进度 悬浮容器 -->
<div id="devprogress_text_container">
<span id="devprogress_progresstext"></span>
<span id="devprogress_progresstext_full"></span>
</div>
</div>
<div class="progress">
<div id="devprogress_progressbar" class="progress-bar">
<div class="bubble-container">
<div class="bubble"></div><div class="bubble"></div><div class="bubble"></div>
<div class="bubble"></div><div class="bubble"></div><div class="bubble"></div>
<div class="bubble"></div><div class="bubble"></div><div class="bubble"></div>
<div class="bubble"></div>
</div>
</div>
</div>
</div>
<!-- 项目历时 + 爱心(两行全部居中) -->
<div class="github-badge-big" style="margin-top:12px;position:relative;text-align:center;">
<span class="badge-subject">项目历时:</span>
<i class="footer-love-icon">♥</i>
<span id="loveCount" class="love-count">0</span>
<!-- 时间单独一行并居中 -->
<span class="badge-value bg-apricots" style="display:block;text-align:center;margin-top:4px;">
<span id="blog_running_days" class="odometer"></span> 天
<span id="blog_running_hours"></span> 小时
<span id="blog_running_mins"></span> 分钟
<span id="blog_running_secs"></span> 秒
</span>
</div>
<script no-pjax="">
// 提交进度(DDL)
(function() {
function refresh() {
const start = new Date(...PROGRESS_START);
const end = new Date(...PROGRESS_END);
const now = new Date();
const total = end - start;
const past = now - start;
let progress = 0;
if (past > 0 && past < total) progress = (past / total * 100).toFixed(5);
else if (past >= total) progress = 100;
const short = parseFloat(progress).toFixed(2);
$("#yearprogress_progresstext").text(short + "%");
$("#yearprogress_progresstext_full").text(progress + "%");
$("#yearprogress_progressbar").css("width", progress + "%");
// 应用直白颜色类名
$("#yearprogress_progressbar").addClass(PROGRESS_BAR_COLOR);
}
refresh();
if (!window.yearProgressInterval) {
window.yearProgressInterval = setInterval(refresh, 500);
}
})();
// 开发进度
(function() {
$("#devprogress_progresstext").text(DEV_PROGRESS + ".00%");
$("#devprogress_progresstext_full").text(DEV_HOVER_TEXT);
$("#devprogress_progressbar").css("width", DEV_PROGRESS + "%");
// 应用直白颜色类名
$("#devprogress_progressbar").addClass(DEV_BAR_COLOR);
})();
// 爱心点击
(function() {
const icon = document.querySelector(".footer-love-icon");
const count = document.getElementById("loveCount");
const box = document.querySelector(".github-badge-big");
if (!icon || !count) return;
// 初始化
window.updateLoveCount();
function rand(a, b) { return Math.random() * (b - a) + a }
function pop() {
const el = document.createElement("span");
el.textContent = "+1";
el.style.cssText = "position:absolute;color:#e62445;font-weight:bold;font-size:16px;pointer-events:none;left:" + (icon.offsetLeft - 5) + "px;top:" + (icon.offsetTop - 5) + "px;opacity:1";
box.appendChild(el);
const x = rand(-8, 8);
const r = rand(-30, 30);
const start = performance.now();
function run() {
const t = performance.now() - start;
const p = Math.min(t / 1200, 1);
const k = 1 - Math.pow(1 - p, 3);
el.style.transform = `translate(${x*k}px,${-35*k}px)rotate(${r*k}deg)`;
el.style.opacity = 1 - k;
if (p < 1) requestAnimationFrame(run);
else el.remove();
}
requestAnimationFrame(run);
}
icon.addEventListener("click", e => {
e.preventDefault();
window.getSelection?.removeAllRanges?.();
// 统一计数逻辑
let cur = parseInt(localStorage.getItem("loveClickCount") || 0);
cur++;
localStorage.setItem("loveClickCount", cur);
// 全局更新
window.updateLoveCount();
pop();
});
icon.addEventListener("mousedown", e => e.preventDefault());
icon.ondragstart = () => false;
})();
// 爱心心跳
(function() {
const card = document.getElementById("leftbar_announcement");
const icon = document.querySelector(".footer-love-icon");
if (!card || !icon) return;
Object.assign(icon.style, {
display: "inline-block", color: "#fff", fontSize: "18px",
transition: "color 0.3s", cursor: "pointer", marginRight: "4px"
});
const style = document.createElement("style");
style.textContent = "@keyframes heartBeatReal{0%{transform:scale(1)}15%{transform:scale(1.2)}30%{transform:scale(1)}45%{transform:scale(1.2)}60%{transform:scale(1)}100%{transform:scale(1)}}";
document.head.appendChild(style);
card.addEventListener("mouseenter", () => { icon.style.color = "#e62445"; icon.style.animation = "heartBeatReal 1.2s infinite" });
card.addEventListener("mouseleave", () => { icon.style.color = "#fff"; icon.style.animation = "none" });
})();
// 项目历时
(function() {
const dEl = document.getElementById("blog_running_days");
const hEl = document.getElementById("blog_running_hours");
const mEl = document.getElementById("blog_running_mins");
const sEl = document.getElementById("blog_running_secs");
if (!dEl) return;
const start = new Date(...PROJECT_START_TIME);
function update() {
const diff = Date.now() - start;
const d = Math.floor(diff / 86400000);
const h = Math.floor((diff % 86400000) / 3600000);
const m = Math.floor((diff % 3600000) / 60000);
const s = Math.floor((diff % 60000) / 1000);
dEl.textContent = d;
hEl.textContent = h < 10 ? '0' + h : h;
mEl.textContent = m < 10 ? '0' + m : m;
sEl.textContent = s < 10 ? '0' + s : s;
}
update();
if (!window.runTimeInterval) window.runTimeInterval = setInterval(update, 1000);
})();
</script>
<style>
/* 自定义直白颜色类 - bg-xxx 一看就懂 */
.bg-orange { background-color: #fd7e14 !important; }
.bg-blue { background-color: #0d6efd !important; }
.bg-red { background-color: #dc3545 !important; }
.bg-green { background-color: #198754 !important; }
.bg-yellow { background-color: #ffc107 !important; }
/* 两个进度条共用悬浮效果 */
#yearprogress_text_container,
#devprogress_text_container{
font-size:14px;color:#333;line-height:22px;text-align:right;width:110px;
height:22px;overflow:hidden;user-select:none
}
#yearprogress_text_container>span,
#devprogress_text_container>span{
transition:transform .3s ease;display:block
}
#yearprogress_text_container:hover>span,
#devprogress_text_container:hover>span{
transform:translateY(-22px)
}
.love-count{font-size:14px;color:#e62445;font-weight:500;margin-right:6px}
.progress{height:12px;border-radius:6px;background:#e9ecef;overflow:hidden}
.progress-bar{position:relative;height:100%;border-radius:6px}
.bubble-container{position:absolute;inset:0;pointer-events:none}
.bubble{position:absolute;bottom:-20px;background:rgba(255,255,255,.35);opacity:.8;animation:bubbleUp linear infinite}
.bubble:nth-child(1){width:3px;height:3px;left:5%;animation-duration:2.2s}
.bubble:nth-child(2){width:5px;height:5px;left:15%;animation-duration:3.8s}
.bubble:nth-child(3){width:4px;height:4px;left:25%;animation-duration:2.6s}
.bubble:nth-child(4){width:6px;height:6px;left:38%;animation-duration:4.2s}
.bubble:nth-child(5){width:3px;height:3px;left:48%;animation-duration:2.9s}
.bubble:nth-child(6){width:5px;height:5px;left:60%;animation-duration:3.5s}
.bubble:nth-child(7){width:4px;height:4px;left:70%;animation-duration:2.4s}
.bubble:nth-child(8){width:6px;height:6px;left:80%;animation-duration:4.5s}
.bubble:nth-child(9){width:3px;height:3px;left:88%;animation-duration:3.1s}
.bubble:nth-child(10){width:4px;height:4px;left:95%;animation-duration:2.7s}
@keyframes bubbleUp{0%{transform:translateY(0)scale(1);opacity:.7}50%{opacity:.9}100%{transform:translateY(-120px)scale(1.1);opacity:0}}
</style>
[/collapse]
[collapse title=”新增主页卡片3D效果” color=”indigo”]
<!--鼠标悬停3D效果start-->
<style>
/* 开启3D空间 */
article.post:not(.post-full),
.shuoshuo-preview-container {
transform-style: preserve-3d !important;
transition: all 0.3s ease;
}
/* 常态:文字不做任何3D偏移 */
article.post:not(.post-full) header.post-header,
article.post:not(.post-full) a.post-title,
article.post:not(.post-full) div.post-meta,
.shuoshuo-preview-container .shuoshuo-title,
.shuoshuo-preview-container .shuoshuo-content {
position: relative !important;
transition: all 0.3s cubic-bezier(.03,.98,.52,.99);
will-change: transform, text-shadow;
/* 初始无3D、无阴影 */
transform: translateZ(0px);
text-shadow: none;
}
/* 🔥 鼠标悬浮卡片时:文字才开启3D上浮 + 立体阴影 */
article.post:not(.post-full):hover header.post-header,
article.post:not(.post-full):hover a.post-title,
article.post:not(.post-full):hover div.post-meta,
.shuoshuo-preview-container:hover .shuoshuo-title,
.shuoshuo-preview-container:hover .shuoshuo-content {
transform: translateZ(30px) !important;
/* 3D立体文字阴影,柔和有层次 */
text-shadow: 0 8px 16px rgba(0,0,0,0.15),
0 4px 8px rgba(0,0,0,0.1);
}
</style>
<script src="https://cdn.jsdelivr.net/gh/huangwb8/bloghelper@latest/js/mobile-detect.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/huangwb8/bloghelper@latest/vanilla3D/vanilla-tilt.js"></script>
<script type="text/javascript">
var md = new MobileDetect(window.navigator.userAgent);
if(!md.phone() && !md.tablet()){
window.pjaxLoaded = function(){
// 销毁旧实例防冲突
document.querySelectorAll("article.post:not(.post-full), .shuoshuo-preview-container").forEach(el => {
if (el.vanillaTilt) el.vanillaTilt.destroy();
});
// 文章卡片3D倾斜
VanillaTilt.init(document.querySelectorAll("article.post:not(.post-full)"),{
reverse:false,
max:4,
startX:0,
startY:0,
perspective:1000,
scale:1.02,
speed:300,
transition:true,
axis:null,
reset:true,
easing:"cubic-bezier(.03,.98,.52,.99)",
glare:true,
"max-glare":0.7,
"glare-prerender":false,
gyroscope:false
});
// 说说卡片3D倾斜
VanillaTilt.init(document.querySelectorAll(".shuoshuo-preview-container"),{
reverse:false, // 是否反转倾斜方向
max:4, // 最大的倾斜角度(度)
startX:0, // X轴上的起始倾斜,单位为度。
startY:0, // Y轴上的起始倾斜,单位为度。
perspective:1000, // 转换角度,越低倾斜越极端
scale:1.02, // 缩放比例,2 = 200%, 1.5 = 150%, 等等..
speed:300, // 进入/退出 过渡的速度
transition:true, // 是否在进入/退出的时候设置过渡效果
xis:null, // 设置禁用哪个轴的反转,值为"x"或者"y"或者null
reset:true, // 设置在退出时清除倾斜效果
easing:"cubic-bezier(.03,.98,.52,.99)", // 设置进入退出时过渡的贝塞尔曲线
glare:true,// 设置是否拥有炫光效果,即透明度渐变效果
"max-glare":0.7, // 设置最大的透明效果,1=100%,0.5=50%
"glare-prerender":false, // false, VanillaTilt为你创建透明炫光元素,否则你需要自己在.jstilt-glare>.js-tilt-glare-inner中自己添加render函数
"mouse-event-element":null, // css选择器或者链接到HTML的元素,他将监听该元素上的鼠标事件
"full-page-listening":false, // 是否监听整个页面的鼠标移动事件,若为true,他将监听这个页面,而非选中元素
gyroscope:false, // 是否开启陀螺仪的方向检测
gyroscopeMinAngleX: 0, //陀螺仪最小角度X
gyroscopeMaxAngleX: 0, //陀螺仪最大角度X
gyroscopeMinAngleY: 0, //陀螺仪最小角度
gyroscopeMaxAngleY: 0, //陀螺仪最大角度
gyroscopeSamples: 10 //陀螺仪样品
});
}
$(window.pjaxLoaded);
$(document)?.on('pjax:end', window.pjaxLoaded);
}
</script>
<!--鼠标悬停3D效果end-->
[/collapse]
[collapse title=”新增鼠标特效” color=”indigo”]
<!--鼠标样式:两个同心圆,大圆追小圆-->
<style type="text/css">
#cursor{position:fixed;width:16px;height:16px;background:#009688;border-radius:8px;opacity:0.25;z-index:10086;pointer-events:none;transition:0.2s ease-in-out;transition-property:background,opacity,transform}
#cursor.hidden{opacity:0}
#cursor.hover{opacity:0.1;transform:scale(2.5)}
#cursor.active{opacity:0.5;transform:scale(0.5)}
#clickME{cursor:pointer;display:inline-block;border:1px solid #009688}
</style>
<script src="https://cdn.jsdelivr.net/gh/huangwb8/bloghelper@latest/js/cursor_01.js"></script>
<!--鼠标样式结束-->
[/collapse]
发表回复