<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
<channel>
<atom:link href="http://space.fosky.top/feed" rel="self" type="application/rss+xml"/>
<title>FoskyM's Blog</title>
<link>http://space.fosky.top</link>
<description>是侬勿望</description>
<language>zh-CN</language>
<copyright>© FoskyM </copyright>
<pubDate>Sat, 02 May 2026 20:39:38 GMT</pubDate>
<generator>Mix Space CMS (https://github.com/mx-space)</generator>
<docs>https://mx-space.js.org</docs>
<image>
    <url>https://cravatar.cn/avatar/1e03f55c71895224f301d1f5520adb50?s=400</url>
    <title>FoskyM's Blog</title>
    <link>http://space.fosky.top</link>
</image>
<item>
    <title>前端 Canvas 技术经验心得</title>
    <link>http://space.fosky.top/posts/experience/frontend-canvas-experience</link>
    <pubDate>Sun, 26 Apr 2026 09:13:41 GMT</pubDate>
    <description>前言

近年来出现各种开源富文本编辑器项目，各家大厂也在自己的文档应用上发力。

大体上有四代：

</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/experience/frontend-canvas-experience'>http://space.fosky.top/posts/experience/frontend-canvas-experience</a></blockquote>
      <h2>前言</h2>
<p>近年来出现各种开源富文本编辑器项目，各家大厂也在自己的文档应用上发力。</p>
<p>大体上有四代：
</p>
<p>目前大多数的文档、富文本编辑器仍然在第三代，因为这个技术非常成熟。<br>但槽点也不少，一是 contenteditable 在不同浏览器上的行为不同(当然现在大多数应用都是 chromium，倒是很好地解决了这点)，二是事件拦截与处理，你永远预料不到用户粘贴进来什么东西。<br>具体的相关分析与介绍可以见两篇有道云的知乎文章：<br>有道云笔记新版编辑器架构设计（上）：<a href="https://zhuanlan.zhihu.com/p/345895871">https://zhuanlan.zhihu.com/p/345895871</a><br>有道云笔记新版编辑器架构设计（下）：<a href="https://zhuanlan.zhihu.com/p/347415991">https://zhuanlan.zhihu.com/p/347415991</a></p>
<h3>个人看法</h3>
<p>虽然以 Canvas 驱动的富文本编辑器技术还不成熟，就像 Google Docs 上线了一段时间又改回原来的 contenteditable 模式，但我还是认为 Canvas 技术会是大趋势。<br>且不仅限于富文本编辑器，只要是依托于网页且有所见即所得的需求的任何编辑器，未来都有可能转向 Canvas 技术。<br>因此这两年我在 Canvas 上投入了颇多精力，也有了些经验与心得，记录于此。</p>
<h2>技术</h2>
<h3>原生 Canvas</h3>
<p>这是最入门的技术了，如果只需实现静态图像或刷新率要求不高的场景，用原生 Canvas 即可。<br>常用场景：生成分享图、二维码等，或是在线富文本编辑器亦有该技术实现方案。<br>需要注意的是渲染 DPR，否则不同设备上渲染效果不一致。<br>另外 Canvas 的文本天然就会偏模糊一些，因此对于文本多的情况不建议使用。<br>本人的 <a href="https://github.com/FoskyM/train-ticket-generator">火车票生成器</a> 就是原生 Canvas 渲染。</p>
<h3>WebGL / WebGL2</h3>
<p>通过 OpenGL 接口发指令绘制，在精度、性能上都有很大的提升。<br>常用场景：CAD、画板、游戏、图片处理加速。<br>基本上是最优解了。</p>
<h3>WebGPU</h3>
<p>直接向 GPU 发命令，但在某些场景下仍然不如 WebGL 好，毕竟也是新技术。<br>所以这块并没有深入了解。</p>
<h2>引擎库</h2>
<p>调研了很多相关引擎库，列出一些经典的，如下。</p>
<h3>Konva.js</h3>
<p>很多开源编辑器/表格采用，静态还行，动态场景性能相对一般。</p>
<h3>Fabric.js</h3>
<p>虽然老牌，但动态上不如 <code>Konva.js</code>。</p>
<h3>Pixi.js</h3>
<p>现代化引擎，同时支持 <code>WebGL</code> 和 <code>WebGPU</code>，性能出色，基本是目前首选引擎方案。</p>
<h3>LittleJS</h3>
<p>游戏引擎，某些场景下比 <code>Pixi.js</code> 发挥更出色。<br>就是需要自己封装一下才能当做普通的图形渲染引擎使用。</p>
<p><em>具体呢可以看下这个 benchmark 页：<a href="https://benchmarks.slaylines.io/">https://benchmarks.slaylines.io/</a></em></p>
<h2>封装</h2>
<p>很多开源项目都是强耦合于引擎的，比如在创建一个矩形时直接 <code>const rect = new Konva.rect({...})</code><br>或者是采用原生 Canvas 的整个项目的业务实现都基于一个 canvas 上下文，而没有进行自己的封装<br>这不利于迁移改造。</p>
<p>在一个富文本编辑器或其它需要长期迭代的 WebGL 项目内，这样耦合是绝对不好的。<br>有必要实现一个抽象层，并封装相关引擎的接口。</p>
<p>例如：</p>
<pre><code class="language-typescript">class KonvaEngine extends AbstractEngine
{
  // ...
  function drawRect(width: number, height: number, ...): Rect {
    const rect = new Konva.rect({...})
    return konvaRectToAbstractRect(rect)
  } 
  // ...
}</code></pre><h2>动态性能优化</h2>
<p>在经手的项目内，有着复杂多元素的需求。<br>性能瓶颈主要在三块：渲染、计算、GC。</p>
<h3>渲染</h3>
<h4>画布渲染</h4>
<p>当画布上元素很多时，会出现明显掉帧。<br>这块优化可以做的很多：精灵图、视窗内渲染、LOD 按需渲染、按需更新等。</p>
<h4>元素渲染</h4>
<p>画布上存在大量形状后，每次绘制都会卡顿，排查发现是数据更新，导致 dom 更新，出现了一系列 React 的微任务调度。<br>这块主要是防抖节流，并将部分渲染更新操作放到了 RAF 中。</p>
<h3>计算</h3>
<p>由于在场景中充斥着非常多的计算，例如图形的交点计算。<br>我们的场景中有：直线、二阶贝塞尔曲线、三阶贝塞尔曲线、椭圆、圆形等。<br>这里主要有两块经典场景：交点坐标计算与交点查找。</p>
<h4>交点坐标计算</h4>
<p>这块一开始是将我们的数据转换为 <code>paper.js</code> 后计算，但导致了精度丢失。<br>后来我们单独实现了针对性算法，即不同两种形状间分别有计算。<br>虽然性能提升，但代码实打实地变烂了。<br>后续因为别的需求，我们删去了椭圆和圆形的实体定义，将其降级成了四个二阶贝塞尔曲线的组合形状，这样在计算上就方便了许多。</p>
<h4>交点查找</h4>
<p>这块一开始是我们的同事写的，后续我调试时在代码中发现了多处 2 级 for 即 O(m*n)，以及其它的一些可优化处。<br>这显然是不合适的。改造后的算法主要利用 <code>Set</code> 来优化为 O(m+n)。</p>
<p>当然也还做了另一些，例如对细分算法的优化、对路径的优化。</p>
<h3>GC</h3>
<p>在连续绘制时，总能感觉到突然卡顿，不用说，这肯定是触发 GC 了。<br>这块主要是用对象池去优化，避免元素对象被 GC。</p>
<h2>一些探索实现</h2>
<h3>富文本编辑器</h3>
<p>自己设想的架构大致如下：</p>
<p>Event-&gt;EventBus-&gt;Handler-&gt;CommandManager-&gt;Command-&gt;Transaction-&gt;DocumentModel-&gt;LayoutEngine(diff、markDirty)-&gt;PaginationCoordinator(协调分页)-&gt;EditorView-&gt;RenderEngine(diff、patch)-&gt;RenderBackend</p>
<p>目前实现的一些 demo 基本都写到一半废了。</p>
<h3>动态配置化卡片</h3>
<p>这个目前还是原型阶段。<br>主要实现：传入符合 schema 的配置 json，并传入相关数据，依据配置动态将数据渲染到画布实现卡片，例如证件、名片、票据等。</p>
<p>schema 定义：<br>基本配置：宽高比、圆角、边框、凹槽、阴影、默认文本样式等。<br>元素：region、text、textRegion、image、qrcode、decoration。</p>
<p>通过以上信息，基本就能描述出卡片了。</p>
<h3>类 CAD 绘制</h3>
<p>其实就是性能优化 part 中的项目，不赘述了。</p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/experience/frontend-canvas-experience#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">69edd7451f31cbf785f308eb</guid>
  <category>posts</category>
<category>经验分享</category>
 </item>
  <item>
    <title>2025 年度总结</title>
    <link>http://space.fosky.top/posts/daily/annual-summary-2025</link>
    <pubDate>Wed, 31 Dec 2025 14:56:45 GMT</pubDate>
    <description>概述

2025 的最后一天，依旧是一个人，在出租屋听着歌、写着代码，然后绞尽脑汁编年度总结。

回</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/daily/annual-summary-2025'>http://space.fosky.top/posts/daily/annual-summary-2025</a></blockquote>
      <h2>概述</h2>
<p>2025 的最后一天，依旧是一个人，在出租屋听着歌、写着代码，然后绞尽脑汁编年度总结。</p>
<p>回忆了下 2025 年，感觉还是蛮割裂的。明明上半年还在校上课、打比赛，下半年已然成为一个合格的社畜了(虽然还只是实习)。甚至大脑里已经记不清在学校的日常生活了。</p>
<p>上半年已经写过小记了，有些事情便不在此处赘述。但年初还是比较值得纪念的事情，写在此处：完成<em>公交环游金华</em>计划、拿到业余无线电A级操作证(虽然一次都没通联过)。</p>
<p>写在小记里的一些事情已经完成：本学院声学系语音降噪项目、隔壁经管学院勤工俭学项目，两门重修课也过了，不过前端实习的工作量还是超过了我的预期了。</p>
<h2>实习与秋招</h2>
<p>5月底莫名其妙地加入似一科技(特工宇宙)，负责“观猹”项目的前端部分。明明只有UI稿，以至于当时就想提包跑路了，但还是留下来把项目的前端起了个框架。</p>
<p>7.16，北京天安门边上的 Blue Note，观猹正式发布，在这儿认识了许多好厉害的人，也在见到了好几个大人物，庆功宴上感觉自己心潮澎湃。</p>
<p>而从北京回来后，其实花时间的大头便是观猹每周的例行更新。虽然很充实，但我总感觉我失去了自己的方向。</p>
<p>内心反复挣扎，一方面其实很想陪着“观猹”走到未来，但另一方面又在考虑自己原来规划的未来。讲道理毕竟一手搭建起观猹的前端，也确实有些感情难以割舍。</p>
<p>一直到了九月底去了上海S创后，展会上见到各行各业的创业者、开发者、投资者，脑海中那些想法又蹦了出来，我想走自己的路，而不是在观猹养老。极度纠结许久后，我，终于下定决心离职了。大家觉得我离职得很突然，但其实是深思熟虑。</p>
<p>离职后去了学长在萧山的创业公司，想着先苟着，2026 年再做决定。入职时公司有两个项目在推进，我依旧选择前端，先搭建了企业官网，然后参与了其中一个项目，也慢慢过了两个半月了。日子过得平平淡淡，上班模式和以前不太一样，一开始还不太习惯，不过呆了一段时间后感觉还行。</p>
<p>其实我也没有纯摆烂，秋招我也参加了下，不过是陪跑。十月看秋招已过半，便稍微编写了下简历投了六七家公司，有直接终止流程的，也有我自己放弃笔试的，当然也有约了面试的。不过只面试了两家大厂部门，一家是腾讯文档（深圳），一家是字节抖音电商（杭州）。都是二面挂，感觉可能还是自己有所欠缺。</p>
<p>前者一面问了几十个问题，二面感觉全是压力，和我看的面经完全不一样；后者面得感觉还行，都聊的挺开，不过可能是KPI面吧，也懒得整理面经了。之后也就没投了，感觉每次面试和准备面试都是在折磨自己。甚至觉得连春招都懒得看了。</p>
<p>腾讯文档约面倒是挺有意思，我本来投的意向是杭州或上海，没想到接到电话，说看了我的个人主页和 GitHub，问我愿不愿意去深圳，想了想面个试而已也就同意了。后面看到“火车票生成器”多了几个来自深圳的 UA，项目repo 也多了几个看着像小号的 star，估摸着可能是 Canvas 的缘故。然后还催我做测评，说不做测评约不了面。</p>
<p>字节这边虽然投了官投，但我是乱投的，所以也没后续。后来还是Boss直聘上有HR联系我，牛客搜了搜说这种基本都是KPI了，想着面试一下也无所谓，也就把简历发过去了。不过面试过程也挺难绷的：开始约在了 11.11，然后推到 11.13，继续推到 11.18，中间对接我的 HR 离职(可能是实习生？)，最后新 HR 告诉我推到 11.25 晚上，关键当天面试官又迟到了。想了想是KPI，算了算了，应付下得了，没想到一面给我过了。然后过了几天到周五二面，半小时就结束了，唉~折腾。</p>
<p>想想还是安心摆烂，不用思考七的八的。</p>
<h2>项目与技术栈</h2>
<h3>项目</h3>
<p>一直在忙里偷闲，也做了做自己的项目。</p>
<p>比如优化 <a href="https://fosky.top">个人网站</a>，完全组件化了；</p>
<p>又比如优化 <a href="https://image.fosky.top/projects/ticket/">火车票生成器</a>，生成效果更加真实；</p>
<p>尝试了下 <a href="https://image.fosky.top/projects/c-music-player/">竖排音乐播放器</a>，感觉网页竖排效果还是很 ok 的；</p>
<p>还有 <a href="https://image.fosky.top/projects/c-calendar/">天文万年农历</a>，对天文算法和农历有了些理解；</p>
<p>其实还有些别的项目，不过因为完成度过低，暂时没有公开。</p>
<h3>技术栈</h3>
<p>五月份在后端方向上弃用了 thinkphp+think-orm，改用了 webman+eloquent orm；</p>
<p>在观猹项目中使用的一些前端技术积累；</p>
<p>十一月开始对前端 Canvas 进行深入了解，并深入 React 与相关库，另外弃用 tauri 而选择 electron+capacitor 方案；</p>
<p>十二月为了折腾地图，开始研究 pgsql+postgis。</p>
<h2>生活</h2>
<p>七月初为了观猹项目进度，和后端合租，申请了校外住宿。</p>
<p>九月咬咬牙给自己组装了一台台式，虽然没买显卡，内存条也只买了32G的套条，但好歹有了台能正经使用的主机。而不像另一台游戏本一样，风扇飞起，写个代码都懒得写。就在我组好台式没多久后，内存疯狂涨价，庆幸自己买得算早。</p>
<p>十月中旬我搬到了萧山，开始了自己的独居生活。押一付二+添置物品，又出去一大笔钱。</p>
<p>十一月底我开始尝试自己烧菜做饭，吃得倒是越来越爽了。但是为什么越来越容易半夜饿了？</p>
<p>十二月中旬辅导员打电话过来，问我什么时候签三方。我说我还没想好，再看看。辅导员说最晚三/四月份要给他准信。但我估计到那时还是想不好自己的去向。</p>
<p>自媒体也没时间做，都被写代码挤占了。而且将近四个月没练字了，今天试着写了写，感觉要起飞。</p>
<p>希望 2026 活的像个人点吧~2025 实在是各种焦头烂额、反复规划、自我怀疑的一年。</p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/daily/annual-summary-2025#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">695539ad0813eb921217c70d</guid>
  <category>posts</category>
<category>日常杂谈</category>
 </item>
  <item>
    <title>近半年小记</title>
    <link>http://space.fosky.top/posts/daily/2025-past-half-year-record</link>
    <pubDate>Tue, 27 May 2025 04:15:25 GMT</pubDate>
    <description>勿念

去年我得知外公患癌了，还是晚期，已经大范围转移了。

暑假我去陪外公，他还能正常走路，就是一</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/daily/2025-past-half-year-record'>http://space.fosky.top/posts/daily/2025-past-half-year-record</a></blockquote>
      <h3>勿念</h3>
<p>去年我得知外公患癌了，还是晚期，已经大范围转移了。</p>
<p>暑假我去陪外公，他还能正常走路，就是一条腿不太利索。而且他闻到油腻的味道就想吐，只能喝点粥。</p>
<p>外公他们老家在福建的，后面到了温州定居。查出症状后回到了福建老家疗养。</p>
<p>我妈是嫁到义乌来的，所以我们去看望外公的话也要不少路。</p>
<p>有段时间我们去了福州，外公在那边住院治疗，我们在边上租了几间小房间，吃得也很朴素。</p>
<p>这是我第一次来到这么拥挤的医院。电梯爆满，队伍从电梯排到了门口外。</p>
<p>人性在这里展现的淋漓尽致，他们可不管你在不在排队，一股脑的往上挤，虽然他们也是因为有想多看几眼的人……</p>
<p>暑假这段时间外公的状态还是很不错的，所以我们待了没多久，就回义乌了。</p>
<p><em>我曾以为时间很慢。</em></p>
<p>忙于学业和比赛的我也没能抽出时间去看望外公。</p>
<p>直到寒假，我们一家子都去了福建外公老家。</p>
<p>而此时的外公已经只能躺在躺椅上，吃喝拉撒睡都需要人照看。</p>
<p><em>疫情后我们第一次到这边过年。</em></p>
<p>我看着外公那无神的双眼，悲伤的情绪用上心头——时间真快呀，想当年外公还能抱着小小个的我呢。</p>
<p>最凄凉的是有天上午，我们在外面忙着，外公还在睡觉，所以没人照看。等一进房间就发现外公已经掉下床，而他又行动不便，只能躺在地上。天知道地板有多凉。</p>
<p>好在外公状态还是很好，我也稍稍放心了下来。可后来又接到了老家的电话——爷爷住院了！</p>
<p>一时我的心又揪了起来，眼里尽是迷茫。</p>
<p>我们提前离开了。不过是陪外公过完生日后。外公生日那天很开心，他破天荒的要了杯橙汁喝，小口小口地抿着。</p>
<hr>
<p>回到家里已经很晚，我们简单吃了点东西，就睡觉了。</p>
<p>第二天我们去看望爷爷，爷爷状态还挺好，也挺乐观，看得很开，嘴里嘟囔着&quot;岁数到了&quot;。我笑着笑着就笑不出来了。</p>
<p>听奶奶说爷爷：“渠涴不出来，然后吐来昏来。阿拉惊都惊倒，xx(我叔名字)赶紧开车带阿拉去医院。阿坐面个车便昏来，眼睛都睁不开。过年又没医师值班，便先住了院。还好没事干……”</p>
<p>听了一会我听明白了：爷爷肠胃不好，吃得东西又油太少，导致拉不出肠梗阻了。</p>
<p><em>还好没事。</em></p>
<hr>
<p>2.21，我出发回学校了。</p>
<p>2.24，妈妈和我说外公状态欠佳，她出发过去照看。晚上我们通了视频电话，我看到外公迷迷糊糊地瘫在床上，我心揪得厉害。</p>
<p>2.25下午，妈妈和我说外公状态转好了，中午也吃下了一小碗米饭糊。我的心又稍安了一点，但马上又揪了起来，万一是回光返照怎么办？</p>
<p>2.25晚上，妈妈和我说外公情况不乐观，我们又通了视频。此时我不知道和外公说什么，因为外公已经很迷糊了。我很迷茫。</p>
<p>2.26早上六点多开始，妈妈给我打了好多个电话。此时的我还在睡觉，因为我七点多才起床，手机设的七点二十闹铃和自动解除免打扰。七点二十五妈妈又打了个电话过来，此时的我终于惊醒，然后我就看到了满屏的信息提示。我心里暗叫不好赶紧回拨了过去，企盼着不要。可最后还是获知，外公去世了。</p>
<p>我手抖着，赶紧申请了请假，把东西整理完又和班主任及导员通了电话，班主任和导员都让我别难过让我路上小心。</p>
<p>我的表哥、表妹（外公的孙辈）也在杭州上学，我们在下沙汇合。姨姨和姨丈（外公那边的）从嘉兴过来，捎上我们仨一起回福建。</p>
<p>因为外公是在医院去世的，所以火化也很快，我们没能见到他最后一面。</p>
<p>到了那边，我脑子里一坨浆糊，只记得满眼的白衣素缟。</p>
<p>福建这边民俗还是很深的。我记得灵堂里有道士诵经，还要跪拜。</p>
<p>做这些的时候我都像行尸走肉一样，也感觉不出自己的情感。</p>
<p>到了最后一天，我们把外公的骨灰送出灵堂送到车上，跪下去的那瞬间我感觉眼前模糊了，我还以为是我低血糖了，后面反应过来是我的眼泪落到了眼镜上。</p>
<p>我很久没哭了，那天似乎是把几年的泪水都流出来了。</p>
<p>外公葬在了公墓。来了很多人。我第一次见到外公这边的这么多亲戚。也是我爸的第二次见，他第一次见已经是二十多年前他第一次上门了。</p>
<hr>
<p>回到学校，我沉寂了一段时间。先前的实习也结束了，因为我时间太分散。</p>
<p>我终于明白，时间不等人。</p>
<p>我开始想努力提升自己。</p>
<h3>探索</h3>
<p>之前的科创新苗项目又顺便参加了大挑，获得了校特和省银（还是蛮遗憾的吧）</p>
<p>也尝试在小黄鱼上靠着技术赚了点外快。</p>
<p>加入了隔壁学院的一个项目，负责写前端。</p>
<p>加入了本学院隔壁专业的一个项目，负责写 APP 和库。</p>
<p>学长又介绍了个前端实习，我本来想推掉，但考虑了下，还是去了。
因为这家公司虽然是初创公司，但是做AI方向，我感觉发展潜力还是挺不错的。
毕竟哪怕我没赌对，现在的我还是大三，也有足够的试错时间。
不过也确实挺有潜力的，刚好我实习的第一周公司就要搬家，换了个大场地。老板也和知乎和红杉洽谈，积极推动合作。</p>
<p>我在这家公司写的是一个新项目的前端。如果成了，我也算是可以留个名。</p>
<p>说起来也挺好笑的，现在的成员，包括老板在内，基本都挂过科。属于是企业文化了（雾）。
我还在重修高等代数和运筹与优化，我觉得这两门课都是很抽象的东西，远不如概率论直观。特别是证明题，来一道我就懵一道。
虽然我是数据科学与大数据技术专业的，但是我的偏科很严重，计算机相关的我基本都是九十多，数学方面我就概率论九十多能拿出来看一眼，别的都是六七十多分。
（论交叉学科对偏科学生的不友好）</p>
<h3>展望</h3>
<p>本学院的项目应该是完成了基础部分了，可能还有后续工作要推进。</p>
<p>隔壁学院的项目才写了没多少，好在时间不是那么紧张（DDL 了再说）。</p>
<p>实习项目估摸着是最先完成的了，毕竟只用写前端（想当初我一个人开发项目都是前后端一把梭呀）。</p>
<p>重修我倒是希望这次能过，真的不想再重修了。所以要在开发实习项目的同时也要多分点时间给这两门课复习了。</p>
<p>还有一堆小项目想写，不知道什么时候才能提上日程。</p>
<p>另外还想做做自媒体，玩玩开发板啥的。</p>
<p>最后的最后，要赶快搞钱，让家人享福。</p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/daily/2025-past-half-year-record#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">68353c5d0813eb921210b02c</guid>
  <category>posts</category>
<category>日常杂谈</category>
 </item>
  <item>
    <title>ThinkPHP 新项目模型无法获取自增 ID 问题排查</title>
    <link>http://space.fosky.top/posts/experience/thinkphp-new-project-model-cannot-get-insert-id</link>
    <pubDate>Tue, 27 May 2025 02:37:09 GMT</pubDate>
    <description>经过

用 ThinkPHP8 新建了一个小项目，为了省力直接把先前的用户模型代码拷贝过来了。

但</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/experience/thinkphp-new-project-model-cannot-get-insert-id'>http://space.fosky.top/posts/experience/thinkphp-new-project-model-cannot-get-insert-id</a></blockquote>
      <h3>经过</h3>
<p>用 ThinkPHP8 新建了一个小项目，为了省力直接把先前的用户模型代码拷贝过来了。</p>
<p>但是模型 save 后无法获取到自增 ID？于是我开始排查代码，发现代码应该没问题；又排查环境，又让 GPT 帮我修改，都无法解决。</p>
<p>后来我对比了新项目和老项目的区别是 composer.json 中，<code>&quot;topthink/think-orm&quot;: &quot;^3.0&quot;</code> 变成了 <code>&quot;topthink/think-orm&quot;: &quot;^3.0|^4.0&quot;</code>。</p>
<p>我尝试将 think-orm 版本强制回退到 3.x，然后就正常了。</p>
<p>因为 tp8 文档的模型部分中仍然有模型字段的定义，我也没仔细看 think-orm 的文档，所以一时摸不着头脑。</p>
<p>遂在仓库发了 issue 提问，才得知 4.x 无需定义模型字段 $schema。</p>
<p>作者流年给了文档链接，我又仔细看了眼，才发现原来有一笔带过：“不需要定义schema属性（会自动获取）”
（不知道各位用 thinkphp 开发网站的，是不是也像我一样看 tp 文档总看的云里雾里……）</p>
<p>但是我定义 schema 已经成习惯了，一时之间适应不了，所以还是用 3.x 先开发着。
（不过我好奇 schema 不是自动获取的吗？那手动定义为什么会影响到自增 id 的获取）</p>
<h3>碎碎念</h3>
<p>说实话很早就想弃用 tp 了，只不过实在是没有精力去研究别的框架。</p>
<p>我看中 webman 框架已经很久了，只不过一直没时间去摸索，感觉最近也要提上日程了。</p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/experience/thinkphp-new-project-model-cannot-get-insert-id#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">683525550813eb921210af1a</guid>
  <category>posts</category>
<category>经验分享</category>
 </item>
  <item>
    <title>启用新版个人主页</title>
    <link>http://space.fosky.top/posts/daily/new-personal-page</link>
    <pubDate>Mon, 23 Dec 2024 14:25:35 GMT</pubDate>
    <description>简略
查看新版主页：https://fosky.top

旧版主页存档：https://image.</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/daily/new-personal-page'>http://space.fosky.top/posts/daily/new-personal-page</a></blockquote>
      <h3>简略</h3>
<p>查看新版主页：<a href="https://fosky.top">https://fosky.top</a></p>
<p>旧版主页存档：<a href="https://image.fosky.top/projects/homepage-2023/">https://image.fosky.top/projects/homepage-2023/</a></p>
<h3>更换原因</h3>
<ol>
<li>旧版主页性能较低，出现莫名的卡顿与掉帧</li>
<li>旧版主页使用 <code>tailwindcss</code> 编写，卡片的样式维护较难</li>
<li>旧版主页的依赖库版本较低，另外因为多次迭代，有不少遗留问题，难以维护</li>
<li>旧版主页使用 javascript 而非 typescript，在类型上踩坑</li>
<li>旧版主页的文件结构比较乱，规划较差</li>
<li>旧版主页的部分布局不合理，导致显示不佳</li>
<li>部分配置项需要多处修改，如 SEO 信息，迭代麻烦</li>
</ol>
<h3>新版简介</h3>
<p>参考了 <a href="https://s23.moe">https://s23.moe</a></p>
<ol>
<li>使用 typescript 编写</li>
<li>优先使用 TSX 组件 (jsx语法) 而非 SFC 组件，更加灵活与易阅读</li>
<li>使用组合式函数 (composable) ，方便复用且提高性能</li>
<li>实现了 <code>requestWithCache</code> 机制，以防止过多请求 api，减少页面卡顿与接口压力</li>
<li>实现了 <code>inject-seo</code>，只需配置一处地方，无需修改 <code>index.html</code>，迭代方便</li>
<li>优化了架构，使得组件的复用性更强</li>
</ol>
<h3>组件说明</h3>
<ul>
<li>GitHub Stats
使用该项目的 api 生成
<a href="https://github.com/anuraghazra/github-readme-stats">https://github.com/anuraghazra/github-readme-stats</a></li>
<li>社交平台粉丝数
参考了 <code>substats</code> 项目的代码
<a href="https://github.com/spencerwooo/substats">https://github.com/spencerwooo/substats</a></li>
<li>博客文章</li>
<li>抖音近期视频</li>
<li>QQ 音乐听歌状态
从 Q音手机版抓包获取到的接口，sign 加密算法如下
<a href="https://github.com/FoskyM/qq_music_sign">https://github.com/FoskyM/qq_music_sign</a>
美中不足的是此接口需要 Cookies，且会过期，需要解决，或许可以参考以下项目
<a href="https://github.com/lonsty/qqmusic-cookie-setter">https://github.com/lonsty/qqmusic-cookie-setter</a></li>
<li>行者骑行数据</li>
<li>GitHub 仓库列表
获取这个应该是基本操作吧？</li>
<li>Steam 游戏列表
通过 Steam 的 webapi 获取</li>
<li>联系方式</li>
<li>网站访问数据
从 <code>51.la</code> 的组件 js 代码中提取访问数据</li>
<li>项目列表
直接使用 JSON</li>
<li>旅行地图(未完成)</li>
</ul>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/daily/new-personal-page#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">676972dfe45d267a0b8876ad</guid>
  <category>posts</category>
<category>日常杂谈</category>
 </item>
  <item>
    <title>最近精神状况不佳</title>
    <link>http://space.fosky.top/posts/daily/poor-mental</link>
    <pubDate>Sat, 23 Nov 2024 14:45:44 GMT</pubDate>
    <description>大致状况
科创新苗项目尚未结题，去参加了比赛A，然后比赛A还没结束，又被拉去参加比赛B。

新苗项目</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/daily/poor-mental'>http://space.fosky.top/posts/daily/poor-mental</a></blockquote>
      <h2>大致状况</h2>
<p>科创新苗项目尚未结题，去参加了比赛A，然后比赛A还没结束，又被拉去参加比赛B。</p>
<p>新苗项目我是被其它学院的同学拉去的，负责编写算法，但我本人又对算法提不起兴趣，导致一直没去完成剩余部分。</p>
<p>比赛A是信息办的老师让参加的，我担任组长，但我们组的组员都不会开发，于是开发任务落在了我的头上。于是乎只能单人高强度写码。</p>
<p>比赛B是其它学院的同学拉去的，当时比赛A还未结束，感觉比赛奖励挺丰厚的，就答应了。但是该比赛也是比拼算法的，导致我一直磨蹭。</p>
<p>三者叠加导致了最近精神状况不佳，不想写代码、不想学习，浑身乏力，不知道什么时候能调整回来。</p>
<h2>好事情</h2>
<p>好在三者都有好的结果：新苗项目算法部分申请了专利(不知道什么时候能通过)；比赛A获得了一等奖(力压一堆计科专业的)；比赛B的指导老师人很好，还给我介绍了本校科技园某公司的一个单子(和甲方谈的很融洽)。</p>
<p>另外还有一件喜事：认识的一位学长把我推荐去了他朋友的公司。公司不大，但是离学校很近，而且氛围很融洽(二刺猿浓度不要太高)，此外老板也是技术出身(不会有奇奇怪怪的需求)，于是果断开始实习(没想到大三上就找到工作了)。</p>
<p>说到工作，比赛A是学校和某创业公司一起举办的，指导老师和我说，该公司对我很感兴趣，说如果我想去实习的话可以去(好巧不巧，他们聊的那天我刚好进了上面那家公司)。只能以后有机会再去啦😌</p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/daily/poor-mental#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">6741ea98e45d267a0b87a9a7</guid>
  <category>posts</category>
<category>日常杂谈</category>
 </item>
  <item>
    <title>用上了 Mix Space + Shiro</title>
    <link>http://space.fosky.top/posts/daily/using-mix-space-and-shiro</link>
    <pubDate>Wed, 16 Oct 2024 07:05:51 GMT</pubDate>
    <description>说明

10.16 终于有空折腾博客了，起床后折腾了几小时，修了几个迁移脚本的 bug 后，终于把 </description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/daily/using-mix-space-and-shiro'>http://space.fosky.top/posts/daily/using-mix-space-and-shiro</a></blockquote>
      <h2>说明</h2>
<p>10.16 终于有空折腾博客了，起床后折腾了几小时，修了几个迁移脚本的 bug 后，终于把 Mix Space 配置好了。</p>
<p>先前在本地琢磨的时候顺便加了下 Q音/网易云 的音乐卡片</p>
<p><a href="https://github.com/Innei/Shiro/pull/470">https://github.com/Innei/Shiro/pull/470</a></p>
<p>最后也是被合入了 v1.2.2 版本</p>
<p><a href="https://github.com/Innei/Shiro/releases/tag/v1.2.2">https://github.com/Innei/Shiro/releases/tag/v1.2.2</a></p>
<h2>效果展示</h2>
<p><a href="https://y.qq.com/n/ryqq/songDetail/003KtYhg4frNXC">https://y.qq.com/n/ryqq/songDetail/003KtYhg4frNXC</a></p>
<p><a href="https://music.163.com/#/song?id=34723470">https://music.163.com/#/song?id=34723470</a></p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/daily/using-mix-space-and-shiro#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">670f65cfa6200d7c7c214084</guid>
  <category>posts</category>
<category>日常杂谈</category>
 </item>
  <item>
    <title>从 WordPress 迁移数据到 Mix Space</title>
    <link>http://space.fosky.top/posts/experience/wordpress-to-mix-space</link>
    <pubDate>Wed, 09 Oct 2024 15:13:27 GMT</pubDate>
    <description>前言
--


Mix Space 是国人大佬开发的， UI 非常现代化，博客和空间的结合体，让人一</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/experience/wordpress-to-mix-space'>http://space.fosky.top/posts/experience/wordpress-to-mix-space</a></blockquote>
      <h2>前言</h2>
<p><a href="https://mx-space.js.org/">Mix Space</a> 是国人大佬开发的， UI 非常现代化，博客和空间的结合体，让人一眼就喜欢上了。</p>
<p>不少在 WordPress 需要插件支持的功能，在 Mix Space 却是原生支持的。</p>
<p>加上本人的博客经过 WordPress (中学无力维护)-&gt; WordPress (高中在学校没续费服务器)-&gt; WordPress (迁移) -&gt; Typecho (迁移) -&gt; WordPress 这么一系列操作后，数据已经乱七八糟了，特别是文章 ID……不知道该怎么说了，总之就是积重难返。</p>
<h2>在熟悉了 Mix Space 的功能与数据结构后，我想将 WordPress 的数据迁移至 Mix Space，但貌似没找到对应的教程，于是自己折腾了下。
步骤</h2>
<p><strong>首先</strong>搭建好 Mix Space，不用多说。</p>
<p><strong>其次</strong>使用我编写的工具，将从 WordPress 导出的 xml 数据文件转成适用于 Mix Space 的格式：</p>
<p><a href="https://github.com/FoskyM/wordpress-to-mxspace">FoskyM/wordpress-to-mxspace: 用于将 Wordpress 的数据迁移到 Mix Space。 (github.com)</a></p>
<p>你可能需要改动代码，以便适配自己的主题数据。本人使用的是 Kratos-pjax，亲测成功迁移。</p>
<p>改动步骤见此仓库的 README.md。如有 BUG，欢迎 PR。</p>
<p><strong>但这时候又涉及到一个问题</strong>：PermanentLink，即永久/固定链接，如何迁移？</p>
<p>本博客中使用的是 <code>/[year]/[month]/[day]/[slug].html</code> 的格式，</p>
<p>例如本文的地址为：<code>/2024/10/09/wordpress-to-mix-space.html</code></p>
<p>迁移到 Mix Sapce 后，它的地址就变成了 <code>/posts/experience/wordpress-to-mix-space</code> ，即 <code>/posts/[category]/[slug]</code> 的格式，</p>
<p>那么<code>[category]</code>怎么获取？在摸索后，发现 <code>/posts/[slug]</code> 会重定向到 <code>/posts/[category]/[slug]</code> ，我们只需将 <code>/[year]/[month]/[day]/[slug](.html)</code> 重定向到 <code>/posts/[slug]</code> 即可。</p>
<p>在 Nginx 的反代规则之前加上重定向规则，其中 .html 是可省略的：</p>
<pre><code class="language-">location ~ "^/(\d{4})/(\d{2})/(\d{2})/([^/.]+)(\.html)?$" {
    rewrite "^/(\d{4})/(\d{2})/(\d{2})/([^/.]+)(\.html)?$" /posts/$4 permanent;
}</code></pre><h2>当然你可能需要根据你所使用的 PermanentLink 规则来改动重定向规则。
后话</h2>
<p><del>当然因为我不确定数据是否都转换正确了，我并没有在第一时间迁移到 Mix Space，只是在本地搭建了环境进行检查。</del></p>
<p><del>若是检查无误后，本博客应该就会迁移到 Mix Space 了。</del></p>
<p> </p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/experience/wordpress-to-mix-space#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">670f4b0ae8c01b90589d26f5</guid>
  <category>posts</category>
<category>经验分享</category>
 </item>
  <item>
    <title>记一次 Dynadot 无法续费域名尝试解决</title>
    <link>http://space.fosky.top/posts/experience/dynadot-restrictions-solution</link>
    <pubDate>Sun, 06 Oct 2024 16:58:45 GMT</pubDate>
    <description>在 Dynadot 续费某个域名的时候，提示：

以下订单项目有问题。
您的账户无法提交任何新订单。</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/experience/dynadot-restrictions-solution'>http://space.fosky.top/posts/experience/dynadot-restrictions-solution</a></blockquote>
      <p>在 Dynadot 续费某个域名的时候，提示：</p>
<blockquote>
<p>以下订单项目有问题。
您的账户无法提交任何新订单。</p>
</blockquote>
<p>这算什么事？我赶忙上网查询，看到两篇帖子：</p>
<p><a href="https://hostloc.me/thread-1309317-1-1.html">dynadot无法提交任何新订单-美国VPS综合讨论-全球主机交流论坛 - Powered by Discuz! (hostloc.me)</a>
<a href="https://www.dynadot.com/zh/community/forums/Dynadot%E7%9A%84%E6%9C%80%E6%96%B0%E5%8A%A8%E6%80%81/%E5-%E5-%E6-%E6-%E7-%E8-54">域名无法续费 (dynadot.com)</a></p>
<p>感觉没有特别有用的信息，所以我当即联系在线客服，得到了 Dani Reagan 的帮助，他提到我需要更改信息并确保正确，包括账户个人信息与Whois联系信息。</p>
<blockquote>
<p>Account Information: <a href="https://www.dynadot.com/community/help/question/edit-account-info">https://www.dynadot.com/community/help/question/edit-account-info</a>
Whois contact record information: <a href="https://www.dynadot.com/community/help/question/edit-account-info">https://www.dynadot.com/community/help/question/edit-account-info</a></p>
</blockquote>
<p>但是修改后并没有效果，我睡了一觉起来又多试了几次还是不行，又重新联系在线客服 Sally，她详细说明了我需要如何填写信息</p>
<blockquote>
<p>Please make sure your information is true and valid and you have provided details such as street name and number, city/region, state and postal code in your address.</p>
</blockquote>
<p>我本想先去试试，便先感谢了她，然后她提到了关键的一句话：</p>
<blockquote>
<p>After you update your information, please email <a href="mailto:accounts@dynadot.com">accounts@dynadot.com</a> to notify them so the account team can review your account and remove the ban from your account.</p>
</blockquote>
<p>合着原来是还需要人工移除限制状态。
我马上给 <a href="mailto:accounts@dynadot.com">accounts@dynadot.com</a> 发送了邮件，和 Dynadot 团队的来往邮件如下：</p>
<blockquote>
<p>Hello,</p>
<p>Thank you for updating your information and informing us, the restrictions have now been removed and you can make new orders now.</p>
<p>All the best,
Jerry Smith
Dynadot Support Team</p>
<p><strong>Dynadot, Inc</strong></p>
<blockquote>
<p>Date: Sun, 6 Oct 2024 15:30:53 +0800
From: &quot;FoskyM&quot; &lt;<a href="mailto:i@fosky.top">i@fosky.top</a>&gt;
To: &quot;accounts&quot; &lt;<a href="mailto:accounts@dynadot.com">accounts@dynadot.com</a>&gt;
Subject: Please review my account and remove the ban from my account.
I found my account has been banned from payment.
Then I learnt that I need to update my information, I&#39;ve updated them.
So please review my account and remove the ban, thanks!</p>
<p>My account username is `fosky`.</p>
</blockquote>
</blockquote>
<p>与两位客服的交流：
 </p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/experience/dynadot-restrictions-solution#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">670f4b0ae8c01b90589d26f4</guid>
  <category>posts</category>
<category>经验分享</category>
 </item>
  <item>
    <title>安装 Scala 并使用 VSCode 调试</title>
    <link>http://space.fosky.top/posts/experience/dev-scala-with-vscode</link>
    <pubDate>Sun, 06 Oct 2024 13:56:32 GMT</pubDate>
    <description>前言
--


有一门选课名为《Spark大数据技术与应用》，运用到了 Scala。因为不想启动虚拟</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='http://space.fosky.top/posts/experience/dev-scala-with-vscode'>http://space.fosky.top/posts/experience/dev-scala-with-vscode</a></blockquote>
      <h2>前言</h2>
<h2>有一门选课名为《Spark大数据技术与应用》，运用到了 Scala。因为不想启动虚拟机，所以打算在本地配置 Scala 环境。
步骤</h2>
<h3>第一步 安装 JDK 并配置</h3>
<p>版本至少需要 17，可在此下载 <a href="https://www.oracle.com/cn/java/technologies/downloads/#java17">Java Downloads | Oracle 中国</a></p>
<p>配置环境变量 <code>JAVA_HOME</code>=安装目录</p>
<p>然后把 <code>%JAVA_HOME%/bin</code> 配置到 <code>PATH</code> 变量中</p>
<p>配置完后可在终端中运行 <code>java -version</code> 查看版本是否为 17</p>
<h3>第二步 安装 Scala</h3>
<p>版本需要 2.12.X，我使用的是 2.12.20。在此下载 <a href="https://www.scala-lang.org/download/2.12.20.html">Scala 2.12.20 | The Scala Programming Language (scala-lang.org)</a></p>
<p>下载 MSI 后直接安装即可，保险起见可在安装后重启一下。</p>
<h3>第三步 配置 VSCode</h3>
<p>安装插件</p>
<ul>
<li>Extension Pack for Java</li>
<li>Scala (Metals)</li>
<li>Scala Snippets</li>
<li>Scala Syntax (official)</li>
</ul>
<p>测试发现 Metals 会卡住，而我又不想折腾研究原因。</p>
<p>故在 .vscode 文件夹下新建 tasks.json 如下</p>
<pre><code class="language-">{
  "version": "2.0.0",
  "Shell": true,
  "args": [],
  "reveal": "always",
  "echoCommand": true,
  "windows": {
    "command": "cmd",
    "args": ["/C", "scala"]
  },
  "linux": {
    "command": "bash",
    "args": ["scala"]
  },
  "osx": {
    "command": "sh",
    "args": ["scala"]
  },
  "tasks": [
    {
      "label": "run script",
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "args": ["${file}"]
    }
  ]
}
</code></pre><p>这样就可以使用快捷键 <strong>CTRL+SHIFT+B</strong> 进行调试了。</p>
<p></p>

      <p style='text-align: right'>
      <a href='http://space.fosky.top/posts/experience/dev-scala-with-vscode#comments'>看完了？说点什么呢</a>
      </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">670f4b0ae8c01b90589d26f3</guid>
  <category>posts</category>
<category>经验分享</category>
 </item>
  
</channel>
</rss>