news 2026/10/20 22:47:32

Visual Studio Code 用户自定义代码片段(Snippets)完全指南:从内置片段、自定义 JSON 到变量转换与作用域控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Visual Studio Code 用户自定义代码片段(Snippets)完全指南:从内置片段、自定义 JSON 到变量转换与作用域控制
  • 文档
  • 教程

【免费下载链接】vscode-docs

Public documentation for Visual Studio Code

项目地址:https://gitcode.com/gh_mirrors/vs/vscode-docs
点击查看免费下载

代码片段(Snippets)是 VS Code 中用来快速输入重复代码模式的模板,例如循环、条件语句或一段完整的日志输出。本文以官方文档 docs/editing/userdefinedsnippets.md 为主体,系统讲解代码片段在内置、Marketplace 扩展、用户自定义三种来源下的使用方式,并深入剖析片段文件的 JSON 结构、prefix/body/description字段、占位符与 Tabstop 跳转机制、完整变量与变量转换语法,以及语言、项目、文件模式三种作用域控制手段。读完本文,你将能够独立编写、调试、共享和打包自己的代码片段,并把片段绑定到自定义键盘快捷键上。

什么是代码片段

代码片段是预先写好的、可复用的代码模板,用于加速"重复代码模式"的输入——比如for循环、if-else分支、函数定义或样板注释。在 VS Code 中,片段会以两种方式呈现:

  • 混入 IntelliSense 建议列表:与普通补全建议一起出现,可通过触发智能提示的快捷键(kb(editor.action.triggerSuggest))唤起;
  • 独立的片段选择器:在命令面板中运行Insert Snippet命令,可列出当前文件语言可用的全部片段。

此外 VS Code 还支持Tab 补全(tab-completion):在设置中启用"editor.tabCompletion": "on"后,输入片段的prefix(触发文本)并按下插入片段的快捷键(kb(insertSnippet),通常为 Tab),即可直接插入该片段。

代码片段的语法遵循 TextMate 片段语法,但有两个例外:"interpolated shell code"(插值 shell 代码)与\u转义均不支持。

使用内置代码片段

VS Code 为多种语言内置了开箱即用的代码片段,例如 JavaScript、TypeScript、Markdown 和 PHP。要查看某个语言当前可用的全部片段,可以:

  1. 打开命令面板(kb(workbench.action.showCommands));
  2. 运行Insert Snippet命令;
  3. 在列表中查看当前文件语言对应的全部片段。

需要注意,这个列表不仅包含内置片段,还会混入你自己定义的用户片段,以及已安装扩展提供的片段。如果希望只看某一类来源,可以结合下文的作用域与隐藏机制来管理。

从 Marketplace 安装代码片段扩展

许多 VS Code 扩展都会随包附带代码片段(例如语言支持、框架工具类扩展)。查找这类扩展的方法是:

  1. 打开扩展视图(kb(workbench.view.extensions));
  2. 在搜索框中输入过滤器@category:"snippets";
  3. 浏览结果并安装你需要的扩展。

安装完成后,重启 VS Code,新片段即可生效。这种方式适合直接复用社区维护好的片段集合,而无需自己编写。

创建自己的代码片段

不依赖任何扩展,你可以直接在 VS Code 中定义自己的片段。操作路径如下:

  • 菜单File>Preferences>Configure Snippets(即命令Snippets: Configure Snippets);
  • 在弹出的下拉菜单中选择一种语言(按语言标识符区分,例如javascript、typescript、python),片段只会在该语言文件中出现;
  • 或选择New Global Snippets file(新建全局代码片段文件),片段适用于所有语言;
  • 也可以选择New Snippets file for '<folder-name>'...创建项目级片段文件(详见下文"项目片段作用域")。

选择后 VS Code 会自动创建/刷新对应的片段 JSON 文件,你只需写入内容即可。片段文件以 JSON 编写、支持 C 风格注释(//、/* */),并且可以定义不限数量的片段。

以下是一个针对 JavaScript 的for循环片段示例(位于用户片段文件Code/User/snippets/javascript.json):

// in file 'Code/User/snippets/javascript.json' { "For Loop": { "prefix": [ "for", "for-const" ], "body": [ "for (const ${2:element} of ${1:array}) {", "\t$0", "}" ], "description": "A for loop." } }

各字段含义如下:

  • 片段名(此例为"For Loop"):片段在列表中的显示名称。如果未提供description,片段名会直接显示在 IntelliSense 中;
  • prefix:一个或多个触发词。当输入这些文本时片段会出现在 IntelliSense 中。匹配采用子串匹配,因此本例中fc也能匹配到for-const;
  • body:一行或多行内容,插入时会被拼接为多行文本。其中的换行与嵌入制表符会根据插入位置的上下文自动格式化缩进;
  • description:可选的描述文本,由 IntelliSense 显示,帮助区分同名片段。

示例body中包含三个占位符(按遍历顺序):${1:array}、${2:element}和$0。插入片段后,你可以用跳转到下一个占位符的快捷键(kb(jumpToNextSnippetPlaceholder),默认 Tab)快速在占位符间移动并编辑。冒号:后的字符串是默认文本,例如${2:element}中的element。占位符的遍历顺序按编号从小到大,从1开始;$0是可选的特殊位置,总是最后访问,到达后退出片段模式并将光标停在指定位置。

文件模板片段

如果某个片段的本意是填充或替换整个文件的内容(例如新建文件时的样板模板),可以为其添加isFileTemplate属性:

{ "My File Template": { "prefix": "template-name", "body": [ "# ${1:title}", "", "${0}" ], "isFileTemplate": true } }

标记为文件模板的片段,会在你于新文件或已有文件中运行Snippets: Fill File with Snippet命令时,出现在一个专门的下拉列表中,方便按模板一键生成文件内容。

代码片段作用域

片段是有作用域的,VS Code 只会建议与当前上下文相关的片段。作用域可以从两个维度控制:

  1. 语言:片段适用于哪些语言(可能是全部语言);
  2. 项目:片段适用于哪些项目(通常适用于全部项目)。

此外还有更细粒度的文件模式控制(include/exclude)。

语言片段作用域

每个片段都会根据其定义位置,被限定到一个、多个或全部(全局)语言:

  • 单语言片段:定义在某个特定语言的片段文件中(例如javascript.json),可通过Snippets: Configure Snippets按语言标识符访问。这类片段仅在编辑该语言文件时可用;
  • 多语言 / 全局片段:定义在"全局"片段文件中(JSON 文件,后缀为.code-snippets),同样通过Snippets: Configure Snippets访问。在全局片段文件中,片段定义可以增加一个可选的scope属性,取值为一个或多个语言标识符,从而将片段限制到指定语言;如果省略scope,则该全局片段对所有语言可用。

大多数用户自定义片段是单语言的,因此通常定义在语言专属片段文件中。若需多语言共享或全局可用,则使用.code-snippets文件配合scope。

项目片段作用域

你还可以将全局片段文件(.code-snippets)限定到某个项目。项目级片段通过Snippets: Configure Snippets下拉菜单中的New Snippets file for '<folder-name>'...创建,存放于项目根目录的.vscode文件夹中。项目片段适合与参与该项目的所有开发者共享(配合版本控制提交),其行为与全局片段类似,也可以通过scope属性限定到特定语言。

文件模式作用域

include与exclude两个可选属性可以进一步控制片段出现的位置,它们同时适用于语言专属片段文件和全局片段文件,并可与scope属性组合以实现更精确的控制:

  • include:一个 glob 模式或 glob 模式数组,指定片段应出现在哪些文件中;
  • exclude:一个 glob 模式或 glob 模式数组,指定片段不应出现在哪些文件中。

模式匹配规则如下:

  • 仅文件名模式(例如*.test.ts):仅基于文件名匹配,与文件在项目中的位置无关;
  • 基于路径的模式(例如**/*.test.ts或**/dist/**):匹配完整文件路径;
  • 若某个文件同时命中include与exclude,exclude优先;
  • 若两者都未指定,则片段根据scope属性出现在所有适用文件中。

示例:测试片段(仅出现在 TypeScript 测试文件中):

{ "Test Block": { "prefix": "test", "body": [ "test('${1:description}', () => {", "\t${0}", "});" ], "description": "Insert a test block", "scope": "typescript", "include": ["**/*.test.ts", "**/*.spec.ts"] } }

示例:排除目录(出现在所有 JavaScript 文件中,但排除dist与node_modules目录):

{ "Console Log": { "prefix": "log", "body": "console.log(${0});", "description": "Insert console.log", "scope": "javascript", "exclude": ["**/dist/**", "**/node_modules/**"] } }

示例:配置文件片段(使用仅文件名模式,仅出现在travis.yml中):

{ "Travis CI Node": { "prefix": "travis-node", "body": [ "language: node_js", "node_js:", " - ${1:18}" ], "description": "Travis CI Node.js configuration", "scope": "yaml", "include": ["travis.yml"] } }

合理使用include/exclude可以显著减少 IntelliSense 中的干扰项,让片段只在其真正相关的文件中出现。

代码片段语法详解

片段的body可以使用多种特殊结构来控制光标位置与插入文本,其核心语法遵循 TextMate 片段规范(去掉不支持的 shell 插值与\u)。

Tabstops(制表位)

使用$1、$2指定光标位置,数字表示访问顺序;$0表示最终光标位置。同一 Tabstop 的多次出现是关联同步的——编辑其中一个,其余位置会同步更新。

{ "Print": { "prefix": "print", "body": "console.log($1)$0" } }

Placeholders(占位符)

占位符是带默认值的 Tabstop,语法为${1:foo}。插入片段时默认文本会被选中,方便直接输入替换。占位符支持嵌套,例如${1:another ${2:placeholder}}。

Choice(选项)

占位符的值可以是可选项列表,语法为用管道符|包围、逗号分隔的枚举,例如${1|one,two,three|}。片段插入并选中该占位符时,VS Code 会提示用户在候选项中挑选一个。

Variables(变量)

使用$name或${name:default}可插入变量的值:

  • 变量未设置时,插入其default值(若提供)或空字符串;
  • 变量未知(名字未定义)时,插入变量名本身并将其转换为占位符。

可用变量分为以下几类。

文档与光标相关变量:

变量含义
TM_SELECTED_TEXT当前选中的文本,或空字符串
TM_CURRENT_LINE当前行的内容
TM_CURRENT_WORD光标所在单词的内容,或空字符串
TM_LINE_INDEX基于 0 的行号
TM_LINE_NUMBER基于 1 的行号
TM_FILENAME当前文档的文件名
TM_FILENAME_BASE当前文档不含扩展名的文件名
TM_DIRECTORY当前文档所在目录
TM_FILEPATH当前文档的完整文件路径
RELATIVE_FILEPATH相对于打开的工作区或文件夹的当前文档路径
CLIPBOARD剪贴板内容
WORKSPACE_NAME打开的工作区或文件夹的名称
WORKSPACE_FOLDER打开的工作区或文件夹的路径
CURSOR_INDEX基于 0 的光标编号
CURSOR_NUMBER基于 1 的光标编号

当前日期与时间变量:

变量含义
CURRENT_YEAR当前年份
CURRENT_YEAR_SHORT当前年份的后两位
CURRENT_MONTH两位数字的月份(如02)
CURRENT_MONTH_NAME月份完整名称(如July)
CURRENT_MONTH_NAME_SHORT月份简称(如Jul)
CURRENT_DATE两位数字的当月日期(如08)
CURRENT_DAY_NAME星期完整名称(如Monday)
CURRENT_DAY_NAME_SHORT星期简称(如Mon)
CURRENT_HOUR24 小时制当前小时
CURRENT_MINUTE两位数字的当前分钟
CURRENT_SECOND两位数字的当前秒
CURRENT_MILLISECOND三位数字的当前毫秒(如078)
CURRENT_SECONDS_UNIX自 Unix 纪元以来的秒数
CURRENT_MILLISECONDS_UNIX自 Unix 纪元以来的毫秒数
CURRENT_TIMEZONE_OFFSET当前 UTC 时区偏移,格式+HH:MM或-HH:MM(如-07:00)
CURRENT_TIMEZONE_NAME当前时区的 IANA 名称(如America/Los_Angeles)

随机值变量:

变量含义
RANDOM6 位随机十进制数字
RANDOM_HEX6 位随机十六进制数字
UUID一个 Version 4 UUID

行注释 / 块注释变量(自动匹配当前语言):

变量示例输出
BLOCK_COMMENT_STARTPHP 中为/*,HTML 中为<!--
BLOCK_COMMENT_ENDPHP 中为*/,HTML 中为-->
LINE_COMMENTPHP 中为//

下面的片段会在 JavaScript 文件中插入/* Hello World */,在 HTML 文件中插入<!-- Hello World -->:

{ "hello": { "scope": "javascript,html", "prefix": "hello", "body": "$BLOCK_COMMENT_START Hello World $BLOCK_COMMENT_END" } }

变量转换(Variable transforms)

转换允许在插入前修改变量的值。一个转换由三部分组成:

  1. 正则表达式:与变量值匹配(变量无法解析时匹配空字符串);
  2. 格式字符串:引用正则的匹配分组,支持条件插入与简单改写;
  3. 选项:传递给正则表达式的选项(如g、i等)。

以下示例取出当前文件名并去掉扩展名,将foo.txt转换为foo:

${TM_FILENAME/(.*)\\..+$/$1/} | | | | | | | |-> no options | | | | | |-> references the contents of the first | | capture group | | | |-> regex to capture everything before | the final `.suffix` | |-> resolves to the filename

占位符转换(Placeholder-Transform)

与变量转换类似,占位符转换允许在跳转到下一个 Tabstop 时改写占位符中已插入的文本:插入的文本与正则表达式匹配,匹配结果(取决于选项)被替换为指定的替换格式文本。每个占位符出现处都可以基于第一个占位符的值独立定义自己的转换,其格式与变量转换完全相同。

转换示例

下面的示例以双引号形式展示(即片段 body 中的真实写法),以说明某些字符需要双重转义。转换作用于文件名example-123.456-TEST.js:

示例输出说明
"${TM_FILENAME/[\\.]/_/}"example-123_456-TEST.js将第一个.替换为_
"${TM_FILENAME/[\\.-]/_/g}"example_123_456_TEST_js将每个.或-替换为_
"${TM_FILENAME/(.*)/${1:/upcase}/}"EXAMPLE-123.456-TEST.JS全部转为大写
"${TM_FILENAME/[^0-9a-z]//gi}"example123456TESTjs删除所有非字母数字字符

文法(Grammar)

片段语法可用下面的 EBNF(扩展巴科斯范式)完整描述。使用反斜杠\可以转义$、}和\。在 choice 元素内部,反斜杠还可转义逗号与管道符。只有必须转义的字符才需要转义:因此在这些结构中$不应转义;在 choice 结构内部$与}都不应转义。

any ::= tabstop | placeholder | choice | variable | text tabstop ::= '$' int | '${' int '}' | '${' int transform '}' placeholder ::= '${' int ':' any '}' choice ::= '${' int '|' text (',' text)* '|}' variable ::= '$' var | '${' var '}' | '${' var ':' any '}' | '${' var transform '}' transform ::= '/' regex '/' (format | text)+ '/' options format ::= '$' int | '${' int '}' | '${' int ':' '/upcase' | '/downcase' | '/capitalize' | '/camelcase' | '/pascalcase' | '/snakecase' | '/kebabcase' '}' | '${' int ':+' if '}' | '${' int ':?' if ':' else '}' | '${' int ':-' else '}' | '${' int ':' else '}' regex ::= JavaScript Regular Expression value (ctor-string) options ::= JavaScript Regular Expression option (ctor-options) var ::= [_a-zA-Z] [_a-zA-Z0-9]* int ::= [0-9]+ text ::= .* if ::= text else ::= text

从该文法可以看出,format中除了引用分组编号外,还内置了upcase、downcase、capitalize、camelcase、pascalcase、snakecase、kebabcase等大小写/命名风格转换,以及:+(存在时插入)、:?(条件二选一)、:-(缺省值)等条件格式。

使用 TextMate 代码片段

如果手头已有现成的 TextMate 片段(.tmSnippets文件),也可以直接用于 VS Code。推荐的方式是将它们打包为扩展,具体流程见 API 文档中的 TextMate 片段章节。打包后,VS Code 会负责将.tmSnippets转换为自身的片段格式并加载。

将片段打包为扩展进行共享

除了给自己使用,片段还可以打包成扩展上传到扩展市场与团队或社区共享。完整的操作流程记录在 api/language-extensions/snippet-guide.md 中,核心步骤如下:

  1. 先用Snippets: Configure User Snippets命令创建并测试你的片段;
  2. 满意后,把整个 JSON 片段文件复制到扩展目录中(例如snippets.json);
  3. 在扩展的package.json中通过contributes.snippets贡献点声明片段文件:
{ "contributes": { "snippets": [ { "language": "javascript", "path": "./snippets.json" } ] } }

其中language为语言标识符,path为片段文件的相对路径,文件内容即本文介绍的 VS Code 片段 JSON 格式。

  1. 提示:在package.json中加入以下配置,将扩展标记为"代码片段类"扩展,便于在市场上被@category:"snippets"检索到:
{ "categories": ["Snippets"] }

此外,也可以使用yo code扩展生成器(New Code Snippets选项)直接指向一个包含多个.tmSnippets文件的文件夹,生成器会将其打包为 VS Code 片段扩展,同时支持 Sublime 片段(.sublime-snippets)。生成结果包含两个文件:扩展清单package.json和转换后的snippets.json:

. ├── snippets // VS Code integration │ └── snippets.json // The JSON file w/ the snippets └── package.json // extension's manifest

将生成的snippets文件夹复制到.vscode/extensions下的新目录并重启 VS Code 即可生效。

为代码片段分配键盘快捷键

你可以通过自定义键盘快捷键直接插入指定片段。打开keybindings.json(命令Preferences: Open Keyboard Shortcuts File),添加一条将"snippet"作为额外参数传给editor.action.insertSnippet的键绑定:

{ "key": "cmd+k 1", "command": "editor.action.insertSnippet", "when": "editorTextFocus", "args": { "snippet": "console.log($1)$0" } }

这样按下该快捷键时会直接执行Insert Snippet命令,但不再弹出选择列表,而是插入args.snippet中定义的片段文本。键绑定与普通快捷键一样,由键盘组合、命令 ID 和可选的 when clause 上下文(控制快捷键何时生效)组成。

除了内联定义片段,还可以通过langId与name参数引用已有片段:langId指定片段所属语言,name指定片段名称。下面的示例会在按下快捷键时插入csharp语言中名为myFavSnippet的片段:

{ "key": "cmd+k 1", "command": "editor.action.insertSnippet", "when": "editorTextFocus", "args": { "langId": "csharp", "name": "myFavSnippet" } }

值得注意的是,jumpToNextSnippetPlaceholder(跳转到下一个占位符)默认绑定在 Tab 键上,并可通过keybindings.json调整或移除,相关说明见 docs/configure/keybindings.md。

常见问题

如何在插入的脚本中放入一个变量?

如果希望片段插入后保留$variable形式的字面文本,需要转义$,使其不会被片段展开阶段解析为变量。例如:

"VariableSnippet":{ "prefix": "_Var", "body": "\\$MyVar = 2", "description": "A basic snippet that places a variable into script with the $ prefix" }

插入结果为:

$MyVar = 2

如何从 IntelliSense 中移除某个片段?

可以隐藏特定片段,使其不再出现在 IntelliSense(补全列表)中:在Insert Snippet命令的下拉列表中,点击片段条目右侧的Hide from IntelliSense按钮即可。隐藏后,你仍可通过Insert Snippet命令选择该片段,但它不会出现在 IntelliSense 建议中。

下一步

  • 命令行界面:VS Code 提供丰富的命令行接口,可打开/比较文件、安装扩展;
  • 扩展 API:了解扩展 VS Code 的更多方式;
  • Snippet Guide:学习如何将片段打包为扩展,在 VS Code 中使用。
  • 文档
  • 教程

【免费下载链接】vscode-docs

Public documentation for Visual Studio Code

项目地址:https://gitcode.com/gh_mirrors/vs/vscode-docs
点击查看免费下载

相关推荐

上一篇:番茄小说下载器终极指南:一键下载+EPUB+有声书完整方案
下一篇:番茄小说下载器:3分钟学会免费下载小说+生成EPUB+有声书完整方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 3:18:04

Android Studio安装配置全指南:打不开问题排查与values多语言创建

很多朋友第一次接触 Android 开发&#xff0c;最先卡住的地方往往不是代码&#xff0c;而是环境搭建这一步。Android Studio 的安装过程看起来就是“下一步、下一步”&#xff0c;但实际上牵扯到 JDK 版本、SDK 目录、系统变量、模拟器性能这些细节&#xff0c;任何一个地方出了…

作者头像 李华
网站建设 2026/10/14 7:47:00

安防监控视频汇聚实战:EasyCVR平台架构与部署经验

1. 为什么安防监控越来越需要"视频汇聚"这一步先聊个我在实际项目里最常见的场景。一个中型园区&#xff0c;前端摄像头可能有五六种品牌&#xff0c;海康、大华、宇视、天地伟业&#xff0c;再加上一些老旧的模拟摄像头通过编码器接入。监控室里的NVR各有各的IP&…

作者头像 李华
网站建设 2026/10/14 11:46:19

为AI编程助手打造持久记忆:claude-mem上下文管理实践

上周我在做模拟项目X的跨平台重构时遇到一个特别闹心的事&#xff1a;白天和Claude Code讨论好的接口设计&#xff0c;晚上新建会话想继续改代码&#xff0c;它居然完全不记得我们上午定好的方案&#xff0c;上下文里只剩当时贴进去的那几段代码。我一拍桌子&#xff0c;决定自…

作者头像 李华
网站建设 2026/10/15 15:05:53

PS5手柄跨平台适配方案:AnyPS5如何解锁DualSense完整体验

第一次把PS5手柄接到电脑上那个下午&#xff0c;我原本以为会是无缝衔接&#xff1a;插线、装驱动、打开游戏、开玩。结果折腾了半个多小时&#xff0c;灯是亮了&#xff0c;但键位错乱、扳机死沉、触觉反馈全部失效。后来我才意识到&#xff0c;PS5的DualSense虽然是市面上手感…

作者头像 李华
网站建设 2026/10/19 19:52:54

单片机计算机毕设之基于单片机的室内甲醛超标本地声光与手机远程双重报警系统设计 基于单片机的学生宿舍空气质量无线监测与自动通风装置设计(030111)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华