Visual Studio Code 代码片段完整指南

代码片段是帮助快速输入重复代码模式的模板,例如循环和条件语句。

在 Visual Studio Code 中,代码片段会与其他建议一起显示在 IntelliSense 中,可按 Control+Space 调出;也可以在命令面板运行“插入代码片段”(Insert Snippet),打开专门的选择器。

还可以启用 Tab 补全:设置 "editor.tabCompletion": "on",输入片段前缀,也就是触发文本,再按 Tab 插入。

片段语法遵循 TextMate 片段语法,但不支持“插值 shell 代码”和 \u。

内置代码片段

VS Code 为 JavaScript、TypeScript、Markdown、PHP 等多种语言提供内置片段。

builtin javascript snippet

在命令面板运行 Insert Snippet,可以查看当前文件语言可用的片段。该列表不仅包括内置片段,也包括用户自行定义的片段,以及已安装扩展提供的片段。

从 Marketplace 安装片段

Visual Studio Marketplace 中很多扩展包含代码片段。打开扩展视图,macOS 快捷键为 Shift+Command+X,Windows、Linux 为 Ctrl+Shift+X,再使用过滤条件 @category:"snippets" 搜索。

Searching for extensions with snippets

找到需要的扩展后安装,再按原文说明重启 VS Code,即可使用新片段。

创建自己的代码片段

无需扩展就能自行定义片段。在“文件 → 首选项”中选择“配置代码片段”(Configure Snippets),然后按语言标识符选择适用语言;如果希望对所有语言可用,选择“新建全局代码片段文件”(New Global Snippets file)。VS Code 会负责创建和刷新底层片段文件。

snippet dropdown

片段文件使用 JSON,支持 C 风格注释,并可定义任意数量的片段。片段支持大多数 TextMate 动态语法,会根据插入上下文智能调整空白,还支持方便的多行编辑。

以下是 JavaScript 的 for 循环片段:

// 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 是一行或多行内容,插入时会连接成多行。换行与内嵌 Tab 会根据插入上下文调整格式。
  • description 是可选说明,在 IntelliSense 中显示。

示例 body 还包含三个占位符,按跳转顺序分别是 ${1:array}、${2:element} 和 $0。按 Tab 可快速跳到下一个占位符,随后编辑它或继续跳过。

冒号后的字符串是默认文本,例如 ${2:element} 中的 element。占位符按编号从一开始递增遍历;零是可选的特殊编号,始终最后访问,并在指定位置结束片段模式。

文件模板片段

如果片段用于填充或替换整个文件,可在定义中加入 isFileTemplate。在新文件或现有文件中运行“Snippets: Fill File with Snippet”,这些文件模板片段会显示在下拉列表中。

片段作用域

作用域确保只建议相关片段。可以按适用语言划分,也可以按适用项目划分;范围可以是一个、多个或全部。

语言作用域

片段定义在特定语言文件或全局文件中,由此决定它适用于一种、多种还是所有语言。

单语言用户片段放在对应语言的文件里,例如 javascript.json。通过“Snippets: Configure Snippets”按语言标识符打开。只有编辑该语言文件时,片段才可用。

多语言和全局片段放在扩展名为 .code-snippets 的 JSON 文件中,也通过相同命令管理。全局片段定义可以额外包含 scope,指定一个或多个语言标识符。如果没有 scope,该片段对全部语言可用。

大多数用户自定义片段只面向一种语言,因此通常放在对应语言文件中。

项目作用域

也可以把全局片段文件限制在某个项目中。在配置片段的下拉列表选择“New Snippets file for ‘<folder-name>’…”,即可在项目根目录的 .vscode 文件夹中创建项目片段。

项目片段便于与参与同一项目的其他人共享。它们与全局片段类似,也能通过 scope 限定语言。

文件模式作用域

使用可选的 include 与 exclude 可以进一步规定片段在哪些文件出现。这两个属性既适用于语言专用文件,也适用于全局文件,还能与 scope 组合:

  • include:一个 glob 模式或模式数组,指定应该显示片段的文件。
  • exclude:一个 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 可以使用特殊结构,控制光标和插入文本。

Tab 停靠点

使用 $1、$2 等定义光标位置。数字决定访问顺序,$0 表示最终位置。同一编号的多个停靠点会相互关联、同步更新。

占位符

占位符是带默认值的停靠点,例如 ${1:foo}。默认文本插入后会被选中,便于修改。占位符也可以嵌套,例如 ${1:another ${2:placeholder}}。

选择项

占位符可提供多个候选值,语法为用竖线包围、逗号分隔的列表,例如 ${1|one,two,three|}。片段插入并选中该位置后,会提示选择一个值。

变量

通过 $name 或 ${name:default} 插入变量值。变量未设置时,插入默认值或空字符串。如果变量名未知,也就是没有定义,则插入变量名称本身,并把它变成占位符。

可用的文本、路径、工作区及光标变量:

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

当前日期与时间变量:

  • 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_HOUR:24 小时制小时数。
  • 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。

随机值变量:

  • RANDOM:六位随机十进制数字。
  • RANDOM_HEX:六位随机十六进制数字。
  • UUID:一个版本 4 UUID。

根据当前语言插入行注释或块注释:

  • BLOCK_COMMENT_START:块注释起始符,例如 PHP 的 /*、HTML 的 <!--。
  • BLOCK_COMMENT_END:块注释结束符,例如 PHP 的 */、HTML 的 -->。
  • LINE_COMMENT:行注释起始符,例如 PHP 的 //。

以下片段在 JavaScript 中插入 /* Hello World */,在 HTML 中插入 <!-- Hello World -->:

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

变量转换

转换功能可在插入变量前修改其值,由三部分组成:

  1. 正则表达式,与变量值匹配;变量无法解析时匹配空字符串。
  2. 格式字符串,可引用正则捕获组,也支持条件插入和简单变换。
  3. 传递给正则表达式的选项。

下面的示例插入不含扩展名的当前文件名,例如把 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

其中 TM_FILENAME 解析为文件名;正则捕获最后一个扩展名之前的部分;$1 引用第一个捕获组;最后没有指定正则选项。

占位符转换

占位符转换与变量转换类似,在跳到下一个停靠点时改变占位符文本。输入文本与正则匹配后,根据选项替换一个或多个匹配项,替换内容由格式字符串决定。

同一个占位符的每次出现,都可以基于第一个占位符的值独立定义转换。转换格式与变量转换相同。

转换示例

下列示例像片段 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删除所有非字母数字字符。

语法定义

下面是片段语法的 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

使用 TextMate 片段

VS Code 也支持已有 TextMate 片段文件 .tmSnippets。详情见扩展 API 文档中的使用 TextMate 片段。

给片段分配键盘快捷键

可以创建自定义快捷键,直接插入某个片段。运行“Preferences: Open Keyboard Shortcuts File”,打开定义快捷键的 keybindings.json,并将 snippet 作为额外参数:

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

该快捷键会调用 Insert Snippet,但不再提示选择,而是直接插入给定片段。快捷键定义方式与平常一样:指定按键、命令 ID,以及可选的 when 条件,控制何时启用。

还可以不在 snippet 参数中内联定义内容,而是通过 langId 和 name 引用已有片段。langId 选择语言,name 指定片段。例如,下面选择适用于 C# 文件的 myFavSnippet:

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

下一步

  • 命令行:通过丰富的 CLI 打开文件、比较文件或安装扩展。
  • 扩展 API:了解其他扩展 VS Code 的方法。
  • 代码片段指南:将片段打包供 VS Code 使用。

常见问题

如何使用 .tmSnippet 文件中的现有 TextMate 片段

可以把 TextMate 片段文件打包为 VS Code 可用的扩展。参阅使用 TextMate 片段。

如何让片段插入一个带美元符号的脚本变量

需要转义变量名 $variable 中的 $,避免它在片段展开阶段被解析:

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

插入结果为:

$MyVar = 2

能否从 IntelliSense 隐藏片段

可以。在 Insert Snippet 下拉列表中,点击片段条目右侧的“Hide from IntelliSense”按钮:

Hide from IntelliSense button in Insert Snippet dropdown

隐藏后,该片段不再出现在 IntelliSense 补全列表中,但仍可通过 Insert Snippet 命令选择。

原文页面标注日期:2026 年 9 月 30 日。


原文:Snippets in Visual Studio Code。本文为该文档的中文译文,示例代码保留原文。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容