hero image

勿从他觅 但用此心

Just Do It

Tailwind 快速入门

前言:在接触 Tailwind 的刚开始,并没有感受到它的好处,反而觉得这是一种非常繁琐的事情,非常不适应。为了更好的使用 Tailwindcss,便有了该系列:梳理总结使用规律和用法。

章节系列共分为 7 个小节,每小节开头介绍使用规律,再介绍具体使用方法,各自小节独立可依照需求进行查阅。

Unocss 兼容 Tailwind,因此仅需学习 Tailwind 的用法即可。


Huy大约 2 分钟CSSCSS
Claude Code 原理

从零开始构建一个 Claude Code,旨在梳理 Agent 的核心原理。

智能体循环

智能体循环其实就是 ReAct Agent 模式。

核心结构:

用户 → LLM → 工具执行 → 结果 → 回到 LLM → ...(循环)

Huy大约 22 分钟框架AI
大模型对话框自动滚动是如何实现的?

在大模型对话界面中,有一个这样的逻辑:

  1. 新消息会自动滚动到底部
  2. 用户向上查看历史时,自动滚动会停止
  3. 当用户滚回到底部时,自动滚动又会恢复

这个可以用一个滚动状态机来实现。

核心逻辑

监听滚动事件,判断用户是否在底部?

  1. 如果在底部,开启自动滚动
  2. 如果不在底部,关闭自动滚动
  3. 回到底部,恢复自动滚动
const containerRef = useRef(null)
const [isAtBottom, setIsAtBottom] = useState(true)

useEffect(() => {
  const el = containerRef.current

  const handleScroll = () => {
    // 这里加一点容错;
    // scrollTop:当前滚动位置;clientHeight: 可视区域高度
    // scrollHeight: 总内容高度
    const bAtBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 10

    setIsAtBottom(bAtBottom)
  }

  el.addEventListener('scroll', handleScroll)
  return () => el.removeEventListener('scroll', handleScroll)
}, [])

useEffect(() => {
  if (isAtBottom) {
    containerRef.current.scrollTop = containerRef.current.scrollHeight
  }
}, [messages])

Huy小于 1 分钟javascriptjavascript
AI 时代的新界面:Gen UI、A2UI 和 AG-UI 到底是个啥?

最近 AI 圈出了几个新概念:Gen UI、A2UI、AG-UI。名字看着挺唬人,其实说白了,它们都在解决同一个问题——AI 怎么跟人更好地打交道

定义

1. Gen UI:界面不再固定,而是"长"出来的

以前的 App,界面是程序员提前写死的。你打开淘宝,看到的搜索框、分类栏、商品列表,都是固定的。

Gen UI 不一样。它让 AI 根据你说的话,实时生成一个最适合当下场景的界面

你说"帮我找件春天穿的薄羽绒服",AI 不会给你甩一堆文字,而是直接"长"出一个带筛选条件的商品展示界面——就在聊天窗口里。


Huy大约 3 分钟javascriptjavascript
关于 JS 中方法名大小写问题

每当觉得自己基础还可以的时候,就会发现一些以前没有注意到的点。像在 JS 中,有些方法名是全小写的,而有些方法名则是驼峰式的。

例如 instanceof 里的 of 是小写,而 indexOf 里的 Of 是大写。

看起来像是拼写不统一,其实背后是两套完全不同的命名世界

obj instanceof Array
'hello'.indexOf('e')

Huy大约 1 分钟javascriptjavascript
MCP 实录

本文记录一次 MCP(Model Context Protocol)在项目中的落地实践,不涉及具体业务细节,主要是对当时的设计思路与工程经验做一次复盘总结。

一、明确目标:AI 在业务中的真实价值

虽然现在有大量 KOL 在宣传 AI Coding、AI Agent 的生产力提升,但在真实业务中,很多时候的感受是:

工具很强,但不知道该用来干什么。

根本原因其实不在于模型能力,而在于目标不清晰

AI 在业务中的核心价值并不是“替代人类决策”,而是:


Huy大约 4 分钟javascriptjavascript
基于 Vue 简单实现一个 message 提示框

在日常开发中,像 Message.success()Message.error() 这类 API 式调用的提示框非常常见,例如 Element Plus、Ant Design Vue 都提供了类似能力。

本文基于 Vue 3,从最简单的实现入手,手写一个 message 提示框,帮助理解这类组件背后的实现原理。

一、Message 的实现思路

API 式 message 的核心思想可以总结为一句话:


Huy大约 2 分钟框架Vue
Node 中一些方法

本文用于记录常用 Node 的一些方法,方便记忆。

process 模块

processNode.js中每个应用程序都是一个进程类的实例对象

使用process对象代表该应用程序,这是一个全局对象,可以通过它来获取Node.js应用程序以及运行该程序的用户、环境等各种信息的属性、方法和事件。

进程对象属性

  • execPath 可执行文件的绝对路径,如 /usr/local/bin/node

  • version 版本号

  • versions 依赖库的版本号

  • platform 运行平台。 如 darwinfreebsdlinuxsunoswin32

  • stdin 标准输入流可读流,默认暂停状态

  • stdout 标准输出可写流,同步操作

  • stderr 错误输出可写流,同步操作

  • argv 属性值为数组。 如 node your-script.js arg1 arg2 arg3, 则 :

    console.log(process.argv)
    // 输出结果为:
    [
      '/usr/local/bin/node', // process.argv[0]:Node 可执行文件路径
      '/path/to/your-script.js', // process.argv[1]:你运行的脚本路径
      'arg1', // 从 argv[2] 开始是你传的参数
      'arg2',
      'arg3',
    ]
    
  • env 操作系统环境信息

  • pid 应用程序进程 ID

  • title 窗口标题

  • arch 处理器架构 armia32x64


Huy大约 6 分钟javascriptnode
再论 Buffer

本文重新梳理一遍 Node.js 中的 Buffer 概念和使用方法。

为什么需要 Buffer?

在 Node.js 中,Buffer 是处理二进制数据的核心对象。JavaScript 本身是基于 Unicode 的字符串处理,但在网络通信、文件操作等场景中,我们经常需要处理原始的二进制数据。Buffer 提供了一种高效的方式来存储和操作这些数据。(Blob 不能直接进行数据的处理,ArrayBuffer 不能直接操作二进制数据,而 Buffer 则可以直接操作二进制数据)


Huy大约 4 分钟javascriptnode
大文件上传

此前简单梳理过一次大文件的分片上传,这里又重新实现一遍。功能点加上秒传、断点续传、web worker 等。

前端简单用 vite + react19 + antd + axios 实现。后端用 express 实现。代码仓库

功能点总结

  1. 前端分片上传与断点续传

    • 文件切片:用 File.prototype.slice 将大文件分割为多个小块(chunk),每块独立上传。
    • 断点续传:上传前先向后端查询已上传分片,前端只上传未完成的分片,实现断点续传和秒传。
    • 上传进度管理:每个分片上传时通过 onUploadProgress 事件实时更新进度条,整体进度通过所有分片进度的平均值计算。
    • 取消与暂停:利用 axiosCancelToken 实现上传任务的取消和暂停,支持恢复上传。
  2. Web Worker 计算文件 hash `- Web Worker 基础:用 Worker 在浏览器主线程外异步计算大文件 hash,避免 UI 卡顿。

    • 主线程与 Worker 通信:通过 postMessageonmessage 实现主线程与 Worker 的数据交互。
    • SubtleCrypto API:在 Worker 内用 crypto.subtle.digest 计算文件内容的 SHA-256 hash,生成唯一文件名。
  3. React 组件与自定义 Hook

    • 自定义 Hook:用 useDrag 实现拖拽上传、点击上传、文件校验、预览等功能,提升组件复用性。
    • useRef/useState/useEffect:管理 DOM 引用、状态和副作用,确保事件监听和资源释放的正确性。
  4. Node.js 服务端分片处理

    • Express 路由设计:实现 /api/upload(分片上传)、/api/check(查询已上传分片)、/api/merge(合并分片)等接口。
    • 流式处理:用 fs.createReadStreamfs.createWriteStream 实现分片的高效写入和合并,避免大文件占用过多内存。
    • 慢速 Transform 流:自定义 SlowTransform,通过 setTimeout 控制写入速度,方便前端调试进度条和断点续传。
    • 分片合并与 hash 校验:合并所有分片后,流式计算合并文件的 hash,与前端生成的 hash 比较,确保文件完整性。
  5. 性能优化

    • 并行上传与合并:前端并行上传多个分片,后端可并行或串行合并,提升效率。
    • 内存优化:所有大文件操作均采用流式处理,避免内存溢出。
    • 兼容性与用户体验:支持拖拽、点击、进度反馈、错误提示、断点续传等,提升易用性。

Huy大约 3 分钟javascriptnode
2
3
4
5
...
18

Yesterday is history, tomorrow is a mystery, today is a gift of God, which is why we call it the present.