[{"content":"最近把博客从 Hexo 换成了 Hugo，顺便重新设计了一下构建和部署流程。趁热乎记录一下，也方便以后自己查。\n先说结论：整体流程 简单来说就是这么个事儿：\n我写 Markdown → 推到 GitHub → Actions 自动编译 → 服务器拉取 → Cloudflare 加速 画个图更清楚：\n本地写文章 (Markdown) ↓ git push GitHub main 分支 ↓ 触发 Actions GitHub Actions 编译 ↓ 生成静态文件 gh-pages 分支 ↓ 服务器 git pull Nginx 托管静态文件 ↓ Cloudflare CDN 缓存加速 ↓ 用户访问 为啥要搞这么复杂？主要是不想每次改个错别字都要登服务器手动操作。\n为啥选 Hugo 之前用的 Hexo，没啥大毛病，但有几个痒点：\nnpm 依赖太多了。每次 CI 光装依赖就得好一会儿，偶尔还会出点版本冲突的幺蛾子 本地预览慢。文章多了之后，热更新明显变卡 想尝尝鲜。Hugo 用 Go 写的，据说快得离谱 实际用下来，确实快。本地预览基本秒开，GitHub Actions 那边构建也就几秒钟的事。\nGitHub Actions：自动化构建 这是整套流程的核心。配置文件在 .github/workflows/hugo.yml，做的事情也简单：\nname: Build Hugo Site on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - name: 装 Hugo run: | wget -O hugo.deb https://github.com/gohugoio/hugo/releases/... sudo dpkg -i hugo.deb - name: 拉代码 uses: actions/checkout@v4 with: submodules: recursive # 主题是 submodule - name: 编译 run: hugo --gc --minify - name: 推到 gh-pages uses: peaceiris/actions-gh-pages@v4 with: publish_dir: ./public publish_branch: gh-pages - name: 顺手清一下 CDN 缓存 run: curl -X POST \u0026#34;https://api.cloudflare.com/...\u0026#34; ... 每次 push 到 main 分支，Actions 就自动跑这一套。成功之后，编译好的静态文件就躺在 gh-pages 分支里了。\n双分支策略 这个设计我挺满意的：\nmain 分支：源代码，Markdown 文件 + 主题配置 gh-pages 分支：编译产物，纯静态文件 好处是服务器上不用装 Hugo，直接拉 gh-pages 就能用。万一哪天想换个部署方式，也方便。\n服务器这边 服务器就做两件事：\n定时（或手动）从 gh-pages 拉最新的静态文件 Nginx 伺候着 Nginx 配置没啥特别的，主要是加了点缓存和压缩：\nserver { listen 80; server_name blog.kkkk24juastin.asia; root /var/www/blog; # 压缩 gzip on; gzip_types text/css application/javascript text/html; # 静态资源缓存久一点 location ~* \\.(css|js|png|jpg|woff2)$ { expires 1y; add_header Cache-Control \u0026#34;public, immutable\u0026#34;; } } 更新脚本也就几行：\n#!/bin/bash cd /var/www/blog git fetch origin gh-pages git reset --hard origin/gh-pages 扔 crontab 里定时跑，或者配个 webhook 触发都行。\nCloudflare 加速 最后挂了层 Cloudflare，主要图几个好处：\n全球 CDN。访客能从就近节点拿缓存，不用每次都回源 免费 SSL。懒得自己折腾证书 DDoS 防护。虽然我这小破站应该没人会打 不过有个坑：Cloudflare 默认不缓存 HTML 页面。对于静态博客来说这太亏了，得手动加个 Cache Rule，让它把 HTML 也缓存上。\n配置好之后，访问速度从之前的 2 秒多降到了几十毫秒，效果立竿见影。\n实际效果 优化前后的对比：\n指标 之前 现在 首字节时间 (TTFB) 2.28s ~50ms 页面加载 3.5s 0.8s 主要提升来自 CDN 缓存。代码层面其实已经没啥可优化的了，瓶颈都在网络延迟。\n一些碎碎念 整套流程跑下来，最爽的是真的不用操心部署了。写完文章，commit + push，等个几十秒，刷新页面就能看到更新。\n当然也有不爽的地方。Hugo 的模板语法（Go Template）用起来不太顺手，文档也比较散。不过忍忍就好，毕竟主题配好了基本不用改。\n如果你也在折腾博客，希望这篇能有点帮助。有问题可以留言，看到会回的 👋\n","permalink":"https://web.943827561.xyz/posts/hugo-blog-architecture/","summary":"\u003cp\u003e最近把博客从 Hexo 换成了 Hugo，顺便重新设计了一下构建和部署流程。趁热乎记录一下，也方便以后自己查。\u003c/p\u003e\n\u003ch2 id=\"先说结论整体流程\"\u003e先说结论：整体流程\u003c/h2\u003e\n\u003cp\u003e简单来说就是这么个事儿：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e我写 Markdown → 推到 GitHub → Actions 自动编译 → 服务器拉取 → Cloudflare 加速\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e画个图更清楚：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e本地写文章 (Markdown)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        ↓ git push\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eGitHub main 分支\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        ↓ 触发 Actions\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eGitHub Actions 编译\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        ↓ 生成静态文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egh-pages 分支\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        ↓ 服务器 git pull\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eNginx 托管静态文件\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        ↓ \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eCloudflare CDN 缓存加速\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        ↓\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e用户访问\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e为啥要搞这么复杂？主要是不想每次改个错别字都要登服务器手动操作。\u003c/p\u003e\n\u003ch2 id=\"为啥选-hugo\"\u003e为啥选 Hugo\u003c/h2\u003e\n\u003cp\u003e之前用的 Hexo，没啥大毛病，但有几个痒点：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003enpm 依赖太多了\u003c/strong\u003e。每次 CI 光装依赖就得好一会儿，偶尔还会出点版本冲突的幺蛾子\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e本地预览慢\u003c/strong\u003e。文章多了之后，热更新明显变卡\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e想尝尝鲜\u003c/strong\u003e。Hugo 用 Go 写的，据说快得离谱\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e实际用下来，确实快。本地预览基本秒开，GitHub Actions 那边构建也就几秒钟的事。\u003c/p\u003e","title":"聊聊这个博客是怎么跑起来的"},{"content":"起因 前两天觉得博客打开有点慢，但也没太在意。今天闲着没事，拿 curl 测了一下，好家伙，首字节时间（TTFB）居然要 2.28 秒：\ncurl -s -o /dev/null -w \u0026#34;TTFB: %{time_starttransfer}s\\n\u0026#34; https://blog.kkkk24juastin.asia/ # 输出：TTFB: 2.280466s 这也太离谱了。明明挂着 Cloudflare CDN，怎么还这么慢？\n排查过程 先看看响应头：\ncurl -sI https://blog.kkkk24juastin.asia/ | grep -i cache # 输出： # cf-cache-status: DYNAMIC # cache-control: max-age=3600 看到 cf-cache-status: DYNAMIC 我就懂了。\n这玩意的意思是 Cloudflare 压根没缓存这个页面，每次访问都要回源到我的服务器。而我的服务器在国外，网络延迟加上 TLS 握手，2 秒多其实不算意外。\n问题出在哪 Cloudflare 有个\u0026quot;特性\u0026quot;：默认不缓存 HTML 页面。\n它的逻辑是 HTML 通常是动态生成的，不适合缓存。但对于静态博客来说，HTML 就是静态文件啊，为啥不能缓存？\n解决方案 需要手动加一条 Cache Rule，告诉 Cloudflare：这个域名下的 HTML 也给我缓存上。\n操作步骤：\n登录 Cloudflare Dashboard 选你的域名 进 Caching → Cache Rules 创建规则： 匹配条件: 主机名 = blog.kkkk24juastin.asia 缓存设置: - 符合缓存条件: 是 - 边缘 TTL: 1 个月 - 浏览器 TTL: 1 天 保存，等几分钟生效。\n效果验证 再跑一遍：\n# 第一次，预热缓存 curl -s -o /dev/null -w \u0026#34;TTFB: %{time_starttransfer}s\\n\u0026#34; https://blog.kkkk24juastin.asia/ # TTFB: 1.1s（回源了） # 第二次，缓存命中 curl -s -o /dev/null -w \u0026#34;TTFB: %{time_starttransfer}s\\n\u0026#34; https://blog.kkkk24juastin.asia/ # TTFB: 0.045s # 确认缓存状态 curl -sI https://blog.kkkk24juastin.asia/ | grep cf-cache-status # cf-cache-status: HIT 从 2.28s 降到 45ms，提升了 98%。\n舒服了。\n还做了啥 既然都折腾了，顺手做了几个小优化：\n1. 确认 Brotli 压缩开了 在 Cloudflare 的 Speed → Optimization 里，确保 Brotli 是开着的。比 Gzip 压缩率更高。\n2. 加了资源预加载 在 extend_head.html 里加了 DNS 预解析：\n\u0026lt;link rel=\u0026#34;dns-prefetch\u0026#34; href=\u0026#34;//fonts.googleapis.com\u0026#34;\u0026gt; \u0026lt;link rel=\u0026#34;preconnect\u0026#34; href=\u0026#34;https://fonts.googleapis.com\u0026#34; crossorigin\u0026gt; 3. 构建时自动清缓存 在 GitHub Actions 里加了一步，每次部署完自动清 Cloudflare 缓存：\n- name: 清缓存 run: | curl -X POST \u0026#34;https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/purge_cache\u0026#34; \\ -H \u0026#34;Authorization: Bearer $CF_API_TOKEN\u0026#34; \\ --data \u0026#39;{\u0026#34;purge_everything\u0026#34;:true}\u0026#39; 这样每次更新文章，CDN 会立刻拉取最新内容。\n总结 对于静态博客来说，优化的重点不在代码层面（Hugo 已经够快了），而是让 CDN 真正发挥作用。\n如果你的博客也挂着 Cloudflare 但还是慢，先检查一下 cf-cache-status 是不是 HIT。不是的话，多半是缓存规则没配好。\n就这样，收工。\n","permalink":"https://web.943827561.xyz/posts/hugo-blog-speed-optimization-v2/","summary":"从 2.28s 优化到 50ms，原来问题出在 Cloudflare 没缓存 HTML","title":"博客加载太慢？我是这样排查和解决的"},{"content":"发现问题 博客搭建完成后，访问时总觉得有点卡。打开 Chrome DevTools 看了下 Network 面板，发现几个问题：\n图片没有做懒加载，首屏就加载了所有图片 HTML/CSS/JS 文件可以进一步压缩 没有利用好浏览器缓存 外部资源（如字体）请求有延迟 既然发现了问题，那就一个个解决。\nHugo 构建优化 深度压缩配置 Hugo 自带 minify 功能，但默认配置比较保守。在 hugo.toml 中可以配置更激进的压缩选项：\n[minify] disableXML = true minifyOutput = true [minify.tdewolff] [minify.tdewolff.css] keepCSS2 = false precision = 0 [minify.tdewolff.html] keepDocumentTags = true keepEndTags = true keepQuotes = false keepWhitespace = false [minify.tdewolff.js] keepVarNames = false precision = 0 [minify.tdewolff.json] keepNumbers = false precision = 0 [minify.tdewolff.svg] keepComments = false precision = 0 这个配置使用了 tdewolff/minify 库的参数，可以对各类资源做深度压缩：\nCSS: 移除不必要的空格、简化数值精度 HTML: 移除空白、可选引号 JS: 压缩变量名 SVG: 移除注释、简化数值 构建缓存 重复构建时，很多资源是不变的，可以利用缓存加速：\n[build] writeStats = true [caches] [caches.assets] dir = \u0026#34;:resourceDir/_gen\u0026#34; maxAge = \u0026#34;720h\u0026#34; # 30 天 [caches.getcsv] dir = \u0026#34;:cacheDir/:project\u0026#34; maxAge = \u0026#34;4h\u0026#34; [caches.getjson] dir = \u0026#34;:cacheDir/:project\u0026#34; maxAge = \u0026#34;4h\u0026#34; [caches.getresource] dir = \u0026#34;:cacheDir/:project\u0026#34; maxAge = \u0026#34;4h\u0026#34; [caches.images] dir = \u0026#34;:resourceDir/_gen\u0026#34; maxAge = \u0026#34;720h\u0026#34; writeStats = true 会生成一个包含所有使用过的类名的文件，可以配合 PurgeCSS 做 tree-shaking（虽然 PaperMod 主题本身已经很精简了）。\n图片处理优化 Hugo 的图片处理功能很强大，合理配置可以减小图片体积：\n[imaging] quality = 80 resampleFilter = \u0026#34;Lanczos\u0026#34; hint = \u0026#34;photo\u0026#34; anchor = \u0026#34;Smart\u0026#34; bgColor = \u0026#34;#ffffff\u0026#34; [imaging.exif] disableDate = false disableLatLong = true # 保护隐私 quality = 80：图片质量设为 80%，肉眼几乎看不出差别，但体积能减小不少 resampleFilter = \u0026quot;Lanczos\u0026quot;：高质量重采样算法，适合缩放照片 anchor = \u0026quot;Smart\u0026quot;：智能裁剪，自动识别图片主体 disableLatLong = true：移除 EXIF 中的位置信息，保护隐私 前端优化 DNS 预解析和预连接 浏览器解析域名需要时间，可以用 dns-prefetch 提前解析外部域名：\n\u0026lt;!-- 放在 layouts/partials/extend_head.html --\u0026gt; \u0026lt;link rel=\u0026#34;dns-prefetch\u0026#34; href=\u0026#34;//fonts.googleapis.com\u0026#34;\u0026gt; \u0026lt;link rel=\u0026#34;dns-prefetch\u0026#34; href=\u0026#34;//fonts.gstatic.com\u0026#34;\u0026gt; \u0026lt;link rel=\u0026#34;dns-prefetch\u0026#34; href=\u0026#34;//cdn.jsdelivr.net\u0026#34;\u0026gt; \u0026lt;link rel=\u0026#34;preconnect\u0026#34; href=\u0026#34;https://fonts.googleapis.com\u0026#34; crossorigin\u0026gt; \u0026lt;link rel=\u0026#34;preconnect\u0026#34; href=\u0026#34;https://fonts.gstatic.com\u0026#34; crossorigin\u0026gt; preconnect 比 dns-prefetch 更进一步，会提前建立完整的 TCP 连接。\n图片懒加载 现代浏览器都支持原生的 loading=\u0026quot;lazy\u0026quot; 属性，不需要额外的 JS 库：\ndocument.addEventListener(\u0026#39;DOMContentLoaded\u0026#39;, function() { function addLoadedClass(img) { if (img.complete) { img.classList.add(\u0026#39;loaded\u0026#39;); } else { img.addEventListener(\u0026#39;load\u0026#39;, function() { img.classList.add(\u0026#39;loaded\u0026#39;); }); } } document.querySelectorAll(\u0026#39;.post-content img\u0026#39;).forEach(function(img) { if (!img.hasAttribute(\u0026#39;loading\u0026#39;)) { img.setAttribute(\u0026#39;loading\u0026#39;, \u0026#39;lazy\u0026#39;); img.setAttribute(\u0026#39;decoding\u0026#39;, \u0026#39;async\u0026#39;); } addLoadedClass(img); }); }); 这段代码做了两件事：\n给所有文章图片添加 loading=\u0026quot;lazy\u0026quot; 和 decoding=\u0026quot;async\u0026quot; 属性 图片加载完成后添加 loaded 类，配合 CSS 做渐显效果 图片渐显效果 配合上面的 JS，在 CSS 中实现平滑的渐显效果：\n/* assets/css/extended/custom.css */ .post-content img, .entry-cover img { background-color: var(--code-bg); transition: opacity 0.3s ease-in-out; } .post-content img[loading=\u0026#34;lazy\u0026#34;], .entry-cover img[loading=\u0026#34;lazy\u0026#34;] { opacity: 0; } .post-content img.loaded, .entry-cover img.loaded { opacity: 1; } 这样图片在加载时会显示一个灰色占位背景，加载完成后平滑显示。\n减少布局偏移 图片加载时如果没有预留空间，会导致页面布局跳动（CLS 指标），用户体验很差：\n.post-content img { aspect-ratio: attr(width) / attr(height); height: auto; max-width: 100%; } 如果图片设置了 width 和 height 属性，浏览器可以提前计算出图片的宽高比，预留好空间。\n尊重用户偏好 有些用户可能对动画敏感，可以检测并禁用过渡效果：\n@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } 优化效果 做完这些优化后，再看 Lighthouse 跑分：\n指标 优化前 优化后 首次内容绘制 (FCP) ~1.5s ~0.8s 最大内容绘制 (LCP) ~2.5s ~1.5s 累积布局偏移 (CLS) 0.15 \u0026lt; 0.05 当然，实际效果还取决于服务器性能和用户网络。\n更多优化思路 这次只做了 Hugo 本身的优化，还有一些可以继续优化的方向：\nCDN 加速：把静态资源放到 CDN 上，全球访问都很快 Gzip/Brotli 压缩：服务器开启压缩，进一步减小传输体积 HTTP/2：启用 HTTP/2 多路复用，并行加载资源 字体优化：使用 font-display: swap 避免字体阻塞渲染 图片格式：使用 WebP/AVIF 等现代格式 后续有空再继续折腾。\n参考资料 Hugo 官方文档 - Configure Minify Hugo 官方文档 - Image Processing Web.dev - Browser-level image lazy loading Web.dev - Optimize Cumulative Layout Shift ","permalink":"https://web.943827561.xyz/posts/hugo-blog-performance-optimization/","summary":"博客上线后发现加载速度不太理想，于是花了点时间研究优化方案。这篇文章记录了从 Hugo 配置到前端样式的完整优化过程。","title":"Hugo 博客加载速度优化实践"},{"content":"👋 嘿 这里是 kkkk24 的个人博客。\n主要记录一些技术折腾、踩坑经历，偶尔也写点别的。\n技术栈 日常用的比较多的：\nPython / JavaScript / Go Vue / React Django / FastAPI MySQL / PostgreSQL / Redis Docker / Linux 不是什么都精通，但什么都能写点。\n这个博客 用 Hugo + PaperMod 主题搭的。\n部署方式：GitHub Actions 自动编译 → 推到 gh-pages → 服务器拉取 → Cloudflare CDN。\n具体可以看这篇：聊聊这个博客是怎么跑起来的\n联系 GitHub: kkkk24juastin Email: contact@kkkk24juastin.asia 其他 文章可以转载，注明出处就行 发现错误或者有建议，欢迎留言或者直接提 PR 这个博客不卖课不带货，纯粹自己写着玩 ","permalink":"https://web.943827561.xyz/about/","summary":"\u003ch2 id=\"-嘿\"\u003e👋 嘿\u003c/h2\u003e\n\u003cp\u003e这里是 \u003cstrong\u003ekkkk24\u003c/strong\u003e 的个人博客。\u003c/p\u003e\n\u003cp\u003e主要记录一些技术折腾、踩坑经历，偶尔也写点别的。\u003c/p\u003e\n\u003ch2 id=\"技术栈\"\u003e技术栈\u003c/h2\u003e\n\u003cp\u003e日常用的比较多的：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePython / JavaScript / Go\u003c/li\u003e\n\u003cli\u003eVue / React\u003c/li\u003e\n\u003cli\u003eDjango / FastAPI\u003c/li\u003e\n\u003cli\u003eMySQL / PostgreSQL / Redis\u003c/li\u003e\n\u003cli\u003eDocker / Linux\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e不是什么都精通，但什么都能写点。\u003c/p\u003e\n\u003ch2 id=\"这个博客\"\u003e这个博客\u003c/h2\u003e\n\u003cp\u003e用 \u003ca href=\"https://gohugo.io/\"\u003eHugo\u003c/a\u003e + \u003ca href=\"https://github.com/adityatelange/hugo-PaperMod\"\u003ePaperMod\u003c/a\u003e 主题搭的。\u003c/p\u003e\n\u003cp\u003e部署方式：GitHub Actions 自动编译 → 推到 gh-pages → 服务器拉取 → Cloudflare CDN。\u003c/p\u003e\n\u003cp\u003e具体可以看这篇：\u003ca href=\"/posts/hugo-blog-architecture/\"\u003e聊聊这个博客是怎么跑起来的\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"联系\"\u003e联系\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eGitHub: \u003ca href=\"https://github.com/kkkk24juastin\"\u003ekkkk24juastin\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eEmail: \u003ca href=\"mailto:contact@kkkk24juastin.asia\"\u003econtact@kkkk24juastin.asia\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"其他\"\u003e其他\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e文章可以转载，注明出处就行\u003c/li\u003e\n\u003cli\u003e发现错误或者有建议，欢迎留言或者直接提 PR\u003c/li\u003e\n\u003cli\u003e这个博客不卖课不带货，纯粹自己写着玩\u003c/li\u003e\n\u003c/ul\u003e","title":"关于"},{"content":"之前逛别人博客的时候，经常看到左下角有个会动的小人，眼睛还会跟着鼠标跑，感觉挺有意思的。研究了一下发现这玩意叫 Live2D，于是决定给自己的 Hexo 博客也整一个。\n折腾了一晚上，踩了不少坑，这里记录一下实现过程。\n效果 加完之后，博客左下角会多一个二次元小人，能：\n眼睛跟着鼠标动（有点魔性） 随机显示一言 换装、换模型 截图保存 还能玩个打砖块小游戏 说实话没啥实际用处，但看着就是舒服 😂\n最简单的方式 如果只是想快速体验，一行代码就够了。\n在主题的 layout/layout.ejs 里加上：\n\u0026lt;script src=\u0026#34;https://fastly.jsdelivr.net/npm/live2d-widgets@1.0.0/dist/autoload.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; 放在 \u0026lt;/body\u0026gt; 之前就行。刷新页面，看板娘应该就出来了。\n不过这种方式没法自定义，想要更多控制就得用下面的方法。\n完整配置版 第一步：创建组件 在主题目录的 layout/_partial/ 下面新建一个 live2d.ejs：\n\u0026lt;%# 看板娘组件 %\u0026gt; \u0026lt;% if (theme.live2d \u0026amp;\u0026amp; theme.live2d.enable) { %\u0026gt; \u0026lt;% // 读取配置，给个默认值兜底 const cdnPath = (theme.live2d.cdn \u0026amp;\u0026amp; theme.live2d.cdn.url) ? theme.live2d.cdn.url : \u0026#39;https://fastly.jsdelivr.net/npm/live2d-widgets@1.0.0/dist/\u0026#39;; const modelId = (theme.live2d.model \u0026amp;\u0026amp; theme.live2d.model.id !== undefined) ? theme.live2d.model.id : 0; const modelCdnPath = (theme.live2d.model \u0026amp;\u0026amp; theme.live2d.model.cdnPath) ? theme.live2d.model.cdnPath : \u0026#39;https://fastly.jsdelivr.net/gh/fghrsh/live2d_api/\u0026#39;; const toolItems = (theme.live2d.tools \u0026amp;\u0026amp; theme.live2d.tools.items) ? theme.live2d.tools.items : [\u0026#39;hitokoto\u0026#39;, \u0026#39;asteroids\u0026#39;, \u0026#39;switch-model\u0026#39;, \u0026#39;switch-texture\u0026#39;, \u0026#39;photo\u0026#39;, \u0026#39;info\u0026#39;, \u0026#39;quit\u0026#39;]; const drag = theme.live2d.drag !== undefined ? theme.live2d.drag : false; const logLevel = theme.live2d.logLevel || \u0026#39;warn\u0026#39;; %\u0026gt; \u0026lt;script\u0026gt; const live2d_path = \u0026#39;\u0026lt;%= cdnPath %\u0026gt;\u0026#39;; // 动态加载资源 function loadExternalResource(url, type) { return new Promise((resolve, reject) =\u0026gt; { let tag; if (type === \u0026#39;css\u0026#39;) { tag = document.createElement(\u0026#39;link\u0026#39;); tag.rel = \u0026#39;stylesheet\u0026#39;; tag.href = url; } else if (type === \u0026#39;js\u0026#39;) { tag = document.createElement(\u0026#39;script\u0026#39;); tag.type = \u0026#39;module\u0026#39;; tag.src = url; } if (tag) { tag.onload = () =\u0026gt; resolve(url); tag.onerror = () =\u0026gt; reject(url); document.head.appendChild(tag); } }); } (async () =\u0026gt; { // 手机上就别加载了，太占地方 if (screen.width \u0026lt; 768) return; // 处理图片跨域（这个坑踩了好久） const OriginalImage = window.Image; window.Image = function(...args) { const img = new OriginalImage(...args); img.crossOrigin = \u0026#34;anonymous\u0026#34;; return img; }; window.Image.prototype = OriginalImage.prototype; // 加载资源 await Promise.all([ loadExternalResource(live2d_path + \u0026#39;waifu.css\u0026#39;, \u0026#39;css\u0026#39;), loadExternalResource(live2d_path + \u0026#39;waifu-tips.js\u0026#39;, \u0026#39;js\u0026#39;) ]); // 初始化 initWidget({ waifuPath: live2d_path + \u0026#39;waifu-tips.json\u0026#39;, cdnPath: \u0026#39;\u0026lt;%= modelCdnPath %\u0026gt;\u0026#39;, cubism2Path: live2d_path + \u0026#39;live2d.min.js\u0026#39;, cubism5Path: \u0026#39;https://cubism.live2d.com/sdk-web/cubismcore/live2dcubismcore.min.js\u0026#39;, modelId: \u0026lt;%= modelId %\u0026gt;, tools: \u0026lt;%- JSON.stringify(toolItems) %\u0026gt;, drag: \u0026lt;%= drag %\u0026gt;, logLevel: \u0026#39;\u0026lt;%= logLevel %\u0026gt;\u0026#39; }); })(); \u0026lt;/script\u0026gt; \u0026lt;% } %\u0026gt; 第二步：引入组件 在 layout/layout.ejs 里引入（放在 \u0026lt;/body\u0026gt; 前面）：\n\u0026lt;%- partial(\u0026#39;_partial/live2d\u0026#39;) %\u0026gt; 第三步：配置主题 在主题的 _config.yml 里添加：\n# Live2D 看板娘 live2d: enable: true model: id: 0 # 默认模型 cdnPath: https://fastly.jsdelivr.net/gh/fghrsh/live2d_api/ tools: items: - hitokoto # 一言 - asteroids # 小游戏 - switch-model # 切换模型 - switch-texture # 切换皮肤 - photo # 拍照 - info # 关于 - quit # 关闭 drag: false logLevel: warn cdn: url: https://fastly.jsdelivr.net/npm/live2d-widgets@1.0.0/dist/ 踩过的坑 1. 看板娘变形 一开始在 CSS 里给容器设了宽高，结果模型比例全乱了。后来发现要让它自己加载 waifu.css，不要手动设置尺寸。\n2. 图片跨域 控制台一堆跨域错误，截图功能也用不了。解决方法是在加载前给 Image 设置 crossOrigin：\nconst OriginalImage = window.Image; window.Image = function(...args) { const img = new OriginalImage(...args); img.crossOrigin = \u0026#34;anonymous\u0026#34;; return img; }; 3. 手机上太占地方 加个判断，屏幕小就不加载：\nif (screen.width \u0026lt; 768) return; 4. PJAX 导致重复加载 把看板娘的代码放到 PJAX 刷新区域外面就好了。\n想用自己的模型？ 默认用的是 fghrsh 的模型 API，里面模型挺多的。\n如果想用自己的模型，可以 fork 那个仓库，把模型放进去，然后改一下 cdnPath 指向你自己的地址。\n相关链接 live2d-widget 项目地址 模型资源 live2d_api 更多模型资源 就这些。虽然只是个小玩意，但折腾的过程还是挺有意思的。\n有问题可以留言 👋\n","permalink":"https://web.943827561.xyz/posts/add-live2d-to-hexo-blog/","summary":"\u003cp\u003e之前逛别人博客的时候，经常看到左下角有个会动的小人，眼睛还会跟着鼠标跑，感觉挺有意思的。研究了一下发现这玩意叫 Live2D，于是决定给自己的 Hexo 博客也整一个。\u003c/p\u003e\n\u003cp\u003e折腾了一晚上，踩了不少坑，这里记录一下实现过程。\u003c/p\u003e\n\u003ch2 id=\"效果\"\u003e效果\u003c/h2\u003e\n\u003cp\u003e加完之后，博客左下角会多一个二次元小人，能：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e眼睛跟着鼠标动（有点魔性）\u003c/li\u003e\n\u003cli\u003e随机显示一言\u003c/li\u003e\n\u003cli\u003e换装、换模型\u003c/li\u003e\n\u003cli\u003e截图保存\u003c/li\u003e\n\u003cli\u003e还能玩个打砖块小游戏\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e说实话没啥实际用处，但看着就是舒服 😂\u003c/p\u003e\n\u003ch2 id=\"最简单的方式\"\u003e最简单的方式\u003c/h2\u003e\n\u003cp\u003e如果只是想快速体验，一行代码就够了。\u003c/p\u003e\n\u003cp\u003e在主题的 \u003ccode\u003elayout/layout.ejs\u003c/code\u003e 里加上：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003escript\u003c/span\u003e \u003cspan class=\"na\"\u003esrc\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;https://fastly.jsdelivr.net/npm/live2d-widgets@1.0.0/dist/autoload.js\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003escript\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e放在 \u003ccode\u003e\u0026lt;/body\u0026gt;\u003c/code\u003e 之前就行。刷新页面，看板娘应该就出来了。\u003c/p\u003e\n\u003cp\u003e不过这种方式没法自定义，想要更多控制就得用下面的方法。\u003c/p\u003e\n\u003ch2 id=\"完整配置版\"\u003e完整配置版\u003c/h2\u003e\n\u003ch3 id=\"第一步创建组件\"\u003e第一步：创建组件\u003c/h3\u003e\n\u003cp\u003e在主题目录的 \u003ccode\u003elayout/_partial/\u003c/code\u003e 下面新建一个 \u003ccode\u003elive2d.ejs\u003c/code\u003e：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e\u0026lt;%\u003c/span\u003e\u003cspan class=\"c1\"\u003e# 看板娘组件 %\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e\u0026lt;%\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eenable\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"o\"\u003e\u0026lt;%\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e//\u003c/span\u003e \u003cspan class=\"err\"\u003e读取配置，给个默认值兜底\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003ecdnPath\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecdn\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecdn\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"err\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecdn\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;https://fastly.jsdelivr.net/npm/live2d-widgets@1.0.0/dist/\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003emodelId\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emodel\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emodel\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eid\u003c/span\u003e \u003cspan class=\"o\"\u003e!==\u003c/span\u003e \u003cspan class=\"n\"\u003eundefined\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"err\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emodel\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eid\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003emodelCdnPath\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emodel\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emodel\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecdnPath\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"err\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emodel\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecdnPath\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;https://fastly.jsdelivr.net/gh/fghrsh/live2d_api/\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003etoolItems\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etools\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etools\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eitems\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"err\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etools\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eitems\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;hitokoto\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;asteroids\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;switch-model\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;switch-texture\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;photo\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;info\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;quit\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003edrag\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edrag\u003c/span\u003e \u003cspan class=\"o\"\u003e!==\u003c/span\u003e \u003cspan class=\"n\"\u003eundefined\u003c/span\u003e \u003cspan class=\"err\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edrag\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"bp\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003elogLevel\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etheme\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elogLevel\u003c/span\u003e \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;warn\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"o\"\u003e%\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003escript\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003elive2d_path\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;%= cdnPath %\u0026gt;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e//\u003c/span\u003e \u003cspan class=\"err\"\u003e动态加载资源\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003efunction\u003c/span\u003e \u003cspan class=\"n\"\u003eloadExternalResource\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003enew\u003c/span\u003e \u003cspan class=\"n\"\u003ePromise\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eresolve\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ereject\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003elet\u003c/span\u003e \u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etype\u003c/span\u003e \u003cspan class=\"o\"\u003e===\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;css\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003etag\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003edocument\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;link\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003erel\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;stylesheet\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ehref\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etype\u003c/span\u003e \u003cspan class=\"o\"\u003e===\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;js\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003etag\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003edocument\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;script\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etype\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;module\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esrc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eonload\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eresolve\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eonerror\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereject\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003edocument\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ehead\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappendChild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etag\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003easync\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"o\"\u003e//\u003c/span\u003e \u003cspan class=\"err\"\u003e手机上就别加载了，太占地方\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escreen\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e768\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"o\"\u003e//\u003c/span\u003e \u003cspan class=\"err\"\u003e处理图片跨域（这个坑踩了好久）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eOriginalImage\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ewindow\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eImage\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"n\"\u003ewindow\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eImage\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003efunction\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e...\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eimg\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enew\u003c/span\u003e \u003cspan class=\"n\"\u003eOriginalImage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e...\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eimg\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecrossOrigin\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;anonymous\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eimg\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"n\"\u003ewindow\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eImage\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprototype\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eOriginalImage\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprototype\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"o\"\u003e//\u003c/span\u003e \u003cspan class=\"err\"\u003e加载资源\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"n\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003ePromise\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eall\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eloadExternalResource\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d_path\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;waifu.css\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;css\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eloadExternalResource\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elive2d_path\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;waifu-tips.js\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;js\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"o\"\u003e//\u003c/span\u003e \u003cspan class=\"err\"\u003e初始化\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"n\"\u003einitWidget\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003ewaifuPath\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003elive2d_path\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;waifu-tips.json\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003ecdnPath\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;%= modelCdnPath %\u0026gt;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003ecubism2Path\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003elive2d_path\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;live2d.min.js\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003ecubism5Path\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;https://cubism.live2d.com/sdk-web/cubismcore/live2dcubismcore.min.js\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003emodelId\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;%=\u003c/span\u003e \u003cspan class=\"n\"\u003emodelId\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003etools\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;%-\u003c/span\u003e \u003cspan class=\"n\"\u003eJSON\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estringify\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoolItems\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003edrag\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;%=\u003c/span\u003e \u003cspan class=\"n\"\u003edrag\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003elogLevel\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;%= logLevel %\u0026gt;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e})();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"o\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"n\"\u003escript\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e\u0026lt;%\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"第二步引入组件\"\u003e第二步：引入组件\u003c/h3\u003e\n\u003cp\u003e在 \u003ccode\u003elayout/layout.ejs\u003c/code\u003e 里引入（放在 \u003ccode\u003e\u0026lt;/body\u0026gt;\u003c/code\u003e 前面）：\u003c/p\u003e","title":"给博客加个 Live2D 看板娘"}]