2026-01-27 00:17:00
早上九点,顺风打电话来:"快递到了,放前台了啊。" 估摸着是那三脚架到了
这东西没有真不行,晚上出门一抹黑,不用长曝光,啥都拍不了
我有三个需求:轻量化、收纳短、伸缩1.5m,再三选择后,下单了富宝图旗下新品,空气三号 LITE
图一拆包后,我直接蒙了
周日在群里扯淡,看到 菜鸟之志 推荐的八爪鱼支架,我笑了,这什么玩意,长得那么招笑
真的受够了这种秒懂的日子
还别说,这工具不错,小巧,轻便,灵活度很高,推荐



八爪鱼是送的,但图三这个快拆套装我感觉买亏了。加了一百块钱,就换回这么一小块铁片,关键脚架本身就带一个

出门前纠结了半天要不要背双肩包,最后想想算了,索性直接挂在包拉链上了

有没有一种吕布骑狗的感觉,我这破尼康配上这个架子,多少有点高攀了





今天全程下雨,走在西湖边吹冷风,冻得头疼
回家发现买的电池也到了,价格方面,只有原装的二分之一,应该够我折腾了
天知道这支架是哪个小作坊代工的,漆水和碳布的质量,不敢苟同,我最垃圾的鱼竿,破烧火棍的碳纤维材料都比这个强,不如高性能的铝材料,甚至不如玻璃钢
他的旋转设计也有缺陷,不容易锁紧,又不敢用力拧,因为碳布根本受不了这种扭矩,哪怕你有交叉工艺,也顶不住,这不符合物理规律
再加上碳纤维这东西本身就是消耗品,树脂会氧化。三脚架这玩意,风吹雨打的,扭矩承受力只会越来越差。网上已经看到不少人把它拧断了,总之不推荐
2026-01-24 05:50:00
这两天突发奇想,在赶一个新项目
从早上 8 点写到晚上 11 点,除了去卫生间,人基本没动过,饭也没吃
这不是我多能坐得住,我只是倔
妄想一步登天,做不完就死磕。十几个小时是日常,通宵是常态,哪个月没有 4~5 次 20h + 作战记录?
GitHub Commits 一眼就能看出来:我从凌晨提交到凌晨,电子厂的狗都不会这么干
也许这就是倔驴 + 心流?
而我,天生心流圣体
老实说,我对“心流”没概念,只是前阵子偶然了解到。所以我并不明白,但我知道那是一种状态
当然,不吃饭是不行的
晚上 11:30,厨房炒个菜,微波炉热两个馒头,回屋再冲一大杯黑咖啡,两勺燕麦,少许牛奶,就算齐活
坐回电脑前,打开 BlogFinder,随手一翻,看到了阮一峰的周刊
心想,周五了
低头再看,周六了
然后,我看到了他的第一个推荐文章,心里“咯噔”一下:
点进去,翻译看看,整篇文章的核心观点就是:
如果你在意开源软件,就应该停止使用 MySQL
MySQL 虽然是基于 GPL v2 开源,实际上已经没有开源精神,因为 MySQL 正走向封闭

这是 Otto 在 1 月 11 日给出的截图
数据显示,从去年 9 月开始,到今年 1 月 11 日,MySQL 几乎完全断更
我看到这里,第一反应是去查官方信息 MySQL 核心团队博客,无果后,再 Google 一下,事情就对上了
早在 9 月 11 日,外媒就曝出 Oracle 大幅裁减 MySQL 核心员工 (约 70 人) 的消息,甚至还有传闻称,MySQL 团队已被并入 HeatWave 部门,Oracle 要把资源优先投入 AI
新闻刚出来时,MySQL 还没断更
现在再把这张“断崖式提交图”放出来,那可谓是深水炸弹
更有意思的是,Otto 还特意把图做成黑白,再配上大字标语当封面
手段可见一斑,毕竟,这人是 MariaDB Foundation (玛利亚数据库基金会) CEO
而 MariaDB 是 MySQL 的最重要的分支与直接竞争者
当年 Oracle 宣布收购 Sun Microsystems 的当天,MySQL 原始作者之一 Monty Widenius 就发起了 MariaDB fork
有意思的是:
就连 MariaDB 的 LOGO 海狮,也是有故事背景的
It happened when Monty and his older daughter My were snorkeling on one of the islands in the Galapagos. Something big, brown and fast suddenly appeared at an arm’s distance, laughing in their faces. Fond memories of this fast and funny creature, scaring the tourists, popped into Monty’s mind when asked picking a logo for MariaDB. He wanted to adhere to the tradition of animals as symbols of Open Source projects.

下面是 Otto 的举证,他认为 MySQL 所有开发工作都在 Oracle 内部进行
而公开的 Bug 追踪器只是个摆设,Oracle 内部有自己的系统
更离谱的是,他声称:
那些提交 PR 的人,除了石沉大海,就只剩下第二个选择
被 Oracle 员工重新编写并抹去原作者的贡献记录,原作者仅在博客中被提及其名
Otto 还证言道:
我在 AWS 负责 RDS MySQL 和 MariaDB 团队时,部门员工极其抗拒向 MySQL 提交代码,因为Oracle 的接纳态度极其恶劣
MySQL 8.0.29 将 ALTER TABLE 的默认行为改为 in-place
而这个问题,直到 8.0.32 才算彻底修完
更大的问题在于:
自 MySQL 8.0 发布以来,整整六年,没有一次真正意义上的大版本更新,几乎没有像样的功能可以讲
甚至,有传言新版本的 MySQL 性能大幅下降,之后被 MySQL 性能专家 Mark Callaghan 进行基准测试后得出MySQL 9.5 的吞吐量比 8.0 版本竟然低了 15%
最后,Otto 顺势给出了“迁移方案”:
说自家的 MariaDB 作为 MySQL 的亲兄弟,有极高的兼容性,对于传统 LAMP 架构,可以无缝切换
他说得也没错,MariaDB 起源于 MySQL 5.1 分支,早期开发策略几乎完全对标 MySQL,以至于后来被开源社区认可,尤其在 Debian、Ubuntu、Fedora 等发行版中,直接成为默认数据库

说实话,我已经不想看下去了,我只是个普通人,一个喜欢编程的小学生
从初一第一次接触数据库开始,就是 MySQL
从上学、工作,到后来失业
我靠它吃了很多年饭
刚毕业那会儿,我为了面试,背得最多的就是 MySQL
对着镜子:一会儿 Indexing、一会儿 Concurrency 人都要疯了
所以,我对 MySQL,是有感情的
现在它要没落了,心里说不出的滋味
虽然国内教学体系还在用 MySQL,但现实已经很清楚了
MySQL 不可能再回到从前老大哥的位置了
哎,天道如来,也罢
2026-01-23 10:05:00
今天聊聊所谓的“劣根性”,这是碰都不能碰的滑梯
自西贝事件以来,某些“二流报纸”先后两次下场定调,蹭流量的自媒体紧跟实事充当“叼盘”
群众一看,纷纷跳出来表态,生怕队站得慢了
就好像你官媒一说话,事情就“定性”了?下面的人尾巴竖得比狗都直,太激进,太可怕了
也是,宪法都随便改的国家,这确实算不了什么
陈丹青曾对“原则问题”有过精辟的论述:
中国人是不讲原则的,这既是最坏的地方,也是最好的地方
哎,就什么东西他妈的“有用”,就拿来用。没用就打倒他,结果翻出来还有用,再拿出来
说句难听的,民族劣根性
话到嘴边打不住,我大抵是要挨骂了
毕竟你在这个国家,你说他不好,他们就会说你是洋奴
如果你说外国好,走狗是免不了的
如果你说要入籍日本,汉奸的帽子也要扣上
但是,若你闭口不言,悄悄入籍日本,那你就是成功人士
若入了外籍,还说很爱国,恭喜你,摸到名利的门槛了
若你把老婆孩子移居境外,自己却在国内教别人如何爱国,这最起码是个处长
写到这,我心里很难受
我爱我的国家,我为中国的悠久历史文化而自豪,我为唐宋八大家的文学思想而感到骄傲
可如今,一切都变了,真的乱了套
昧着良心说假话的人,生活的有滋有味
而寻找真理追求真相的人,却苦不堪言,甚至还有失去自由的危险
回望当年的庐山会议,多少人为了活命出卖同僚?
有多少人,眼睁睁看着彭老总从成都被揪到北京批斗游街?一度打到瘫痪,囚于暗室,死不瞑目
又有多少人,为了党的先进性和纯洁性,为了完成自我革命,而检举揭发与自己同床共枕几十年的爱人,甚至是自己的孩子
有党性,没人性
这句话,我曾在王局的节目评论区看到过
而我认为,真正有党性的人,凤毛麟角
如毛的秘书李锐、中央党校教授蔡霞等等,他们在坚持原则的同时,从不失有人性的光辉
那些只剩党性、泯灭人性的东西,他们哪来的信仰?不过是借党性之名,道貌岸然地活着,却早已不是人了
说到底,中国人是没有信仰的,都是为了活着,活着最要紧
至于独立思考是什么,早已抛在脑后
想一想,中国发展了千年文明,从先秦诸子百家到宋明理学,再到改革开放引进西方科学
可回过头看,中国人连独立思考都未曾普及,尤其是批判性思维和质疑权威的能力,那是碰都不能碰的滑梯
所以中国人就缺乏鉴赏能力,什么都是和稀泥,没有是非,没有标准
就喜欢讲道德,讲儒家那点奴性思维,以至于,法治社会,人没有人格,法律没有尊严
在这种环境下,人性都畸形了:
一方面逆来顺受,自甘卑贱屈辱贫寒而不自知
另一方面,一朝得势,便以贵凌贱以富凌贫,加倍压迫自己的同胞
这种轮回,在史书里转了数千年,直到今天,天安门依然贴着“万岁”,纯奴性
2026-01-18 23:48:00
这事半个月前就计划好了,本想放到 Photosuite 下个版本里
拖到现在,若不是为了昨天拍的一套图,我也懒得折腾
就是为了这口醋,才包的这顿饺子
我的目的很简单:不引入新的语法,而是通过换行来实现拼图
在 Markdown 中连续插入多张图片,只要它们之间没有非空白内容,就应被视为一个整体自动组合





拼图分组思路由贪心算法实现:
当扫描到一张图片时,以它为起点向后遍历,将所有连续相邻的图片依次纳入同一组
一旦相邻关系被打断,就停止扩展,并根据组内图片数量决定是否生成拼图(不足两张则原样保留)
难点在于“相邻”的定义:
因为 Markdown 编译为 HTML 后,图片容器之间可能夹杂换行符或空白文本节点
所有,不能直接依赖 nextSibling 进行判断
// src/modules/imageGrid.ts
/**
* 检查两个容器是否相邻
*
* @param container1 - 第一个容器
* @param container2 - 第二个容器
* @returns 是否相邻
*/
function areContainersAdjacent(container1: HTMLElement, container2: HTMLElement): boolean {
// 获取两个容器的父元素
const parent1 = container1.parentElement;
const parent2 = container2.parentElement;
// 如果父元素不同,不是相邻的
if (parent1 !== parent2 || !parent1) return false;
// 获取父元素的所有子元素
const siblings = Array.from(parent1.children);
const index1 = siblings.indexOf(container1);
const index2 = siblings.indexOf(container2);
// 检查是否相邻(中间只能有文本节点或空白节点)
if (index2 !== index1 + 1) {
// 检查中间是否只有空白文本节点
let hasNonWhitespace = false;
let node = container1.nextSibling;
while (node && node !== container2) {
if (node.nodeType === Node.ELEMENT_NODE) {
hasNonWhitespace = true;
break;
}
if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) {
hasNonWhitespace = true;
break;
}
node = node.nextSibling;
}
return !hasNonWhitespace && node === container2;
}
return true;
}
在解决了相邻判定的问题之后,分组逻辑本身就变得很简单了
当 Photosuite 扫描到一张图片时,会从当前位置向后查找连续相邻的图片,并将它们归为一组
出于美观考虑,我这里将单组图片数量限制为最多三张
// src/modules/imageGrid.ts
function processImageGrids(root: Element) {
// 获取所有图片元素
const images = Array.from(root.querySelectorAll("img"));
// 用于标记已处理的图片
const processed = new Set<Element>();
for (let i = 0; i < images.length; i++) {
const img = images[i];
// 跳过已处理的图片
if (processed.has(img)) continue;
// 检查是否可以形成拼图
const gridImages = [img];
processed.add(img);
// 查找连续的图片(最多3张)
for (let j = i + 1; j < images.length && gridImages.length < 3; j++) {
const nextImg = images[j];
// 检查两个图片容器是否相邻
const currentContainer = ensurePhotosuiteContainer(gridImages[gridImages.length - 1]);
const nextContainer = ensurePhotosuiteContainer(nextImg);
if (areContainersAdjacent(currentContainer, nextContainer)) {
gridImages.push(nextImg);
processed.add(nextImg);
} else {
break;
}
}
// 如果找到了多张连续的图片(2-3张),创建拼图
if (gridImages.length >= 2) {
createImageGrid(gridImages);
}
}
}
我用 Boardmix 做了一个流程图,通俗易懂:

把图片简单地放进一个 Flex 容器并不难
如果一张是横图(16:9),另一张是竖图(9:16),直接使用 flex: 1 只会让它们宽度相同,却无法保证高度一致,结果要么高低不齐,要么图片被强行拉伸
要让多张图片在同一行里等高对齐,关键不在 Flex,而在比例关系
直观来说:哪张图片更“扁”,就应该占更宽的位置;哪张更“瘦”,就占得窄一些,这样它们的高度才能最终一致
用更具体的话说:
每张图片在一行中所占的宽度,应该和它本身的宽高比成正比
宽高比越大(越横),分到的宽度就越多;宽高比越小(越竖),分到的宽度就越少
因此,在等高布局下,可以把每张图片的宽度理解为:
每张图片的宽度占比 ≈ 自身宽高比 ÷ 所有图片宽高比之和
其中:
宽高比 = 宽 / 高
基于这个思路,我没有让 Flex 自由分配空间,而是先计算好每张图片应占的宽度,再通过 flex-basis 精确控制布局
具体实现上,会先异步获取每张图片的宽高比,计算出总比例后,将容器宽度按比例拆分。同时考虑到图片之间的间距(gap),使用 calc() 对最终宽度进行修正,避免累计误差
// src/modules/imageGrid.ts
/**
* 异步更新拼图项宽度
* 基于图片宽高比计算宽度,使得所有图片高度一致
*/
async function updateGridDimensions(images: HTMLImageElement[], gridItems: HTMLElement[]) {
const ratios: number[] = [];
// 获取所有图片的宽高比
for (const img of images) {
const ratio = await resolveImageRatio(img);
ratios.push(ratio);
}
// 计算总比例
const totalRatio = ratios.reduce((sum, r) => sum + r, 0);
const gapCount = gridItems.length - 1;
// 设置每张图片的宽度百分比
gridItems.forEach((item, index) => {
if (totalRatio > 0) {
const ratio = ratios[index];
const percent = (ratio / totalRatio) * 100;
// 使用 calc 计算实际宽度:(比例% * 100) - (gap总宽 * 比例占比)
// 公式: calc(33.33% - (2 * var(--gap) * 0.3333))
const widthCalc = `calc(${percent}% - (${gapCount} * var(--photosuite-grid-gap, 4px)) * ${ratio / totalRatio})`;
// 设置 flex-basis 和 max-width
item.style.flex = `0 0 ${widthCalc}`;
item.style.maxWidth = widthCalc;
}
});
}
这样一来,不管图片比例多么悬殊,它们在拼图中都会自然对齐
高度一致、宽度合理、边缘整齐,同时也避免了任何形式的拉伸或裁剪
样式只负责布局:Flex + gap + 响应式间距,没有额外装饰,所有空间都留给图片本身
这里通过 CSS 变量统一管理间距;在移动端则适当缩小 gap,以保证有限屏幕宽度下的视觉紧凑度
// src/styles/image-grid.scss
/* 拼图容器 */
.photosuite-grid {
--photosuite-grid-gap: 4px;
display: flex;
gap: var(--photosuite-grid-gap);
width: 100%;
margin: 0;
padding: 0;
align-items: flex-start;
}
/* 移动端保持拼图布局,但减小间距 */
@media (max-width: 768px) {
.photosuite-grid {
--photosuite-grid-gap: 2px;
}
}
在交互层面,加了点人情味,当鼠标悬停在图片上时(拼图状态),会有一个轻微的放大效果
注:使用该功能无需配置,默认为
imageGrid: true拼图状态下不显示 EXIF 和标签,它们在编译阶段并未生成
至此,完成
感谢 Claude Code、Gemini、ChatGPT 对项目的大力支持
Photosuite 已发布至 npm,可直接安装:
pnpm add photosuite
# or
npm install photosuite
# or
yarn add photosuite
2026-01-13 00:39:00
晚上刷 1900 的博客,我忽然想起了 主题配色切换动画
随手输入关键字 “主题” 一搜,果然找到了那篇:给博客主题切换加个动画
看到左上角的发布日期时,不禁有些感叹,原来这已经是半年前的事了

实现思路与 1900 类似,本质上是利用 View Transitions API 接管视图更新,从而实现遮罩动画
通过 document.startViewTransition 捕获 DOM 快照,再配合 CSS 的 clip-path(裁剪路径)实现平滑过渡:
const transition = document.startViewTransition(() => {
themeValue = themeValue === "light" ? "dark" : "light";
setPreference(true);
});
transition.ready.then(() => {
// 从上至下的裁剪路径
const clipPath = [
'inset(0 0 100% 0)', // 开始:底部被完全裁剪
'inset(0 0 0 0)', // 结束:完全显示
];
document.documentElement.animate(
{ clipPath: clipPath },
{
duration: 1000, // 长动画,可能会掉帧
easing: "ease-out",
pseudoElement: "::view-transition-new(root)",
}
);
});
此外,我还给博客增加了两个功能按钮,灵感借鉴自 SeerSu,他的博客设计非常线性,我很喜欢
class="fixed bottom-6 md:bottom-8 z-50 w-10 h-10 rounded-md bg-white/40 dark:bg-gray-900/40 backdrop-blur-md border border-white/50 dark:border-gray-700/50 text-gray-700 dark:text-gray-200 shadow-sm hover:bg-white/70 dark:hover:bg-gray-800/70 hover:scale-110 hover:shadow-lg transition-all duration-300 ease-out translate-y-8 opacity-0 pointer-events-none flex items-center justify-center gap-1"
整体视觉设计上,采用了玻璃风格,悬停时有缩放效果
当页面向下滚动到一定范围,该按钮才会浮现,并自动调整“返回按钮”的位置
// 监听 BackToTop
window.addEventListener("backToTopVisibilityChange", e => {
// 如果回到顶部按钮出现,返回按钮自动向上移动让出位置
updateVerticalPosition(e.detail.visible);
});