vscode插件開發(fā)Api:web視圖api(第一部分)

webview API允許擴(kuò)展在Visual Studio Code中創(chuàng)建完全可自定義的視圖捞蚂。例如妇押,內(nèi)置的 Markdown 擴(kuò)展使用 Web 視圖來呈現(xiàn) Markdown 預(yù)覽。
Web 視圖自由且強(qiáng)大姓迅、可用于構(gòu)建超出 VS Code 本機(jī) API 支持的復(fù)雜用戶界面敲霍。
github示例項(xiàng)目
github示例項(xiàng)目2

使用注意

web視圖消耗資源巨大,若能通過vscode本機(jī)Api實(shí)現(xiàn)功能丁存,則盡可能不要采用此法

跟隨示例來學(xué)習(xí)web視圖

示例的git地址

web視圖的基礎(chǔ)知識

創(chuàng)建一個(gè)命令來開我們的web視圖

再package.json中的 contributes字段下肩杈,注冊一個(gè)命令,如下圖:



其中catCoding.start是我們實(shí)際關(guān)聯(lián)的命令解寝。下面兩個(gè)字段是命令的名字和描述

創(chuàng)建web視圖本體

在extension.ts中寫入以下內(nèi)容


import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(
    vscode.commands.registerCommand('catCoding.start', () => {
      // Create and show a new webview
      const panel = vscode.window.createWebviewPanel(
        'catCoding', // Identifies the type of the webview. Used internally
        'Cat Coding', // Title of the panel displayed to the user
        vscode.ViewColumn.One, // Editor column to show the new webview panel in.
        {} // Webview options. More on these later.
      );
    })
  );
}

這段代碼額意思是注冊一個(gè)名為catCoing.start的命令扩然。該命令調(diào)用vscode.window.createWebviewPanel方法創(chuàng)建一個(gè)web視圖。其第二個(gè)參數(shù)Cat Coding是標(biāo)簽頁的名稱聋伦,第三個(gè)參數(shù)表示web視圖展示在哪一欄的工作區(qū)中
至此我們創(chuàng)建了一個(gè)新的web視圖夫偶,它有標(biāo)題,不過沒有內(nèi)容

為新的web視圖注入html內(nèi)容

依然是在extension.ts文件中觉增,改為一下內(nèi)容:

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(
    vscode.commands.registerCommand('catCoding.start', () => {
      // Create and show panel
      const panel = vscode.window.createWebviewPanel(
        'catCoding',
        'Cat Coding',
        vscode.ViewColumn.One,
        {}
      );

      // And set its HTML content
      panel.webview.html = getWebviewContent();
    })
  );
}

function getWebviewContent() {
  return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cat Coding</title>
</head>
<body>
    <img src="https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif" width="300" />
</body>
</html>`;
}

如上所示兵拢,html的內(nèi)容添加在webViewPanel的webview.html屬性當(dāng)中。webview.html是一個(gè)完整的html文件的內(nèi)容逾礁,主語語法哦说铃!
我們在這里向html中添加了一張gif圖:一個(gè)敲鍵盤的貓貓

內(nèi)容修改:可以做更多

我們可以多寫一些東西,使得整個(gè)頁面內(nèi)容更加靈活

import * as vscode from 'vscode';

const cats = {
  'Coding Cat': 'https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif',
  'Compiling Cat': 'https://media.giphy.com/media/mlvseq9yvZhba/giphy.gif'
};

export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(
    vscode.commands.registerCommand('catCoding.start', () => {
      const panel = vscode.window.createWebviewPanel(
        'catCoding',
        'Cat Coding',
        vscode.ViewColumn.One,
        {}
      );

      let iteration = 0;
      const updateWebview = () => {
        const cat = iteration++ % 2 ? 'Compiling Cat' : 'Coding Cat';
        panel.title = cat;
        panel.webview.html = getWebviewContent(cat);
      };

      // Set initial content
      updateWebview();

      // And schedule updates to the content every second
      setInterval(updateWebview, 1000);
    })
  );
}

function getWebviewContent(cat: keyof typeof cats) {
  return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cat Coding</title>
</head>
<body>
    <img src="${cats[cat]}" width="300" />
</body>
</html>`;
}

上面的代碼新增的內(nèi)容是:每秒調(diào)用切換一次貓貓的圖片
通過panel.title來修改panel的標(biāo)題
通過panel.webview.html來修改頁面的內(nèi)容

生命周期panel.onDidDispose

web視圖有自己的生命周期api嘹履。
panel.dispose方法用于關(guān)閉web視圖
panel.onDidDispose用于在視圖關(guān)閉時(shí)調(diào)用腻扇,使用方法如下:

    panel.onDidDispose(
        () => {
          // When the panel is closed, cancel any future updates to the webview content
          clearInterval(interval);
        },
        null,
        context.subscriptions
      );

讀取當(dāng)前panel是否為可見狀態(tài)

當(dāng)選中其他標(biāo)簽頁時(shí),咱們的web視圖的panel.visible將會變?yōu)閒alse

同一時(shí)刻相同web視圖只允許存在一個(gè)


當(dāng)前我們可以同時(shí)又多個(gè)coding Cat的web視圖砾嫉,這在很多時(shí)候顯然是不符合用戶需求的幼苛,我們可以將其改成同一時(shí)刻相同web視圖只允許存在一個(gè)

import * as vscode from 'vscode';

const cats = {
  'Coding Cat': 'https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif',
  'Compiling Cat': 'https://media.giphy.com/media/mlvseq9yvZhba/giphy.gif'
};

export function activate(context: vscode.ExtensionContext) {
    // Track currently webview panel
    let currentPanel: vscode.WebviewPanel | undefined = undefined;
  
    context.subscriptions.push(
      vscode.commands.registerCommand('catCoding.start', () => {
        const columnToShowIn = vscode.window.activeTextEditor
          ? vscode.window.activeTextEditor.viewColumn
          : undefined;
  
        if (currentPanel) {
          // If we already have a panel, show it in the target column
          currentPanel.reveal(columnToShowIn);
        } else {
          // Otherwise, create a new panel
          currentPanel = vscode.window.createWebviewPanel(
            'catCoding',
            'Cat Coding',
            vscode.ViewColumn.One,
            {}
          );
          currentPanel.webview.html = getWebviewContent('Coding Cat');
  
          // Reset when the current panel is closed
          currentPanel.onDidDispose(
            () => {
              currentPanel = undefined;
            },
            null,
            context.subscriptions
          );
        }
      })
    );
  }

  
function getWebviewContent(cat: keyof typeof cats) {
  return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cat Coding</title>
</head>
<body>
    <img src="${cats[cat]}" width="300" />
</body>
</html>`;
}

這里用到的一個(gè)zpi是panel.reveal(),該方法用于將視圖重新顯示到當(dāng)前的工作區(qū)
這里的columnToShowIn就是獲取的當(dāng)前的工作區(qū)在哪一欄

生命周期onDidChangeViewState

前面我們了解了panel.onDidDispose,下面來了解一個(gè)新的生命周期函數(shù)onDidChangeViewState
每當(dāng) Web 視圖的可見性更改或?qū)?Web 視圖移動到新列時(shí)焕刮,都會觸發(fā)該事件舶沿。我們的擴(kuò)展可以使用此事件根據(jù) Web 視圖顯示在哪一列中來更改貓:onDidChangeViewState

import * as vscode from 'vscode';


const cats = {
    'Coding Cat': 'https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif',
    'Compiling Cat': 'https://media.giphy.com/media/mlvseq9yvZhba/giphy.gif',
    'Testing Cat': 'https://media.giphy.com/media/3oriO0OEd9QIDdllqo/giphy.gif'
};

export function activate(context: vscode.ExtensionContext) {
    context.subscriptions.push(
        vscode.commands.registerCommand('catCoding.start', () => {
            const panel = vscode.window.createWebviewPanel(
                'catCoding',
                'Cat Coding',
                vscode.ViewColumn.One,
                {}
            );
            panel.webview.html = getWebviewContent('Coding Cat');

            // Update contents based on view state changes
            panel.onDidChangeViewState(
                e => {
                    const panel = e.webviewPanel;
                    switch (panel.viewColumn) {
                        case vscode.ViewColumn.One:
                            updateWebviewForCat(panel, 'Coding Cat');
                            return;

                        case vscode.ViewColumn.Two:
                            updateWebviewForCat(panel, 'Compiling Cat');
                            return;

                        case vscode.ViewColumn.Three:
                            updateWebviewForCat(panel, 'Testing Cat');
                            return;
                    }
                },
                null,
                context.subscriptions
            );
        })
    );
}

function updateWebviewForCat(panel: vscode.WebviewPanel, catName: keyof typeof cats) {
    panel.title = catName;
    panel.webview.html = getWebviewContent(catName);
}


function getWebviewContent(cat: keyof typeof cats) {
    return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cat Coding</title>
</head>
<body>
    <img src="${cats[cat]}" width="300" />
</body>
</html>`;
}

加載本地內(nèi)容

如果你注意看了我們的代碼就會發(fā)現(xiàn)舌剂,我們的貓貓的gif路徑是用的線上路徑
為什么不在文件夾中直接放幾張圖呢?
因?yàn)閃eb 視圖在無法直接訪問本地資源的隔離上下文中運(yùn)行暑椰。
這樣做是出于安全原因霍转。
同時(shí)這意味著,為了從擴(kuò)展加載圖像一汽、樣式表和其他資源避消,或從用戶的當(dāng)前工作區(qū)加載任何內(nèi)容,必須使用panel.webview.asWebviewUri函數(shù)將 localURI 轉(zhuǎn)換為 VS Code 可用于加載本地資源子集的特殊 URI召夹。

import * as vscode from 'vscode';
import * as path from 'path';

export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(
    vscode.commands.registerCommand('catCoding.start', () => {
      const panel = vscode.window.createWebviewPanel(
        'catCoding',
        'Cat Coding',
        vscode.ViewColumn.One,
        {}
      );

      // Get path to resource on disk
      const onDiskPath = vscode.Uri.file(
        path.join(context.extensionPath, 'media', 'cat.gif')
      );

      // And get the special URI to use with the webview
      const catGifSrc = panel.webview.asWebviewUri(onDiskPath);

      panel.webview.html = getWebviewContent(catGifSrc);
    })
  );
}


function getWebviewContent(cat: any) {
    return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cat Coding</title>
</head>
<body>
    <img src="${cat}" width="300" />
</body>
</html>`;
}

上面的代碼中onDiskPath為gif的localURI岩喷,注意其寫法:
path.join(context.extensionPath, 'media', 'cat.gif')拼接路徑
vscode.Uri.file獲取localURI
親測這樣寫也是一樣的:

const onDiskPath = vscode.Uri.file(
        "/g:/vscode-extension-samples-main/vscode-extension-samples-main/webview-sample/media/cat.gif"
      );

再用panel.webview.asWebviewUri轉(zhuǎn)換成vscode可識別的特殊URI,并從該位置加載gif圖

注意:
默認(rèn)情況下监憎,Web 視圖只能訪問以下位置的資源:

  • 在擴(kuò)展的安裝目錄中纱意。
  • 在用戶當(dāng)前處于活動狀態(tài)的工作區(qū)中。
    使用WebviewOptions.localResourceRoots則能夠允許訪問其他本地資源鲸阔。

還可以始終使用數(shù)據(jù) URI 直接在 Web 視圖中嵌入資源偷霉。

控制本地資源訪問:WebviewOptions.localResourceRoots

說到WebviewOptions.localResourceRoots我們需要回頭看看我們創(chuàng)建web視圖時(shí)的初始化方法:vscode.window.createWebviewPanel()當(dāng)時(shí)我們介紹了前三個(gè)參數(shù)的含義,那么第四個(gè)參數(shù)為什么是個(gè)空對象呢褐筛?

其實(shí)第四個(gè)參數(shù)就是我們這里說的WebviewOptions.localResourceRoots类少,它控制我們的視圖可以訪問的本地資源,空對象表示使用默認(rèn)值渔扎,也就是上述默認(rèn)情況下可以訪問的擴(kuò)展的安裝目錄中和用戶當(dāng)前處于活動狀態(tài)的工作區(qū)中硫狞。
如果按照下述設(shè)置,則表示完全隔離本地環(huán)境晃痴,不能訪問任何本地資源:

const panel = vscode.window.createWebviewPanel(
        'catCoding',
        'Cat Coding',
        vscode.ViewColumn.One,
        {
            localResourceRoots: []
        }
      );

可以通過設(shè)置對象中l(wèi)ocalResourceRoots的值來使視圖對某些本地資源擁有訪問權(quán)限残吩。

vscode.commands.registerCommand('catCoding.start', () => {
      const panel = vscode.window.createWebviewPanel(
        'catCoding',
        'Cat Coding',
        vscode.ViewColumn.One,
        {
            enableScripts: true,
            localResourceRoots: [
            vscode.Uri.file(path.join(context.extensionPath, "media")),
            vscode.Uri.file(vscode.env.appRoot)
        ]
    }

下片段代碼段表示只從擴(kuò)展中的目錄加載資源

        {
          localResourceRoots: [vscode.Uri.file(path.join(context.extensionPath, 'media'))]
        }

今天先到這里

import * as vscode from 'vscode';
import * as path from 'path';

export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(
    vscode.commands.registerCommand('catCoding.start', () => {
      const panel = vscode.window.createWebviewPanel(
        'catCoding',
        'Cat Coding',
        vscode.ViewColumn.One,
        {
            localResourceRoots: [
            vscode.Uri.file(path.join(context.extensionPath, "html")),
            vscode.Uri.file(vscode.env.appRoot)
        ]
    }
      );

      // Get path to resource on disk
      const onDiskPath = vscode.Uri.file(
        path.join(context.extensionPath, 'media', 'cat.gif')
      );
      console.log(context.extensionPath,path,path.join(context.extensionPath, 'media', 'cat.gif'),onDiskPath)
      // And get the special URI to use with the webview
      const catGifSrc = panel.webview.asWebviewUri(onDiskPath);
      
      panel.webview.html = getWebviewContent("/g:/vscode-extension-samples-main/vscode-extension-samples-main/webview-sample/media/cat.gif");
    })
  );
}


function getWebviewContent(cat: any) {
    return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cat Coding</title>
</head>
<body>
    <img src="${cat}" width="300" />
</body>
</html>`;
}

web視圖的主題樣式

web視圖作為vscode的一部分,我們是可以讓其根據(jù)vscode的皮膚來自動切換樣式顏色的
VS Code 將主題分為三個(gè)類別倘核,并向元素添加一個(gè)特殊類以指示當(dāng)前主題:body

  • vscode-light 亮主題泣侮。
  • vscode-dark 暗主題。
  • vscode-high-contrast 高對比度主題笤虫。
    下面我們用一個(gè)現(xiàn)實(shí)例子來說明:
    ①我們在extension.ts的html里面旁瘫,將body標(biāo)簽內(nèi)容改成:
   <body>
               <img src="${catGifPath}" width="300" />
               <h1>我不應(yīng)該變色</h1>
               <h1 id="lines-of-code-counter">0</h1>

               <script nonce="${nonce}" src="${scriptUri}"></script>
           </body>

②在media/vscode.css里面使用我們上面提到的技巧祖凫,根據(jù)vscode的主題琼蚯,來設(shè)置id為lines-of-code-counter的標(biāo)簽的顏色。

body.vscode-light #lines-of-code-counter {
    color: rgb(230, 8, 174);
  }
  
  body.vscode-dark #lines-of-code-counter{
    color: rgb(239, 255, 93);
  }
  
  body.vscode-high-contrast #lines-of-code-counter {
    color: red;
  }

③效果如下:
數(shù)字會跟隨vscode的主題切換,而漢字則始終保持同一顏色
【圖片待上傳,截圖待補(bǔ)充】

④完整的文件內(nèi)容如下
src\extension.ts

import * as vscode from 'vscode';

const cats = {
    'Coding Cat': 'https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif',
    'Compiling Cat': 'https://media.giphy.com/media/mlvseq9yvZhba/giphy.gif',
    'Testing Cat': 'https://media.giphy.com/media/3oriO0OEd9QIDdllqo/giphy.gif'
};

export function activate(context: vscode.ExtensionContext) {
    context.subscriptions.push(
        vscode.commands.registerCommand('catCoding.start', () => {
            CatCodingPanel.createOrShow(context.extensionUri);
        })
    );

    context.subscriptions.push(
        vscode.commands.registerCommand('catCoding.doRefactor', () => {
            if (CatCodingPanel.currentPanel) {
                CatCodingPanel.currentPanel.doRefactor();
            }
        })
    );

    if (vscode.window.registerWebviewPanelSerializer) {
        // Make sure we register a serializer in activation event
        vscode.window.registerWebviewPanelSerializer(CatCodingPanel.viewType, {
            async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, state: any) {
                console.log(`Got state: ${state}`);
                // Reset the webview options so we use latest uri for `localResourceRoots`.
                webviewPanel.webview.options = getWebviewOptions(context.extensionUri);
                CatCodingPanel.revive(webviewPanel, context.extensionUri);
            }
        });
    }
}

function getWebviewOptions(extensionUri: vscode.Uri): vscode.WebviewOptions {
    return {
        // Enable javascript in the webview
        enableScripts: true,

        // And restrict the webview to only loading content from our extension's `media` directory.
        localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media')]
    };
}

/**
 * Manages cat coding webview panels
 */
class CatCodingPanel {
    /**
     * Track the currently panel. Only allow a single panel to exist at a time.
     */
    public static currentPanel: CatCodingPanel | undefined;

    public static readonly viewType = 'catCoding';

    private readonly _panel: vscode.WebviewPanel;
    private readonly _extensionUri: vscode.Uri;
    private _disposables: vscode.Disposable[] = [];

    public static createOrShow(extensionUri: vscode.Uri) {
        const column = vscode.window.activeTextEditor
            ? vscode.window.activeTextEditor.viewColumn
            : undefined;

        // If we already have a panel, show it.
        if (CatCodingPanel.currentPanel) {
            CatCodingPanel.currentPanel._panel.reveal(column);
            return;
        }

        // Otherwise, create a new panel.
        const panel = vscode.window.createWebviewPanel(
            CatCodingPanel.viewType,
            'Cat Coding',
            column || vscode.ViewColumn.One,
            getWebviewOptions(extensionUri),
        );

        CatCodingPanel.currentPanel = new CatCodingPanel(panel, extensionUri);
    }

    public static revive(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
        CatCodingPanel.currentPanel = new CatCodingPanel(panel, extensionUri);
    }

    private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
        this._panel = panel;
        this._extensionUri = extensionUri;

        // Set the webview's initial html content
        this._update();

        // Listen for when the panel is disposed
        // This happens when the user closes the panel or when the panel is closed programmatically
        this._panel.onDidDispose(() => this.dispose(), null, this._disposables);

        // Update the content based on view changes
        this._panel.onDidChangeViewState(
            e => {
                if (this._panel.visible) {
                    this._update();
                }
            },
            null,
            this._disposables
        );

        // Handle messages from the webview
        this._panel.webview.onDidReceiveMessage(
            message => {
                switch (message.command) {
                    case 'alert':
                        vscode.window.showErrorMessage(message.text);
                        return;
                }
            },
            null,
            this._disposables
        );
    }

    public doRefactor() {
        // Send a message to the webview webview.
        // You can send any JSON serializable data.
        this._panel.webview.postMessage({ command: 'refactor' });
    }

    public dispose() {
        CatCodingPanel.currentPanel = undefined;

        // Clean up our resources
        this._panel.dispose();

        while (this._disposables.length) {
            const x = this._disposables.pop();
            if (x) {
                x.dispose();
            }
        }
    }

    private _update() {
        const webview = this._panel.webview;

        // Vary the webview's content based on where it is located in the editor.
        switch (this._panel.viewColumn) {
            case vscode.ViewColumn.Two:
                this._updateForCat(webview, 'Compiling Cat');
                return;

            case vscode.ViewColumn.Three:
                this._updateForCat(webview, 'Testing Cat');
                return;

            case vscode.ViewColumn.One:
            default:
                this._updateForCat(webview, 'Coding Cat');
                return;
        }
    }

    private _updateForCat(webview: vscode.Webview, catName: keyof typeof cats) {
        this._panel.title = catName;
        this._panel.webview.html = this._getHtmlForWebview(webview, cats[catName]);
    }

    private _getHtmlForWebview(webview: vscode.Webview, catGifPath: string) {
        // Local path to main script run in the webview
        const scriptPathOnDisk = vscode.Uri.joinPath(this._extensionUri, 'media', 'main.js');

        // And the uri we use to load this script in the webview
        const scriptUri = webview.asWebviewUri(scriptPathOnDisk);

        // Local path to css styles
        const styleResetPath = vscode.Uri.joinPath(this._extensionUri, 'media', 'reset.css');
        const stylesPathMainPath = vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css');

        // Uri to load styles into webview
        const stylesResetUri = webview.asWebviewUri(styleResetPath);
        const stylesMainUri = webview.asWebviewUri(stylesPathMainPath);

        // Use a nonce to only allow specific scripts to be run
        const nonce = getNonce();

        return `<!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">

                <!--
                    Use a content security policy to only allow loading images from https or from our extension directory,
                    and only allow scripts that have a specific nonce.
                -->
                <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; img-src ${webview.cspSource} https:; script-src 'nonce-${nonce}';">

                <meta name="viewport" content="width=device-width, initial-scale=1.0">

                <link href="${stylesResetUri}" rel="stylesheet">
                <link href="${stylesMainUri}" rel="stylesheet">

                <title>Cat Coding</title>
            </head>
            <body>
                <img src="${catGifPath}" width="300" />
                <h1>我不應(yīng)該變色</h1>
                <h1 id="lines-of-code-counter">0</h1>

                <script nonce="${nonce}" src="${scriptUri}"></script>
            </body>
            </html>`;
    }
}

function getNonce() {
    let text = '';
    const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    for (let i = 0; i < 32; i++) {
        text += possible.charAt(Math.floor(Math.random() * possible.length));
    }
    return text;
}

media\vscode.css

:root {
    --container-padding: 20px;
    --input-padding-vertical: 6px;
    --input-padding-horizontal: 4px;
    --input-margin-vertical: 4px;
    --input-margin-horizontal: 0;
}

body {
    padding: 0 var(--container-padding);
    color: var(--vscode-foreground);
    font-size: var(--vscode-font-size);
    font-weight: var(--vscode-font-weight);
    font-family: var(--vscode-font-family);
    background-color: var(--vscode-editor-background);
}

ol,
ul {
    padding-left: var(--container-padding);
}

body > *,
form > * {
    margin-block-start: var(--input-margin-vertical);
    margin-block-end: var(--input-margin-vertical);
}

*:focus {
    outline-color: var(--vscode-focusBorder) !important;
}

a {
    color: var(--vscode-textLink-foreground);
}

a:hover,
a:active {
    color: var(--vscode-textLink-activeForeground);
}

code {
    font-size: var(--vscode-editor-font-size);
    font-family: var(--vscode-editor-font-family);
}

button {
    border: none;
    padding: var(--input-padding-vertical) var(--input-padding-horizontal);
    width: 100%;
    text-align: center;
    outline: 1px solid transparent;
    outline-offset: 2px !important;
    color: var(--vscode-button-foreground);
    background: var(--vscode-button-background);
}

button:hover {
    cursor: pointer;
    background: var(--vscode-button-hoverBackground);
}

button:focus {
    outline-color: var(--vscode-focusBorder);
}

button.secondary {
    color: var(--vscode-button-secondaryForeground);
    background: var(--vscode-button-secondaryBackground);
}

button.secondary:hover {
    background: var(--vscode-button-secondaryHoverBackground);
}

input:not([type='checkbox']),
textarea {
    display: block;
    width: 100%;
    border: none;
    font-family: var(--vscode-font-family);
    padding: var(--input-padding-vertical) var(--input-padding-horizontal);
    color: var(--vscode-input-foreground);
    outline-color: var(--vscode-input-border);
    background-color: var(--vscode-input-background);
}

input::placeholder,
textarea::placeholder {
    color: var(--vscode-input-placeholderForeground);
}

/* #lines-of-code-counter {
color: aqua;
} */

body.vscode-light #lines-of-code-counter {
    color: rgb(230, 8, 174);
  }
  
  body.vscode-dark #lines-of-code-counter{
    color: rgb(239, 255, 93);
  }
  
  body.vscode-high-contrast #lines-of-code-counter {
    color: red;
  }

CSS的其他技巧

在編程中如果想要使用和vscode主題一樣的顏色辩诞,怎么獲取比較快呢操禀?
  • 使用CSS變量來獲取,例如:
code {
  color: var(--vscode-editor-foreground);
}
  • 自動補(bǔ)全這些變量名质礼,可以考慮使用vscode插件
除了顏色兔院,還有字體也可以獲取到:

--vscode-editor-font-family- 編輯器字體系列(來自設(shè)置)零聚。editor.fontFamily
--vscode-editor-font-weight- 編輯器字體粗細(xì)(來自設(shè)置)榨了。editor.fontWeight
--vscode-editor-font-size- 編輯器字體大屑宓(來自設(shè)置)。editor.fontSize

對特定主題設(shè)置樣式

如果我們不滿足于只對vscode的亮龙屉、暗呐粘、高對比三種主題設(shè)置各自的樣式,而是想對其各自的主題分別設(shè)置樣式转捕,例如對主題《One Dark Pro》的樣式進(jìn)行設(shè)計(jì)作岖,如下:

body[data-vscode-theme-id="One Dark Pro"] {
    background: hotpink;
}

對于需要編寫針對單個(gè)主題的 CSS 的特殊情況,webviews 的 body 元素具有一個(gè)名為 data 屬性的數(shù)據(jù)屬性五芝,該屬性存儲當(dāng)前活動主題的 ID痘儡。這使您可以為 Web 視圖編寫特定于主題的 CSS

支持的媒體格式:

音頻:

  • Wav
  • Mp3
  • Ogg
  • Flac
    視頻:
  • H.264
  • VP8
    注意:使用視頻時(shí),需要保證視頻軌道和音頻軌道都是支持的枢步,不然的話vscode就會播放視頻沉删,但是沒有聲音
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市醉途,隨后出現(xiàn)的幾起案子丑念,更是在濱河造成了極大的恐慌,老刑警劉巖结蟋,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脯倚,死亡現(xiàn)場離奇詭異,居然都是意外死亡嵌屎,警方通過查閱死者的電腦和手機(jī)推正,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宝惰,“玉大人植榕,你說我怎么就攤上這事∧岫幔” “怎么了尊残?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長淤堵。 經(jīng)常有香客問我寝衫,道長,這世上最難降的妖魔是什么拐邪? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任慰毅,我火速辦了婚禮,結(jié)果婚禮上扎阶,老公的妹妹穿的比我還像新娘汹胃。我一直安慰自己婶芭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布着饥。 她就那樣靜靜地躺著犀农,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宰掉。 梳的紋絲不亂的頭發(fā)上井赌,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機(jī)與錄音贵扰,去河邊找鬼仇穗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛戚绕,可吹牛的內(nèi)容都是我干的纹坐。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼舞丛,長吁一口氣:“原來是場噩夢啊……” “哼耘子!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起球切,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤谷誓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后吨凑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捍歪,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年鸵钝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了糙臼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恩商,死狀恐怖变逃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情怠堪,我是刑警寧澤揽乱,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站粟矿,受9級特大地震影響凰棉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嚷炉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一渊啰、第九天 我趴在偏房一處隱蔽的房頂上張望探橱。 院中可真熱鬧申屹,春花似錦绘证、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杆煞,卻和暖如春魏宽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背决乎。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工队询, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人构诚。 一個(gè)月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓蚌斩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親范嘱。 傳聞我的和親對象是個(gè)殘疾皇子送膳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容