更多文章,參見大搜車技術博客: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使用,簡直絕配。