Astro 博客接入 l2d-widget 看板娘:从踩坑到拖拽自由
Astro 博客接入 l2d-widget 看板娘:从踩坑到拖拽自由
给博客加一个会动的 Live2D 看板娘,是很多站长的小心愿。这篇文章记录了我从 oml2d 切换到 l2d-widget 的完整过程——踩了三个大坑(域名劫持、移动端误判、无法拖拽),最后一步步解决,并成功让看板娘可以按住随意拖动。
🔍 一、为什么换掉 oml2d
最早我用的是 oh-my-live2d(oml2d),它是目前文档最全、星标最多的 Live2D 网页组件之一。但实际接入后问题接踵而至:
❌ 坑 1:默认”关于”按钮跳转到垃圾网站
点击看板娘菜单里的”关于”,竟然跳到了一个叫”51吃瓜网”的垃圾站!
排查后发现:oml2d 默认”关于”菜单的 onClick 是 window.open("https://oml2d.com"),而 oml2d.com 域名已经被劫持(和它的模型站 model.oml2d.com 一样),返回的是完全无关的垃圾网页。
// oml2d 源码里的默认"关于"按钮
{ id: "About", onClick() { window.open("https://oml2d.com") } } // ← 域名已被劫持讽刺的是,官网文档里推荐的模型地址
model.oml2d.com也早已失效——返回的不是模型 JSON,而是一个带<!doctype html>的垃圾页面,还缺 CORS 头,浏览器直接拒绝加载。
❌ 坑 2:窄窗口下看板娘直接消失
修好模型后,看板娘还是不出现。折腾了半天,翻源码发现:
// oml2d 用窗口宽度判断"移动端"
rc = window.matchMedia("screen and (max-width: 768px)")
Ba = () => rc.matches ? "mobile" : "pc"
// 当 mobileDisplay: false 且判定为移动端时 → 直接隐藏
get mobileHidden() { return !mobileDisplay && Ba() === "mobile" }也就是说只要浏览器窗口窄于 768px(比如开着 DevTools 侧栏、或者窗口没最大化),看板娘就被判定成”移动端”隐藏了。桌面小窗口用户完全看不到。
❌ 坑 3:看板娘钉死在角落,不能拖动
oml2d 的舞台是 position: fixed 固定左下角,没有内置拖拽。想让它可移动,得自己写一坨事件监听。
✨ 二、发现 l2d-widget
正头疼时,发现 oml2d 作者 hacxy 又出了一个新项目——l2d-widget,号称:
- 零运行时依赖(~500 行源码,纯原生 DOM + CSS Animation)
- 一行集成:
createWidget()完成加载、渲染、交互 - 完整交互:悬浮菜单、提示气泡、逐字打字动画、嘴型驱动
import { createWidget } from 'l2d-widget';
createWidget({
model: { path: 'https://model.hacxy.cn/cat-black/model.json' },
});更关键的是,它的默认”关于”按钮跳转的是 GitHub 官方仓库,没有劫持风险;也不存在 768px 移动端误判问题。
🛠️ 三、接入步骤
1. 本地化脚本(无 npm 也能用)
l2d-widget 的 dist/index.min.js 是 UMD 产物,全局变量 L2D_WIDGET,内置了 Live2D SDK,零外部依赖。把它放到 public/assets/js/l2d-widget/ 即可:
<script src="/assets/js/l2d-widget/index.min.js"></script>2. 配置模型(数组 = 自动开启切换菜单)
在 src/config.ts 中配置模型列表,model 传数组会自动出现”切换模型”菜单:
Live2D: {
enable: true,
position: 'bottom-left',
primaryColor: 'rgba(10, 132, 255, 0.9)',
size: 300,
models: [
{ name: '黑猫', path: 'https://model.hacxy.cn/cat-black/model.json', scale: 1 },
{ name: '白猫', path: 'https://model.hacxy.cn/cat-white/model.json', scale: 1 },
]
}3. 初始化(Astro Layout 全局壳)
我的博客用 swup 做 SPA 切换,Layout 是全局壳只渲染一次,所以看板娘在这里初始化最合适:
window.addEventListener("load", () => {
const widget = window.L2D_WIDGET.createWidget({
model: models.map(m => ({ path: m.path, scale: m.scale })),
position, size, primaryColor,
transitionDuration: 800,
});
});4. 实现拖拽(l2d-widget 也没有内置)
l2d-widget 的容器是 position: fixed 的 div,默认 pointer-events: none(只允许点击 canvas 区域)。拖拽思路:
- 找到 canvas 的父容器(
position: fixed且包含 canvas 的 div) - 给它开启
pointer-events: auto - 监听 mousedown / mousemove / mouseup,实时更新
left/bottom - 位移超过 5px 才算拖动,避免误触模型点击动画
container.style.pointerEvents = "auto";
container.addEventListener("mousedown", onDown);
window.addEventListener("mousemove", onMove);
window.addEventListener("mouseup", onUp);
// ... 触摸事件同理🐱 四、最终效果
- 左下角黑猫看板娘(可切换白猫)
- 鼠标悬浮弹出菜单:休眠 / 切换模型 / 关于(GitHub)
- 模型上方定时冒出提示气泡
- 按住看板娘可以自由拖到屏幕任意位置
- 构建后 JS 压缩到 130KB(brotli),对页面性能影响很小
📌 五、经验总结
- 第三方组件的默认跳转链接一定要检查——域名劫持比想象中普遍,
oml2d.com、model.oml2d.com都沦陷了 matchMedia("max-width: 768px")判移动端不可靠,桌面窄窗口会被误伤- 新项目优先看作者的维护状态:l2d-widget 是 oml2d 作者的新作,API 更现代、依赖更少,踩坑更少
- 本地化 UMD 脚本(而非 npm 引用)部署更稳,不依赖 CDN 可用性
📎 相关链接:l2d-widget 文档 · GitHub 仓库 · 本博客源码
