在 VS Code 中創建自定義 Emmet 代碼段

已發表: 2022-03-10
快速總結 ↬在本文中,Manuel 解釋了為什麼 Emmet 是他最喜歡的用於編寫 HTML 和 CSS 的生產力工具之一,以及如何在 Visual Studio Code 中創建自定義 Emmet 片段以幫助您進一步改進前端工作流程。

今年早些時候,我在博客上分享了我在開始新的 Web 項目時喜歡使用的 HTML 樣板,並逐行解釋。 它主要是<head>標籤和屬性的集合,我通常在我構建的每個網站上使用。 直到最近,我只是在需要時復制和粘貼樣板文件,但我決定通過將其作為片段添加到我選擇的編輯器 VS Code 來改進我的工作流程。

這是我創建的自定義片段的快速演示。

Visual Studio Code 中的片段和縮寫

VS Code 內置了自定義用戶片段以及 Emmet 提供的 HTML 和 CSS 片段和縮寫。

例如,如果您在 HTML 文檔中鍵入p>a{Sign Up}並按EnterTab ,Emmet 會將其轉換為以下標記:

 <p><a href="">Sign Up</a></p>

注意訪問 Emmet 文檔以了解如何使用縮寫語法。

如果我們經常需要這個特定的縮寫,我們可以將它保存為一個片段,以進一步改進我們的工作流程。

 { "html": { "snippets": { "signup": "p>a{Sign Up}" } } }

現在我們可以輸入signup並按EnterTab 鍵,我們將得到相同的結果。 我將在下一節解釋如何創建片段。

Emmet 默認帶有一堆 HTML 片段。 例如, ! 創建 HTML 文檔的基本結構。

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> </body> </html>

這很好,但是如果我們想通過刪除或添加元素和屬性來調整這個片段,我們必須覆蓋它並創建我們自己的片段。

創建和覆蓋片段

如果我們想創建自己的 Emmet 代碼片段或覆蓋 VS Code 中現有的代碼片段,則需要執行以下步驟:

  1. 創建一個snippets.json文件,添加這個基本的 JSON 結構並將其保存在硬盤的某個位置。
     { "html": { "snippets": { } }, "css": { "snippets": { } } }
  2. 打開 VS Code 設置(代碼 → 首選項 → 設置)並蒐索“Emmet Extensions Path”。
  3. 單擊“添加項目”,輸入保存您之前創建的snippets.json文件的文件夾的路徑,然後按“確定”。

而已。 現在我們準備通過向htmlcss對象添加屬性來創建片段,其中key是片段的名稱, value是縮寫或字符串。

我的一些自定義 HTML 片段

在我們深入探討片段創建並向您展示我是如何為我的 HTML 樣板創建片段之前,讓我們先用我創建的一些小但有用的片段來熱身。

延遲加載

開箱即用,有一個img縮寫,但沒有用於延遲加載的圖像。 我們可以使用默認縮寫,只需在方括號中添加我們需要的附加屬性和屬性值。

 { "html": { "snippets": { "img:l": "img[width height loading='lazy']" } } }

img:l + Enter / Tab現在創建以下標記:

 <img src="" alt="" width="" height="" loading="lazy">

我創建的大多數頁面由<header><main><footer>地標和一個<h1>組成。 自定義page縮寫讓我可以快速創建該結構。

 "snippets": { "page": "header>h1^main+footer{${0:©}}" }

page + Enter / Tab創建以下標記:

 <header> <h1></h1> </header> <main></main> <footer>©</footer>

這個縮寫很長,所以讓我們把它分解成更小的部分。

分解

創建一個<header>元素和一個子<h1>

 header>h1

向上移動,回到<header>的級別,並在<main>之後創建一個<footer> >。

 ^main+footer

<footer>中設置最後一個製表位並將默認文本設置為&copy

 {${0:©}}

導航

默認情況下,縮寫nav只是創建一個<nav>開始和結束標記,但我通常需要的是一個帶有嵌套<ul><li>元素和鏈接( <a> )的<nav> 。 如果頁面上有多個<nav>元素,它們也應該被標記,例如使用aria-label

 "nav": "nav[aria-label='${1:Main}']>ul>(li>a[aria-current='page']{${2:Current Page}})+(li*3>a{${0:Another Page}})"

這看起來很瘋狂,所以讓我們再次分解它。

分解

我們從具有aria-label屬性和嵌套<ul><nav>元素開始。 ${1:Main}使用文本“Main”填充屬性,並通過將光標移動到屬性值並在創建時突出顯示它來在屬性值處創建一個製表位。

 nav[aria-label='${1:Main}']>ul

然後我們創建四個帶有嵌套鍊接的列表項。 第一項是特殊的,因為它使用aria-current="page"標記活動頁面。 我們創建另一個製表位並使用文本“當前頁面”填充鏈接。

 (li>a[aria-current='page']>{${2:Current Page}})

最後,我們添加了三個帶有鏈接的列表項和鏈接文本“另一頁”。

 (li*3>a>{${0:Another Page}})

在我們適應之前,我們得到了這個:

 <-- Before: nav + TAB/Enter --> <nav></nav>

現在我們得到這個:

 <-- After: nav + TAB/Enter --> <nav aria-label="Main"> <ul> <li><a href="" aria-current="page">Current Page</a></li> <li><a href="">Another Page</a></li> <li><a href="">Another Page</a></li> <li><a href="">Another Page</a></li> </ul> </nav>
跳躍後更多! 繼續往下看↓

風格

默認style縮寫只創建<style>開始和結束標記,但通常當我使用<style>元素時,我會這樣做,因為我想快速測試或調試某些東西。

讓我們為<style>標籤添加一些默認規則:

 "style": "style>{\\* { box-sizing: border-box; \\}}+{\n${1:*}:focus \\{${2: outline: 2px solid red; }\\} }+{\n${0}}"

分解

某些字符(例如$*{} )必須使用\\進行轉義。

 style>{\\* { box-sizing: border-box; \\}}

\n創建一個換行符, ${1:*}將第一個製表位放在選擇器*處。

 {\n${1:*}:focus \\{${2: outline: 2px solid red; }\\}}
  • 之前<style><style>
  • 之後
     <style> * { box-sizing: border-box; }
    *:focus { outline: 2px solid red; } </style>

好吧,足夠的熱身。 讓我們創建複雜的片段。 起初,我想為我的樣板創建一個片段,但我創建了三個滿足不同需求的縮寫。

  1. 小的
  2. 中等的
  3. 滿的

小樣板

這是一個快速演示的樣板,它創建了以下內容:

  • 基本網站結構,
  • viewport元標記,
  • 頁面標題,
  • <style>元素,
  • 一個<h1>
 { "!": "{<!DOCTYPE html>}+html[lang=${1}${lang}]>(head>meta:utf+meta:vp+{}+title{${2:New document}}+{}+style)+body>(h1>{${3: New Document}})+{${0}}" }

分解

帶有文檔類型的字符串:

 {<!DOCTYPE html>}

帶有lang屬性的<html>元素。 lang屬性的值是一個可以在 VS 代碼設置(代碼 → 首選項 → 設置)中更改的變量。

 html[lang=${1}${lang}]

您可以通過在 VS Code 設置中搜索“emmet variables”並更改lang變量來更改頁面的默認自然語言。 您也可以在此處添加自定義變量。

VS Code 中有 2 個默認變量,lang 設置為 en,charset 設置為 UTF-8。

<head>包括charset元標記、 viewport元標記、 <title><style>標記。 {}創建一個新行。

 (head>meta:utf+meta:vp+{}+title{${2:New document}}+{}+style)

讓我們先快速看看這給了我們什麼。

 <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>New document</title> </head> </html>

看起來不錯,但是meta:utf縮寫在 HTML 中創建了舊的方式來定義charset ,而meta:vp創建了兩個我不需要的製表位,因為我從不為viewport使用不同的設置。

在繼續之前,讓我們覆蓋這些片段。

 { "meta:vp": "meta[name=viewport content='width=device-width, initial-scale=1']", "meta:utf": "meta[charset=${charset}]" }

最後但同樣重要的是, <body>元素,一個帶有默認文本的<h1> ,後跟最後一個製表位。

 body>(h1>{${3: New Document}})+{${0}}

最終樣板:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>New document</title> <style> * { box-sizing: border-box; } *:focus { outline: 2px solid red; } </style> </head> <body> <h1> New Document</h1> </body> </html>

對我來說,這是完美的最小調試設置。

樣板介質

雖然我僅將第一個樣板用於快速演示,但第二個樣板可用於復雜頁面。 該片段創建以下內容:

  • 基本網站結構,
  • viewport元標記,
  • 頁面標題,
  • .no-js / .js類,
  • 外部屏幕和打印樣式表,
  • descriptiontheme-color元標記,
  • 頁面結構。
 { "!!": "{<!DOCTYPE html>}+html[lang=${1}${lang}].no-js>{<!-- TODO: Check lang attribute --> }+(head>meta:utf+meta:vp+{}+title{${1: Change me}}+{}+(script[type=\"module\"]>{document.documentElement.classList.replace('no-js', 'js');})+{}+link:css+link:print+{}+meta[name=\"description\"][content=\"${2: Change me (up to ~155 characters)}\"]+{<!-- TODO: Change page description --> }+meta[name=\"theme-color\"][content=\"${2:#FF00FF}\"])+body>page" }

是的,我知道,這看起來像胡言亂語。 讓我們剖析一下。

分解

doctype和根元素與第一個示例類似,但有一個額外的no-js類和一個註釋,提醒我在必要時更改lang屬性。

 {<!DOCTYPE html>}+html[lang=${1}${lang}].no-js>{ }

TODO Highlight 擴展使評論非常流行。

該擴展程序以視覺方式突出顯示某些關鍵字,例如 TODO。

<head>包括charset元標記、 viewport元標記、 <title>{}創建一個新行。

 (head>meta:utf+meta:vp+{}+title{${1: Change me}}+{}

帶有一行 JavaScript 的腳本。 我在 JS 模塊支持上削減了芥末。 如果瀏覽器支持 JavaScript 模塊,則意味著它是支持現代 JavaScript(例如模塊、ES 6 語法、提取等)的瀏覽器。 我將大多數 JS 僅發送到這些瀏覽器,並且在 JavaScript 處於活動狀態時,如果組件的樣式不同,我會使用 CSS 中的js類。

 (script[type=\"module\"]>{document.documentElement.classList.replace('no-js', 'js');})+{}

兩個<link>元素; 第一個鏈接到主樣式表,第二個鏈接到打印樣式表。

 link:css+link:print+{}

頁面說明:

 meta[name=\"description\"\][content=\"${2: Change me (up to ~155 characters)}\"]+{ }

theme-color元標記:

 meta[name=\"theme-color\"\][content=\"${2:#FF00FF}\"])

正文元素和基本頁面結構:

 body>page

最終樣板文件如下所示:

 <!DOCTYPE html> <html lang="en" class="no-js"> <!-- TODO: Check lang attribute --> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title> Change me</title> <script type="module"> document.documentElement.classList.replace('no-js', 'js'); </script> <link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="print.css" media="print"> <meta name="description" content=" Change me (up to ~155 characters)"> <!-- TODO: Change page description --> <meta name="theme-color" content="#FF00FF"> </head> <body> <header> <h1></h1> </header> <main></main> <footer>©</footer> </body> </html>

完整的樣板

完整樣板與第二個樣板相似; 區別在於附加的meta標記和script標記。

該片段創建以下內容:

  • 基本網站結構,
  • viewport元標記,
  • 頁面標題,
  • js / no-js類,
  • 外部屏幕和打印樣式表,
  • description和開放圖元標籤,
  • theme-color元標記,
  • 規範的<link>標籤,
  • 網站圖標標籤,
  • 頁面結構,
  • < script>標籤。
 { "!!!": "{<!DOCTYPE html>}+html[lang=${1}${lang}].no-js>{<!-- TODO: Check lang attribute --> }+(head>meta:utf+meta:vp+{}+title{${1: Change me}}+{}+(script[type=\"module\"]>{document.documentElement.classList.replace('no-js', 'js');})+{}+link:css+link:print+{}+meta[property=\"og:title\"][content=\"${1: Change me}\"]+meta[name=\"description\"][content=\"${2: Change me (up to ~155 characters)}\"]+meta[property=\"og:description\"][content=\"${2: Change me (up to ~155 characters)}\"]+meta[property=\"og:image\"][content=\"${1:https://}\"]+meta[property=\"og:locale\"][content=\"${1:en_GB}\"]+meta[property=\"og:type\"][content=\"${1:website}\"]+meta[name=\"twitter:card\"][content=\"${1:summary_large_image}\"]+meta[property=\"og:url\"][content=\"${1:https://}\"]+{<!-- TODO: Change social media stuff --> }+{}+link[rel=\"canonical\"][href=\"${1:https://}\"]+{<!-- TODO: Change canonical link --> }+{}+link[rel=\"icon\"][href=\"${1:/favicon.ico}\"]+link[rel=\"icon\"][href=\"${1:/favicon.svg}\"][type=\"image/svg+xml\"]+link[rel=\"apple-touch-icon\"][href=\"${1:/apple-touch-icon.png}\"]+link[rel=\"manifest\"][href=\"${1:/my.webmanifest}\"]+{}+meta[name=\"theme-color\"][content=\"${2:#FF00FF}\"])+body>page+{}+script:src[type=\"module\"]" }

這個令人難以置信的長片段創建了這個:

 <!DOCTYPE html> <html lang="en" class="no-js"> <!-- TODO: Check lang attribute --> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title> Change me</title> <script type="module"> document.documentElement.classList.replace('no-js', 'js'); </script> <link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="print.css" media="print"> <meta property="og:title" content=" Change me"> <meta name="description" content=" Change me (up to ~155 characters)"> <meta property="og:description" content=" Change me (up to ~155 characters)"> <meta property="og:image" content="https://"> <meta property="og:locale" content="en_GB"> <meta property="og:type" content="website"> <meta name="twitter:card" content="summary_large_image"> <meta property="og:url" content="https://"> <!-- TODO: Change social media stuff --> <link rel="canonical" href="https://"> <!-- TODO: Change canonical link --> <link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.svg" type="image/svg+xml"> <link rel="apple-touch-icon" href="/apple-touch-icon.png"> <link rel="manifest" href="/my.webmanifest"> <meta name="theme-color" content="#FF00FF"> </head> <body> <header> <h1></h1> </header> <main></main> <footer>©</footer> <script src="" type="module"></script> </body> </html>

自定義 CSS 片段

為了完整起見,這裡是我正在使用的一些 CSS 片段。

調試

此代碼段創建一個帶有自定義偏移的 5px 紅色輪廓。

 "debug": "outline: 5px solid red;\noutline-offset: -5px;"

定心

display設置為 flex 並將其子項居中的片段。

 "center": "display: flex;\njustify-content: center;\nalign-items: center;"

position屬性設置為sticky ,在topleft屬性上有兩個製表位。

 "sticky": "position: sticky;\ntop: ${1:0};\nleft: ${2:0};" 
應用於div元素的所有 3 個 CSS 片段的演示。

用戶片段

在本文開頭,我提到 VS Code 還提供了自定義代碼片段。 與 Emmet 片段的不同之處在於您不能使用縮寫,但您也可以定義製表位並使用內部變量。

如何充分利用用戶片段可能是另一篇文章的主題,但這是我定義的自定義 CSS 片段的示例:

 "Visually hidden": { "prefix": "vh", "body": [ ".u-vh {", " position: absolute;\n white-space: nowrap;\n width: 1px;\n height: 1px;\n overflow: hidden;\n border: 0;\n padding: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n margin: -1px;", "}" ], "description": "A utility class for screen reader accessible hiding." }

當我們鍵入vh並按EnterTab時,此代碼段不僅創建 CSS 規則,而且是整個聲明塊。

 .u-vh { position: absolute; white-space: nowrap; width: 1px; height: 1px; overflow: hidden; border: 0; padding: 0; clip: rect(0 0 0 0); clip-path: inset(50%); margin: -1px; }

最後的話

創建這些片段需要一些時間,但值得付出努力,因為您可以根據個人喜好自定義 Emmet,自動執行重複性任務並從長遠來看節省時間。

我很想看看你使用了哪些片段,所以請在評論中與我們分享。 如果你想使用我的設置,你可以在 GitHub 上找到我最終的 snippets.json。

資源

  • 默認 CSS Emmet 片段
  • 默認 HTML Emmet 片段
  • 埃米特備忘單
  • VS Code 文檔中的 Emmet