南与 --:--
avatar

南与

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 区域)。拖拽思路:

  1. 找到 canvas 的父容器(position: fixed 且包含 canvas 的 div)
  2. 给它开启 pointer-events: auto
  3. 监听 mousedown / mousemove / mouseup,实时更新 left / bottom
  4. 位移超过 5px 才算拖动,避免误触模型点击动画
container.style.pointerEvents = "auto";
container.addEventListener("mousedown", onDown);
window.addEventListener("mousemove", onMove);
window.addEventListener("mouseup", onUp);
// ... 触摸事件同理

🐱 四、最终效果

  • 左下角黑猫看板娘(可切换白猫)
  • 鼠标悬浮弹出菜单:休眠 / 切换模型 / 关于(GitHub)
  • 模型上方定时冒出提示气泡
  • 按住看板娘可以自由拖到屏幕任意位置
  • 构建后 JS 压缩到 130KB(brotli),对页面性能影响很小

📌 五、经验总结

  1. 第三方组件的默认跳转链接一定要检查——域名劫持比想象中普遍,oml2d.commodel.oml2d.com 都沦陷了
  2. matchMedia("max-width: 768px") 判移动端不可靠,桌面窄窗口会被误伤
  3. 新项目优先看作者的维护状态:l2d-widget 是 oml2d 作者的新作,API 更现代、依赖更少,踩坑更少
  4. 本地化 UMD 脚本(而非 npm 引用)部署更稳,不依赖 CDN 可用性

📎 相关链接:l2d-widget 文档 · GitHub 仓库 · 本博客源码

Astro Live2D 看板娘 l2d-widget 教程