Files
blog-code/public/pio/static/pio.js
2025-12-08 01:03:07 +08:00

360 lines
9.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ----
# Pio Plugin
# By: Dreamer-Paul
# Last Update: 2022.8.12
一个支持更换 Live2D 模型的 JS 插件
本代码为奇趣保罗原创,并遵守 GPL 2.0 开源协议。欢迎访问我的博客https://paugram.com
---- */
var Paul_Pio = function (prop) {
const current = {
idol: 0,
timeout: undefined,
menu: document.querySelector(".pio-container .pio-action"),
canvas: document.getElementById("pio"),
body: document.querySelector(".pio-container"),
root: document.location.origin + "/",
};
// 工具通用函数
const tools = {
// 创建内容
create: (tag, options) => {
const el = document.createElement(tag);
options.class && (el.className = options.class);
return el;
},
// 随机内容
rand: (arr) => {
return arr[Math.floor(Math.random() * arr.length + 1) - 1];
},
// 是否为移动设备
isMobile: () => {
let ua = window.navigator.userAgent.toLowerCase();
ua = ua.indexOf("mobile") || ua.indexOf("android") || ua.indexOf("ios");
return window.innerWidth < 500 || ua !== -1;
},
};
const elements = {
home: tools.create("span", { class: "pio-home" }),
skin: tools.create("span", { class: "pio-skin" }),
info: tools.create("span", { class: "pio-info" }),
night: tools.create("span", { class: "pio-night" }),
close: tools.create("span", { class: "pio-close" }),
dialog: tools.create("div", { class: "pio-dialog" }),
show: tools.create("div", { class: "pio-show" }),
};
current.body.appendChild(elements.dialog);
current.body.appendChild(elements.show);
/* - 方法 */
const modules = {
// 更换模型
idol: () => {
current.idol < prop.model.length - 1
? current.idol++
: (current.idol = 0);
return current.idol;
},
// 创建对话框方法
message: (text, options = {}) => {
const { dialog } = elements;
if (text.constructor === Array) {
dialog.innerText = tools.rand(text);
} else if (text.constructor === String) {
dialog[options.html ? "innerHTML" : "innerText"] = text;
} else {
dialog.innerText = "输入内容出现问题了 X_X";
}
dialog.classList.add("active");
current.timeout = clearTimeout(current.timeout) || undefined;
current.timeout = setTimeout(() => {
dialog.classList.remove("active");
}, options.time || 3000);
},
// 移除方法
destroy: () => {
this.initHidden();
localStorage.setItem("posterGirl", "0");
},
};
this.destroy = modules.destroy;
this.message = modules.message;
/* - 提示操作 */
const action = {
// 欢迎
welcome: () => {
if (document.referrer && document.referrer.includes(current.root)) {
const referrer = document.createElement("a");
referrer.href = document.referrer;
if (prop.content.referer) {
modules.message(
prop.content.referer.replace(/%t/, `${referrer.hostname}`),
);
} else {
modules.message(`欢迎来自 “${referrer.hostname}” 的朋友!`);
}
} else if (prop.tips) {
let text,
hour = new Date().getHours();
if (hour > 22 || hour <= 5) {
text = "你是夜猫子呀?这么晚还不睡觉,明天起的来嘛";
} else if (hour > 5 && hour <= 8) {
text = "早上好!";
} else if (hour > 8 && hour <= 11) {
text = "上午好!工作顺利嘛,不要久坐,多起来走动走动哦!";
} else if (hour > 11 && hour <= 14) {
text = "中午了,工作了一个上午,现在是午餐时间!";
} else if (hour > 14 && hour <= 17) {
text = "午后很容易犯困呢,今天的运动目标完成了吗?";
} else if (hour > 17 && hour <= 19) {
text = "傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~";
} else if (hour > 19 && hour <= 21) {
text = "晚上好,今天过得怎么样?";
} else if (hour > 21 && hour <= 23) {
text = "已经这么晚了呀,早点休息吧,晚安~";
} else {
text = "奇趣保罗说:这个是无法被触发的吧,哈哈";
}
modules.message(text);
} else {
modules.message(prop.content.welcome || "欢迎来到本站!");
}
},
// 触摸
touch: () => {
current.canvas.onclick = () => {
modules.message(
prop.content.touch || [
"你在干什么?",
"再摸我就报警了!",
"HENTAI!",
"不可以这样欺负我啦!",
],
);
};
},
// 右侧按钮
buttons: () => {
// 返回首页 - 使用 Swup 无刷新跳转
elements.home.onclick = () => {
// 检查 Swup 是否可用
if (typeof window !== "undefined" && window.swup) {
try {
// 使用 Swup 进行无刷新跳转
window.swup.navigate("/");
} catch (error) {
console.error("Swup navigation failed:", error);
// 降级到普通跳转
location.href = current.root;
}
} else {
// Swup 不可用时使用普通跳转
location.href = current.root;
}
};
elements.home.onmouseover = () => {
modules.message(prop.content.home || "点击这里回到首页!");
};
current.menu.appendChild(elements.home);
// 更换模型
if (prop.model && prop.model.length > 1) {
elements.skin.onclick = () => {
loadlive2d("pio", prop.model[modules.idol()]);
prop.content.skin &&
modules.message(prop.content.skin[1] || "新衣服真漂亮~");
};
elements.skin.onmouseover = () => {
prop.content.skin &&
modules.message(prop.content.skin[0] || "想看看我的新衣服吗?");
};
current.menu.appendChild(elements.skin);
}
// 关于我
elements.info.onclick = () => {
window.open(
prop.content.link ||
"https://paugram.com/coding/add-poster-girl-with-plugin.html",
);
};
elements.info.onmouseover = () => {
modules.message("想了解更多关于我的信息吗?");
};
current.menu.appendChild(elements.info);
// 夜间模式
if (prop.night) {
elements.night.onclick = () => {
typeof prop.night === "function" ? prop.night() : eval(prop.night);
};
elements.night.onmouseover = () => {
modules.message("夜间点击这里可以保护眼睛呢");
};
current.menu.appendChild(elements.night);
}
// 关闭看板娘
elements.close.onclick = () => {
modules.destroy();
};
elements.close.onmouseover = () => {
modules.message(prop.content.close || "QWQ 下次再见吧~");
};
current.menu.appendChild(elements.close);
},
// 自定义选择器
custom: () => {
prop.content.custom.forEach((item) => {
const el = document.querySelectorAll(item.selector);
if (!el.length) return;
for (let i = 0; i < el.length; i++) {
if (item.type === "read") {
el[i].onmouseover = (ev) => {
const text = ev.currentTarget.title || ev.currentTarget.innerText;
modules.message("想阅读 %t 吗?".replace(/%t/, "“" + text + "”"));
};
} else if (item.type === "link") {
el[i].onmouseover = (ev) => {
const text = ev.currentTarget.title || ev.currentTarget.innerText;
modules.message(
"想了解一下 %t 吗?".replace(/%t/, "“" + text + "”"),
);
};
} else if (item.text) {
el[i].onmouseover = () => {
modules.message(t.text);
};
}
}
});
},
};
/* - 运行 */
const begin = {
static: () => {
current.body.classList.add("static");
},
fixed: () => {
action.touch();
action.buttons();
},
draggable: () => {
action.touch();
action.buttons();
const body = current.body;
const location = {
x: 0,
y: 0,
};
const mousedown = (ev) => {
const { offsetLeft, offsetTop } = ev.currentTarget;
location.x = ev.clientX - offsetLeft;
location.y = ev.clientY - offsetTop;
document.addEventListener("mousemove", mousemove);
document.addEventListener("mouseup", mouseup);
};
const mousemove = (ev) => {
body.classList.add("active");
body.classList.remove("right");
body.style.left = ev.clientX - location.x + "px";
body.style.top = ev.clientY - location.y + "px";
body.style.bottom = "auto";
};
const mouseup = () => {
body.classList.remove("active");
document.removeEventListener("mousemove", mousemove);
};
body.onmousedown = mousedown;
},
};
// 运行
this.init = (noModel) => {
// 未隐藏 + 非手机版,出现操作功能
if (!(prop.hidden && tools.isMobile())) {
if (!noModel) {
action.welcome();
loadlive2d("pio", prop.model[0]);
}
switch (prop.mode) {
case "static":
begin.static();
break;
case "fixed":
begin.fixed();
break;
case "draggable":
begin.draggable();
break;
}
prop.content.custom && action.custom();
}
};
// 隐藏状态
this.initHidden = () => {
// ! 清除预设好的间距
if (prop.mode === "draggable") {
current.body.style.top = null;
current.body.style.left = null;
current.body.style.bottom = null;
}
current.body.classList.add("hidden");
elements.dialog.classList.remove("active");
elements.show.onclick = () => {
current.body.classList.remove("hidden");
localStorage.setItem("posterGirl", "1");
this.init();
};
};
localStorage.getItem("posterGirl") === "0" ? this.initHidden() : this.init();
};
// 请保留版权说明
if (window.console && window.console.log) {
console.log(
"%c Pio %c https://paugram.com ",
"color: #fff; margin: 1em 0; padding: 5px 0; background: #673ab7;",
"margin: 1em 0; padding: 5px 0; background: #efefef;",
);
}