更多文章,参见大搜车技术博客:blog.souche.com/javascript
大搜车无线开发中心持续招聘中,前端,Nodejs,android 均有 HC,简历直接发到:sunxinyu@souche.com前端
你们都是出来写代码的,少不了要写上千万来行代码,其中重复性的代码占比又会很大。那么如何避免一次又一次写重复性的代码呢?除了代码自身的优雅、可复用,Jetbrains系如Intellij IDEA的Live Templates
或Visual Studio Code的Snippet
等内置工具都能很大程度上帮咱们少写不少重复性的代码。下面就vsc的Snippet
,结合demo,讲讲它的用法。java
快捷键Cmd + Shift + P
或F1
打开命令窗口,输入snippet
,选中配置用户代码片断
,这时候会弹出react
能够在现有的代码片断文件上新增snippet,也能够本身新建代码片断文件。android
Snippets片断以JSON格式定义,官方提供的例子以下正则表达式
{
"For_Loop": {
"prefix": "for",
/**
* 在全局代码片断文件新增snippet时,
* 经过该项来指定该snippet使用范围,
* 以下所示,在文件以`.js`或者`.ts`结尾时可以使用该snippet
*/
"scope": "javascript,typescript",
"body": [
"for (const ${2:element} of ${1:array}) {",
"\t$0",
"}"
],
"description": "For Loop"
}
}
复制代码
For_Loop
is the snippet name(后续在指定快捷键绑定的时候会用到).prefix
defines how this snippet is selected from IntelliSense and tab completion. In this case for
.(前缀支持N:1,好比prefix
值为["for","fof"]
,则for
和fof
对应同一条代码片断)body
is the content and either a single string or an array of strings of which each element will be inserted as separate line.description
is the description used in the IntelliSense drop down(非必填).上述英文解释引自官方,怕翻译不到位影响读者理解,就不做翻译了。typescript
下面用一张图展现在使用中各个属性对应的位置express
prefix
,右侧圈中的为
description
,
description
下方的为
body
部份内容
Snippet
的语法集中在body
上。json
Tabstops
: 即$1
、$2
等。使用$1
、$2
等表示按下键盘tab
后光标将要指向的位置。根据数字大小表示前后顺序。$0
表示光标最后指向的位置。能够存在多个相同的Tabstops
,并会同步更新。c#
如下是多个相同的Tabstops同步更新的示例
{
"For_Loop": {
"prefix": "for",
"scope": "javascript,typescript",
"body": [
"for (const ${2:element} of ${1:array}) {",
"\tconst item = $1[$2];$0",
"}"
],
"description": "For Loop"
}
}
复制代码
如下是使用上述snippet的过程
Placeholders
:占位符。用户直接跳过Tabstops
不输入新值时,会使用占位符。它还能内嵌。
如下是占位符内嵌的示例
{
"placeholder": {
"prefix": "ph",
"body": "${1:hello ${2:world}}$0"
}
}
复制代码
如下是使用上述snippet的过程
Choice
: 可选的占位符
以以下snippet为例
{
"choice": {
"prefix": "ch",
"body": "${1|hello,hi,how are you|}"
}
}
复制代码
输入ch
按下tab键后,就会显示
Choice
中,,
、|
、$
、}
、\
可使用\
转义;其余状况有且仅$
、}
、\
可使用\
转义,其余字符没法转义, 详见https://code.visualstudio.com/docs/editor/userdefinedsnippets#_grammar
Variables
: 官方定义的变量
TM_SELECTED_TEXT:当前选定的文本或空字符串;
TM_CURRENT_LINE:当前行的内容;
TM_CURRENT_WORD:光标所处单词或空字符串
TM_LINE_INDEX:行号(从零开始);
TM_LINE_NUMBER:行号(从一开始);
TM_FILENAME:当前文档的文件名;
TM_FILENAME_BASE:当前文档的文件名(不含后缀名);
TM_DIRECTORY:当前文档所在目录;
TM_FILEPATH:当前文档的完整文件路径;
CLIPBOARD:当前剪贴板中内容。
时间相关
CURRENT_YEAR: 当前年份;
CURRENT_YEAR_SHORT: 当前年份的后两位;
CURRENT_MONTH: 格式化为两位数字的当前月份,如 02;
CURRENT_MONTH_NAME: 当前月份的全称,如 July;
CURRENT_MONTH_NAME_SHORT: 当前月份的简称,如 Jul;
CURRENT_DATE: 当天月份第几天;
CURRENT_DAY_NAME: 当天周几,如 Monday;
CURRENT_DAY_NAME_SHORT: 当天周几的简称,如 Mon;
CURRENT_HOUR: 当前小时(24 小时制);
CURRENT_MINUTE: 当前分钟;
CURRENT_SECOND: 当前秒数。
注释相关
BLOCK_COMMENT_START: 在PHP中输出 /* ,在HTML中输出 <!--
BLOCK_COMMENT_END: 在PHP中输出 */ ,在HTML中输出 -->
LINE_COMMENT: 在PHP中输出 // ,在HTML中输出 <!-- -->
复制代码
Variable transforms
变量转换可将变量的值格式化处理后插入预约的位置。 它包括三个部分:
正则表达式和正则表达式匹配选项不做解释。
格式字符串在官方文档的Grammar
中以下
format ::= '$' int | '${' int '}'
| '${' int ':' '/upcase' | '/downcase' | '/capitalize' '}'
| '${' int ':+' if '}'
| '${' int ':?' if ':' else '}'
| '${' int ':-' else '}' | '${' int ':' else '}'
复制代码
假设某总体片断为${variable/regexp/(format|text)/options}
,再结合上述语法, 总体片断可变为
${var_name/regular_expression/$1/options}
${var_name/regular_expression/${1}/options}
${var_name/regular_expression/${1:/upcase}/options}
// /downcase
和/capitalize
使用方式同/upcase
${var_name/regular_expression/${1:+if}/options}
${var_name/regular_expression/${1:?if:else}/options}
${var_name/regular_expression/${1:-else}/options}
${var_name/regular_expression/${1:else}/options}
${var_name/regular_expression/text/options}
上述format
中$
后的数字1表示分组捕获组(正则表达式中()
匹配到的数组)的第1项,同理$2表示分组捕获项第2项。分组捕获相关信息详见分组捕获
现有文件名global-js.json
,以demo说明上述片断含义。为了精简,输出值直接以body末尾注释表示,另外多个body直接放在一个snippet(实际操做不规范,仅仅为了精简)
注:使用transform末尾必须加/
,才能被识别。如${TM_FILENAME_BASE/(global).*/$1/
}
其中1
、2
意义相同
代码片断
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global).*/$1/}" // 输出: global
}
// 待匹配字符串 global-js
// 正则表达式 (global).*
// 所有匹配项 global-js
// 分组捕获组 ['global'],即$1=global
// $1替换global-js,即输出 global
复制代码
3
表示对匹配到的相应分组捕获组转化成大写,或小写,或首字母大写,以替换正则表达式匹配到的所有字符串
代码片断(该片断仅展现转化成大写)
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global).*/${1:/upcase}/}" // 输出: GLOBAL
}
// 待匹配字符串 global-js
// 正则表达式 (global).*
// 所有匹配项 global-js
// 分组捕获组 ['global'],即$1=global
// 经${1:/upcase}转换后,为GLOABl
// ${1:/upcase}替换global-js,即输出GLOABl
复制代码
4
表示匹配成功时,将if
所述语句彻底替换正则表达式匹配项。
代码片断
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global)/${1:+if}/}", //输出: if-js
// 待匹配字符串 global-js
// 正则表达式 (global)
// 所有匹配项 global
// 分组捕获组 ['global'],即$1=global
// $1匹配成功, if替换global,即输出if-js
"body": "${TM_FILENAME_BASE/(global).*/${1:+if}/}" //输出: if
// 待匹配字符串 global-js
// 正则表达式 (global).*
// 所有匹配项 global-js
// 分组捕获组 ['global'],即$1=global
// $1匹配成功, if替换global-js,即输出if
}
复制代码
上述三、4两个示例匹配失败时,不作转换,即仍输出global.js
5
表示匹配成功,且相应的分组捕获成功时,将if
所述语句彻底替换正则表达式匹配项;
匹配成功,且相应的分组捕获为空时,将else
所述语句彻底替换正则表达式匹配项;
匹配失败时,else
所述语句即为处理后的变量
代码片断
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global)/${1:?if:else}/}", //输出: if-js
// 待匹配字符串 global-js
// 正则表达式 (global)
// 所有匹配项 global
// 分组捕获组 ['global'],即$1=global
// $1匹配成功, if替换global,即输出if-js
"body": "${TM_FILENAME_BASE/global/${1:?if:else}/}", //输出: else-js
// 待匹配字符串 global-js
// 正则表达式 global
// 所有匹配项 global
// 分组捕获组 [],$1对应的分组捕获为空
// else替换global,即输出else-js
"body": "${TM_FILENAME_BASE/(globald)/${1:?if:else}/}", //输出: else
// 待匹配字符串 global-js
// 正则表达式 (globald),匹配失败
// 所有匹配项 null
// 分组捕获组 无
// 输出 else
}
复制代码
6
同7
,表示匹配成功,且分组捕获(正则表达式中()
匹配到的项)成功时,不变;
匹配成功,且分组捕获为空时,将else
所述语句彻底替换正则表达式匹配项;
匹配失败时,else
所述语句即为处理后的变量
代码片断
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global)/${1:else}/}", //输出: global-js
// 待匹配字符串 global-js
// 正则表达式 (global)
// 所有匹配项 global
// 分组捕获组 ['global'],即$1=global
// 不变,输出global-js
"body": "${TM_FILENAME_BASE/global/${1:else}/}", //输出: else-js
// 待匹配字符串 global-js
// 正则表达式 global
// 所有匹配项 global
// 分组捕获组 [],$1对应的分组捕获为空
// else替换global,输出else-js
"body": "${TM_FILENAME_BASE/(globald)/${1:else}/}", //输出: else
// 待匹配字符串 global-js
// 正则表达式 (globald),匹配失败
// 所有匹配项 null
// 分组捕获组 无
// 输出 else
}
复制代码
8
表示匹配成功时,将text
彻底替换正则表达式匹配项; 匹配失败时,不变
代码片断
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global)/text/}", //输出: text-js
}
复制代码
Placeholder Transform
本质与Variable Transform
的第8条一致,只是正则表达式变为占位符常量
代码片断
"transform": {
"prefix": "tr",
"body": "$1 -> ${1/placeholder/text/}", //输入: placeholder 输出: placeholder -> text
}
复制代码
首先打开keybindings.json
而后能够添加以下
{
"key": "cmd+k 1",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"snippet": "console.log($1)$0"
}
}
复制代码
亦或者导入已有的snippet
{
"key": "cmd+k 1",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"langId": "csharp", // 语言包,如javascript,typescript
"name": "myFavSnippet" // 对应最开始提过的name,以下面使用场景的`import snippet`
}
}
复制代码
snippet
写snippet"import snipppet": {
"prefix": "sni",
"body": ["\"$1\": {", "\t\"prefix\": \"$2\",", "\t\"body\": [\"$3\"]", "}"]
},
复制代码
加个可选的description
"snipppet": {
"prefix": "sni",
"body": [
"\"$1\": {",
"\t\"prefix\": \"$2\",",
"\t\"body\": [\"$3\"]${4:,\n\t\"description\":\"${5}\"}",
"}"
]
}
复制代码
如某个数组长度较大的对象{title:'input',dataIndex:'input'}
,该数组中对象的每一个title
或dataIndex
不尽相同,则能够写个临时snippet,直接生成该结构。
"templates": {
"prefix": "tem",
"body": [",{dataIndex:$1,", "title:$2}"],
"description": ""
}
复制代码
import
组合"muji store file": {
"prefix": "store",
"body": [
"import { createStore } from '@souche-f2e/muji'",
"",
"type IState = {",
"",
"}",
"const state: IState = {",
"",
"}",
"const store = createStore({",
" state,",
" reducers: {",
" ",
" },",
" effects: {",
" ",
" },",
"})",
"export default store"
]
},
复制代码
"index.tsx under pages": {
"prefix": "ind",
"scope": "typescriptreact",
"body": [
"import React, { Component } from 'react'",
"import { dispatch, IRootState } from '@@/store'",
"import { connect } from '@souche-f2e/muji'",
"const mapStateToProps = (state: IRootState) => state.${1/(.*)/${1:/downcase}/}",
"",
"interface I$1Props extends ReturnType<typeof mapStateToProps> {",
" ",
"}",
"interface I${1}State {",
"",
"}",
"class $1 extends Component<I${1}Props, I${1}State> {",
" render() {",
" return ${3:null}",
" }",
"}",
"export default connect(mapStateToProps)($1)"
]
}
复制代码
只须要输入组件名,就能够一次性生成必备的格式。
安利一下prettier,配合snippet使用,简直绝配。