ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Claude Code Hooks 详解:从六个触发时机到实战配置

Claude Code Hooks 详解:从六个触发时机到实战配置 最近在折腾 AI 编程辅助工具的朋友大概率都听说过 Claude Code 这个名字。它算是 Anthropic 官方推出的命令行编程代理直接在终端里和代码仓库对话能读代码、改文件、跑命令、提 PR一套流程走下来比之前那些聊天框里给代码片段的工具强了好几个量级。 GitHub 上的热度一直居高不下社区里的讨论从安装方法一路卷到插件生态确实热闹。不过我看了一圈发现大多数人聊 Claude Code 都停留在怎么装、怎么用、怎么接 VSCode这个层面真正把它从个人玩具变成生产工具的高级功能反而聊得很少。这里最值得花时间研究的就是 Hooks。Hooks 直译就是钩子它在 Claude Code 的工作流程里预埋了六个关键的挂载点允许你在 Claude 执行工具之前、之后、在你提交提示词的时候、在每一轮任务结束的时候自动运行你自己的 shell 命令、脚本或者程序。它的价值在于AI 模型有随机性这次记得缩进四个空格下次可能就忘了但脚本没有随机性只要挂上去每次都执行。格式、规范、安全检查、通知提醒这类确定性要求交给 Hooks 来兜底是让 Claude Code 稳定可用的关键一环。这篇文章我就围绕 Claude Code Hooks 这个功能展开从它的设计思路、六个触发时机到完整的配置语法、环境变量、退出码约定再到可以直接抄作业的实战案例和排错经验系统地捋一遍。如果你已经装好了 Claude Code想在项目里建立一套自动化护栏或者你是团队的 AI 编程推广者希望让组里的使用姿势更规范这篇应该能给你不少启发。1. 项目概述为什么说 Hooks 是 Claude Code 的分水岭1.1 Hooks 解决的确定性问题用过 Claude Code 的朋友都有一个感受它在开放性任务上表现非常好但稳定性是需要在工程上补的短板。什么叫稳定性举个例子你告诉 Claude每次改完文件都要跑一下 prettier它在当前轮次里可能是遵守的可一旦上下文很长、任务很多它可能就漏了又比如你担心它执行rm -rf这种危险命令模型判断这个命令应该没问题的阈值和我们人不一样真出了事后悔都来不及。Hooks 解决的就是这类模型不可承诺的问题。它的思路非常朴素在工具调用链路上插入确定性的脚本拦截点。脚本不是模型模型会忘脚本不会脚本也不是模型模型有概率判断失误脚本是白名单/黑名单逻辑只有 0 和 1。所以 Hooks 特别适合承担三类职责护栏职责拦截危险命令、校验文件格式、阻止越权操作自动化职责格式化、静态检查、跑测试、同步文档上下文增强职责把 git 状态、构建产物、最新日志注入给模型让它在总结或下一步行动时掌握完整信息。这三类职责看起来简单但放到 AI 编程的实际场景里每一类都能解决一个具体的痛点。我自己最早用 Hooks 就是因为被 Claude 的一次误操作搞怕了——它在一个不该执行git push的目录里执行了推送虽然没造成严重后果但那种不可控感确实让人心里发毛。后来把关键操作全部用 Hooks 管控起来这种焦虑才真正降下来。1.2 Hooks 与插件、MCP 的边界这里要稍微区分一下概念。Claude Code 生态里还有别的扩展方式比如 MCPModel Context Protocol服务器它解决的是模型能力边界问题让 Claude 能操作更多外部工具和数据源而 Hooks 解决的是流程控制问题它在模型行为的外围做钩子不改变模型本身的能力只在你指定的节点上强制执行你的脚本逻辑。打个比方MCP 是给厨师提供更多的食材和厨具Hooks 则是定在厨房里的流程检查点——切完菜必须把刀放回刀架、出锅前必须试味。两者是可以共存的Hooks 甚至可以在某些节点上调用 MCP 服务但它们解决的问题维度完全不同。想通了这一点你就知道该在什么时候用 Hooks 了只要这个动作是必须无条件执行的就放进 Hooks只要是模型可以灵活判断的就留给提示词和工具调用。把两者分清楚你的 Claude Code 才能既灵活又可控。这也是我判断一个团队 AI 编程成熟度的标准只看他们有没有一套成体系的 Hooks 配置大概就能猜出来。2. 六个触发时机Hooks 的完整生命周期Hooks 不是凭空运行的它有六个明确的触发时机。我把它们分成三组来看这样比较好记。2.1 PreToolUse 与 PostToolUse工具调用前后的闸门第一组是 PreToolUse 和 PostToolUse它们在 Claude 调用任何工具时触发。PreToolUse 发生在工具执行之前PostToolUse 发生在工具执行之后。PreToolUse 是最常用的护栏位置。它的 matcher 可以匹配工具名比如Edit、Write、Bash、Read等。你可以用正则表达式同时匹配多个工具例如Edit|Write表示任何修改文件的操作都要先经过你的脚本。这个阶段最经典的应用就是危险命令检查Claude 想执行一条Bash命令你的 hook 脚本先检查命令内容如果包含危险模式脚本返回退出码 2这次工具调用就会被直接取消Claude 会收到该操作被 hook 拒绝的信息转而寻找替代方案。PostToolUse 则适合做事后验证和善后。比如每次Write或Edit之后自动跑一遍 prettier 或 gofmt把格式修正回来或者每次文件写入后检查有没有临时文件残留。你还可以在这一阶段收集工具执行的结果写入日志为审计和排查留下记录。我的经验是PreToolUse 解决能不能做的问题PostToolUse 解决做完了怎么收尾的问题两者配合起来工具调用这条链路才算完整可控。2.2 UserPromptSubmit 与 Notification人机交互的关键节点第二组是 UserPromptSubmit 和 Notification。UserPromptSubmit 在用户向 Claude 提交提示词时触发matcher 匹配的是提示词文本。也就是说你可以对用户输入做集中检查。比如团队里约定不允许在对话里贴密钥、不允许让 Claude 连接生产环境数据库一旦检测到敏感关键字脚本可以拒绝提交或者追加一条警告。还有一个很有用的场景在提示词进入模型之前把你的团队编码规范文件内容附加到上下文里让 Claude 每次都能基于最新规范来响应。这一招对团队推广特别管用因为你不必反复在提示词里强调规范系统会帮你自动带上。Notification 则是在 Claude Code 需要向用户发通知时触发。通常是在后台运行、有耗时任务、或者 Claude 希望用户注意某些状态的时候。你可以利用这个节点把通知转发到桌面弹窗、手机、微信群或者内部的 IM 机器人。比如让 Claude Code 跑完一个长测试后通过 hook 触发notify-sendLinux或者osascriptmacOS弹出桌面提示。这样你就可以放心地让它干着活自己去忙别的事情。2.3 Stop 与 SubagentStop回合结束和子代理收尾第三组是 Stop 和 SubagentStop。Stop 在 Claude Code 完成一轮处理turn之后触发。这个节点的特殊之处在于脚本的 stdout 输出会被送回 Claude作为下一轮对话的一部分上下文。什么意思呢Claude 每轮结束时其实相当于要做一次收尾理解如果你能在这个时点把仓库的关键状态喂给它比如当前的 git diff、最近一次测试结果、新增了哪些文件它就能在下一轮任务里带着更完整的上下文继续干活。很多团队用这个 hook 来实现记忆增强——不需要额外的向量数据库就把关键状态自动附加到每一轮对话里。SubagentStop 则是当 Claude 使用子代理subagent完成任务后触发。Claude Code 支持把一个复杂任务拆给多个子代理并行处理每个子代理跑完都会触发 SubagentStop。它的场景主要是监控和汇总你可以把每个子代理的结果输出到日志或者做统一的质量检查确保子代理的结果符合要求再并入主线程。为了让你看得更清楚我把六个触发时机的名称、触发点、匹配对象和典型用途整理成一张表触发时机触发点匹配对象典型用途PreToolUse工具执行前工具名危险命令拦截、权限检查PostToolUse工具执行后工具名自动格式化、日志记录、质量校验UserPromptSubmit用户提交提示词时提示词文本敏感信息过滤、注入团队规范NotificationClaude 需要通知时无桌面推送、IM 消息转发Stop每一轮处理完成后无注入仓库状态、持久化上下文SubagentStop子代理完成后无子代理结果汇总、质量检查3. 配置与细节matcher、环境变量和运行参数3.1 settings.json 的结构与层级Hooks 的配置位于 settings.json 里。Claude Code 有两层配置用户级配置在~/.claude/settings.json项目级配置在项目目录下的.claude/settings.json。项目级配置会覆盖用户级配置这是标准的层级逻辑。如果你想对某个项目做特殊的 Hooks 约束就放到项目级的文件里如果是通用的、所有项目都适用的放到用户级。配置文件的基础结构是这样{ hooks: { PreToolUse: [ { matcher: Bash, hooks: [ { type: command, command: python ~/.claude/hooks/check_command.py, timeout: 10 } ] } ] } }每个触发时机下面是一个数组数组里的每个元素称为一个hook 规则。每个规则包含两部分matcher用正则表达式指定匹配范围hooks则是实际要执行的命令列表。一个规则下可以挂多个命令它们会按顺序执行。这里有个容易踩的坑JSON 格式对逗号和引号非常敏感一个多余逗号就会导致整个配置失效。我建议写完配置后先用jq . settings.json或者是 Python 的json.tool模块做一次语法校验再重启会话验证。比起在 Claude Code 里发现 hook 不生效再回头找 JSON 语法问题提前校验能省下不少时间。3.2 matcher 匹配规则的精妙之处matcher 是正则表达式这个设计很值得玩味。因为正则既能精确匹配单个工具名又能通过|匹配一组工具还支持一种特殊前缀。比如Edit|Write匹配所有修改文件的工具Bash匹配所有的 shell 命令执行$Bash(git diff)带$前缀时可以匹配命令的子串比如只在执行git diff的时候触发其他 Bash 命令不受影响。$前缀这个功能是我个人最推荐的。它把规则范围精确到了某个具体子命令而不是一刀切地管所有 Bash 调用。比如我想在 Claude 执行git push前自动跑一遍检查就写$Bash(git push)这样既不影响其他 Bash 操作又能精确卡住推送这个动作。实际使用中这种精确匹配能大幅减少误伤和噪音。另外matcher 是正则所以工具名的大小写也要注意。Claude Code 的工具名都是驼峰格式比如Read、Write、Edit、Bash不同版本可能略有差异。如果你发现 hook 没生效先确认 matcher 跟实际工具名完全匹配这个排查成本最低但出问题概率最高。3.3 hook 脚本能拿到的环境变量Hook 脚本运行时会拿到一串 Claude Code 注入的环境变量这是 hook 脚本获取上下文的主要途径。常用的有这么几个CLAUDE_PROJECT_DIR项目根目录的绝对路径CLAUDE_PWD当前工作目录CLAUDE_TRANSACTION_ID当前事务的唯一 ID用于日志关联CLAUDE_PROMPT_TS提示词的时间戳CLAUDE_SESSION_ID当前会话的 IDCLAUDE_TOOL_NAME触发 hook 的工具名仅在 Pre/PostToolUse 时存在CLAUDE_TOOL_USE_ID工具调用的 ID同上CLAUDE_AGENT子代理名称仅在 SubagentStop 时存在CLAUDE_SUBAGENT_TRANSACTION_ID子代理事务 ID同上。我举个具体用法在 PostToolUse 的钩子里要写日志你可以直接拼一个 JSON 行echo {\time\:\$(date -Iseconds)\,\tool\:\$CLAUDE_TOOL_NAME\,\project\:\$CLAUDE_PROJECT_DIR\,\pwd\:\$CLAUDE_PWD\} /tmp/claude_hook.log这样每次工具调用后都会追加一条结构化日志后面想排查问题直接 grep 这个文件就行。注意环境变量要在 hook 脚本里用双引号包住避免路径里带空格导致脚本解析错误这个细节在新手脚本里很常见。3.4 timeout 与 async别让钩子拖垮主流程每个 hook 命令都可以配置timeout单位是秒默认是 60 秒。如果你的脚本逻辑比较复杂比如要跑一次完整的测试记得把 timeout 调大反过来如果只是一个快速的校验脚本可以调小避免 Claude Code 等待太久。还有一个async参数。设成true时hook 会异步执行不阻塞 Claude Code 的主流程。这个设计非常适合通知类和日志类的 hook——通知发不出去不影响干活日志写慢一点也无所谓。但要注意异步 hook 的输出不会回传给 Claude所以不能指望用异步钩子做上下文注入或工具拦截。拦截和校验必须用同步 hook这是原则。我个人的分配建议是拦截类、校验类、状态注入类全部同步通知类、埋点类、日志类全部异步。这样既保证了关键节点的确定性又不让无关紧要的脚本拖慢整体响应速度。4. 实操案例四个能直接抄的 Hooks理论讲完直接上硬菜。下面这几个案例是我自己在项目里验证过、觉得稳定度很高的做法配置文件都是可以直接复制修改的。4.1 案例一给 git push 加一道预检闸门这个案例用 PreToolUse 加$前缀匹配精确拦截git push到受保护分支的行为。目标是只要 Claude 想往 main 分支推送直接拒绝不让它碰运气。先写脚本~/.claude/hooks/check_before_push.sh#!/bin/bash current_branch$(git rev-parse --abbrev-ref HEAD) if [ $current_branch main ] || [ $current_branch master ]; then echo BLOCKED: pushing to $current_branch is not allowed via Claude Code exit 2 fi if ! git diff --quiet; then echo WARNING: you have uncommitted changes, but continuing... 2 fi echo push precheck passed exit 0然后在 settings.json 里挂上{ hooks: { PreToolUse: [ { matcher: $Bash(git push), hooks: [ { type: command, command: bash ~/.claude/hooks/check_before_push.sh, timeout: 10 } ] } ] } }关键点在于exit 2。Claude Code 的约定是PreToolUse 阶段退出码 2 表示阻止这次工具调用。脚本里输出的BLOCKED: ...会被 Claude 看到它会理解这次操作被拒绝然后换一种方式完成任务比如创建一个分支再推送。整个过程不需要人工介入但安全边界守住了。为什么用$Bash(git push)而不是匹配所有Bash因为如果匹配所有 Bash脚本会在每次 Claude 执行任何命令时都跑一遍噪音非常大。用$前缀把匹配范围缩小到 git push脚本只在该拦截的地方出现其他操作完全不受干扰。4.2 案例二Edit/Write 之后自动格式化这个案例用 PostToolUse目标Claude 每次修改文件之后自动对项目跑一次格式化保证代码风格统一。配置长这样{ hooks: { PostToolUse: [ { matcher: Edit|Write, hooks: [ { type: command, command: bash ~/.claude/hooks/autofmt.sh, timeout: 30 } ] } ] } }脚本#!/bin/bash # 根据项目类型选择格式化工具 if [ -f package.json ]; then npx prettier --write $CLAUDE_PWD 2/dev/null || true elif [ -f go.mod ]; then gofmt -w . elif [ -f pyproject.toml ]; then ruff format . fi几个经验点第一脚本最后加|| true。为什么因为 hook 脚本退出码非 0 时stderr 内容会被报告给 Claude虽然不一定中断流程但会造成噪音甚至让 Claude 误以为出了问题。格式化这种锦上添花的活失败了也不该吓到模型所以吞掉错误码。第二为什么不把命令直接写在 JSON 里而是拆成脚本因为配置 JSON 里写复杂命令很容易出现转义地狱也难调试独立脚本可以在命令行里直接手动调试比如CLAUDE_PWD/path/to/project bash ~/.claude/hooks/autofmt.sh调通了再挂上去效率高得多。第三注意作用范围。npx prettier --write $CLAUDE_PWD会格式化整个目录在大项目里可能很慢。如果你的项目很大建议改成只格式化最近修改的文件或者只在Write之后运行而不是Edit。这个取舍要根据项目规模来定。4.3 案例三长任务完成弹桌面通知这个案例用 Notification实现Claude Code 任务跑完弹个通知提醒我。在 macOS 上最常见的做法是调用 osascript{ hooks: { Notification: [ { hooks: [ { type: command, command: osascript -e display notification \Claude Code task finished\ with title \Claude Code\ } ] } ] } ]在 Linux 桌面环境可以用 notify-send{ hooks: { Notification: [ { hooks: [ { type: command, command: notify-send Claude Code Task finished } ] } ] } ]不过我更推荐把逻辑封装成一个脚本比如notify.sh然后在里面根据系统类型分发#!/bin/bash message${1:-Claude Code 任务已完成} case $(uname -s) in Darwin) osascript -e display notification \$message\ with title \Claude Code\ ;; Linux) notify-send Claude Code $message ;; *) echo $message ;; esac这个 hook 的妙处在于Claude Code 的通知触发点包括了耗时任务完成、后台任务需要关注等时刻。配好之后你完全可以一边干别的一边等 Claude Code 跑完来喊你。加上async: true让通知异步执行连一秒钟的阻塞都不会有。4.4 案例四Stop 时注入仓库状态这个案例是 Stop 事件的高级用法。Stop hook 脚本的 stdout 会自动回传给 Claude成为下一轮对话上下文的一部分。所以我们可以写一个脚本把关键的仓库状态打印出来#!/bin/bash # ~/.claude/hooks/dump_repo_state.sh echo git status git status --short echo current branch git branch --show-current echo recent commits git log --oneline -5 echo uncommitted diff git diff --stat配置{ hooks: { Stop: [ { hooks: [ { type: command, command: bash ~/.claude/hooks/dump_repo_state.sh, timeout: 15 } ] } ] } ]这个 hook 的作用很微妙但极其有效。Claude Code 在长会话中容易失忆特别是中间穿插了大量文件阅读和命令执行之后它对当前仓库状态的把握会越来越模糊。Stop 时把 git 状态重新喂一遍相当于每轮对话前都给 Claude 做一次状态刷新让它的决策始终基于真实文件系统而不是自己的推测。我实测下来这个 hook 对长任务的稳定性提升非常明显。这里要注意的是输出格式。因为 stdout 会成为后续对话上下文的一部分所以输出内容要精简、结构化不要打印无意义的大段日志。上下文窗口是宝贵的每轮都塞一堆垃圾信息进去反而会稀释关键信息。我见过有人把整个git diff都打出来结果上下文很快就满了得不偿失。用--stat而不是完整 diff就是这个原因。5. 常见问题与排查技巧Hooks 用起来不难但坑也确实不少。这一节把我踩过的和社区里高频出现的问题集中整理一下。5.1 Hook 不生效的排查套路先做三件事确认配置文件路径正确项目级是.claude/settings.json用户级是~/.claude/settings.json别放错位置确认配置结构合法hooks字段下先按触发时机分类再是规则数组JSON 少一个逗号就整个失效检查 matcher 是否有拼写或大小写问题工具名是驼峰Edit和edit不是一回事。另外改了配置文件之后需要重启 Claude Code 或者重新加载会话才能生效这个细节经常被忽略。你可以在会话里运行/hooks命令查看当前已加载的 hooks 列表确认你的配置是否进入生效状态。CLI 工具不像 IDE 有热重载配置文件变了就要重开会话这是预期行为。5.2 退出码、stdout 与 stderr 的潜规则Hooks 和外部脚本通信靠三样东西退出码、stdout、stderr。这三者的约定非常重要退出码 0正常钩子通过退出码非 01 及以上异常stderr 内容会被报告给 Claude退出码 2仅 PreToolUse明确取消本次工具调用。stdout 的行为因触发时机而异。PreToolUse 和 PostToolUse 中stdout 会被回传给 Claude 处理Stop 中 stdout 会并入对话上下文而异步 hook 的 stdout 会被忽略。理解了这一点你就知道什么信息该写到 stdout、什么该写到 stderr、什么该写到日志文件了。我遇到过的一个典型困扰是某个 hook 脚本在检测到小问题时习惯性地exit 1结果 Claude Code 每次都把 stderr 报告给 Claude把它的注意力带偏到无关的错误上。后来我统一了规范真正要阻断的用exit 2要放行的用exit 0警告信息写到日志文件而不是 stderr这样 Claude 的注意力就不会被无关信息干扰。5.3 超时、性能与异步取舍默认 timeout 是 60 秒。如果你的 hook 脚本要跑测试或者 npm install 这类耗时操作60 秒可能不够记得显式调大。反过来如果只是做个快速校验建议把 timeout 设成 5-10 秒这样即使脚本卡死也不会让 Claude Code 干瞪眼等很久。还有个性能陷阱PostToolUse 里如果每次都跑全量格式化在大项目里会很慢。我的建议是只在Write类工具之后跑格式化Edit这种局部修改可以跳过或者只对修改过的文件跑不要对整个目录跑。格式化工具支持单文件操作的就用单文件模式。另外能用async: true的就尽量用日志、通知、埋点这些不阻塞主流程的 hook 全部异步化拦截类、校验类保持同步。这个取舍能让你的工作流响应速度保持流畅。5.4 安全与权限红线Hooks 本质是让脚本在你的机器上以你的用户权限运行所以有几点必须注意不要轻易下载来源不明的脚本就挂上去hook 没有沙箱脚本能做到的事和你自己终端一样多脚本里用绝对路径引用可执行文件避免依赖 PATH 环境导致在非交互 shell 里找不到命令不要在配置里明文保存敏感凭证需要密钥的脚本建议走系统密钥链或者环境变量注入团队共享项目时项目级 settings.json 会随仓库分发注意里面不要含个人敏感信息涉及团队统一策略的 hook 脚本应该单独管理、由维护者审核后再分发。这四条里最后一条是我特别想强调的。很多团队把.claude/settings.json直接提交进仓库但没有对 hook 脚本做 review 机制。一个恶意的或者有 bug 的 hook 脚本会随着所有人的 clone 扩散到每台机器风险远比AI 写错代码大得多。引用远程脚本也要小心供应链攻击从来不是危言耸听。宁可多一道审查也不要图省事直接信任。6. 从 Hooks 到团队规范进阶落地6.1 团队级 Hooks 的标准分发Claude Code 在个人项目里是效率工具在团队里就变成了一把双刃剑。用得好的团队AI 代码质量稳定、提交规范统一用得散漫的团队AI 产生的代码风格五花八门甚至可能误操作共享环境。Hooks 恰好是解决这个问题的抓手。团队落地 Hooks 的正确姿势是将通用 hook 脚本放在一个独立的 Git 仓库里例如claude-hooks-standard通过版本管理统一分发项目级的.claude/settings.json只保留少量个性化配置其余的引用标准 hook 脚本。这样既保证了团队一致性又给项目留出了灵活空间。新成员入职拉一遍标准 hook 仓库配置好路径就自动获得整套安全检查、格式化规范和通知机制学习成本几乎为零。具体操作上我会建议在标准仓库里维护一个install.sh自动把脚本链接到~/.claude/hooks/目录同时生成或更新用户级配置。这样所有成员的 hook 版本始终保持一致升级时只需要 pull 最新代码再跑一遍 install 脚本。版本变更要写在 CHANGELOG 里因为 hook 行为变化会直接影响所有人每天的使用体验。6.2 值得继续深挖的扩展方向Hooks 的生态还在快速演进除了本文讲的这些还有几个方向很值得关注结合 MCP 服务做更复杂的流程编排比如 PreToolUse 里调用外部代码扫描服务PostToolUse 里把结果写入项目的看板用 Stop hook 做会话记忆持久化把每轮的关键决策写入项目内的 CHANGELOG 或 memory 文件跨会话保持上下文连续性在 CI 环境里跑 Claude Code 时用 Hooks 做自动审核门禁不满足质量门槛的任务不允许生成 PR。最后一个方向我们团队已经在试点效果比预想中好很多。原本担心 AI 生成的变更质量不可控现在通过 PostToolUse 强制跑测试、PreToolUse 拦截敏感操作加上 Stop 阶段的综合检查AI 编程相当于加了一层组织级的控制面。每次提交 PR 前Claude 必须通过所有检查点才能进入下一步这让团队从盯着 AI 干活的焦虑里解放出来变成了审核 AI 完成后的成果。我个人在把 Hooks 引入日常工作后最大的体会是它把AI 编程不可控的焦虑感大大降低了。以前我会盯着 Claude Code 执行每一步担心它乱来现在我把该拦的拦了、该自动化的自动化了、该注入的上下文注入了剩下的就是放手让它干活。这也让我更深刻地理解了一件事——AI 编程工具的工程化重点从来不是让模型更聪明而是让系统更可靠。Hooks 就是这层可靠的具体载体。最后再分享一个小技巧不要一上来就把六个触发时机全部配上。建议从最简单的 PostToolUse 格式化 hook 开始跑通一次、观察效果、积累体感然后再逐步加 PreToolUse 拦截、Stop 状态注入、Notification 通知。Hooks 是配置得越少越容易维护配置得越精准越有价值。等你在实际项目里体会到模型负责创造、脚本负责守规矩这种分工的快感自然会找到自己最需要的那几个钩子。毕竟这套东西的最终目的不是让你写更多配置而是让你少操更多心。
返回列表