大家好,我是韦恩,今天是铁人赛的二十六天,让我们在专案的现有架构里导入WebViewPanel元件吧!
在昨天,我们初步建立了View-ViewModel-Model的资料流架构。
现在我们的专案的src资料夹结构如下
./src
├── extension.ts
├── main
│ ├── common
│ │ └── control.ts
│ ├── data
│ │ └── snippets
│ │ ├── index.ts
│ │ └── snippetfile.ts
│ ├── model
│ │ ├── index.ts
│ │ └── snippet.ts
│ ├── view
│ │ └── treeview.ts
│ └── view-model
│ └── workspace
│ ├── index.ts
│ ├── initialize.ts
│ └── workspace.ts
└── test
├── runTest.ts
└── suite
├── extension.test.ts
└── index.ts
专案的资料夹根据不同功能的划分为各个模组,分为以下几类
这些档案模组会在extension.ts中主程序的进入点active function中初始化,并加以使用。
上面的树状图让我们对专案的个功能一目了然,现在,我们在view的资料夹新增一个webview-panel.ts,并实作WebViewPanel的类别。
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
type ObjectLike = { [key: string]: any };
interface Action<T extends ObjectLike> {
type: string;
payload: T
}
export class WebviewPanel {
private static _instance: WebviewPanel | null;
public static getInstance(context: vscode.ExtensionContext) {
if (WebviewPanel._instance) {
return WebviewPanel._instance;
}
return new WebviewPanel(context);
}
public static createOrShow(context: vscode.ExtensionContext) {
const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined;
if (WebviewPanel._instance) {
WebviewPanel._instance._panel.reveal(column);
return this._instance;
} else {
WebviewPanel._instance = new WebviewPanel(context);
return this._instance;
}
}
public readonly viewType = 'CodeManagerWebViewPanel';
private _panel: vscode.WebviewPanel;
private get webview() {
return this._panel.webview;
}
private _disposables: vscode.Disposable[] = [];
private _eventEmitter = new vscode.EventEmitter();
public get onDidReceiveMessage() {
return this._eventEmitter.event;
}
private constructor(private context: vscode.ExtensionContext) {
this._panel = this.createPanel(context
this.listenLifeCycleChanges();
this.listenWebViewMessage();
this.webview.html = this.loadWebviewContent();
}
private createPanel(context: vscode.ExtensionContext) {
return vscode.window.createWebviewPanel(
this.viewType,
'SnippetManager',
vscode.ViewColumn.Beside,
{
enableScripts: true,
localResourceRoots: [
vscode.Uri.joinPath(context.extensionUri, 'out', 'build'),
vscode.Uri.joinPath(context.extensionUri, 'out', 'build', 'assets')
]
}
);
}
private _dispose() {
this._panel.dispose();
this._disposables.forEach((d: vscode.Disposable) => d.dispose());
this._disposables = [];
this._eventEmitter.dispose();
WebviewPanel._instance = null;
}
private listenLifeCycleChanges() {
this._panel.onDidDispose(() => this._dispose(), null, this._disposables);
this._panel.onDidChangeViewState(
e => {},
null,
this._disposables
);
}
private listenWebViewMessage() {
this._panel.webview.onDidReceiveMessage(
message => {
this._eventEmitter.fire(e);
},
null,
this._disposables
);
}
public sendMessage<T extends ObjectLike>(action: Action<T>) {
this.webview.postMessage(action);
}
private webviewUri(relativePath: string) {
const uri = vscode.Uri.parse(
path.join(this.context.extensionPath,'out','build', relativePath)
);
return this.webview.asWebviewUri(uri);
}
public loadWebviewContent() {
const mainfest = readJSON(path.join(this.context.extensionPath, 'out/build/asset-manifest.json'));
const entrypointsJs = mainfest['entrypoints'].filter((p: string) => p.includes('static/js'));
console.log(entrypointsJs);
const nonce = getNonce();
return `<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" href="${this.webviewUri('./favicon.ico')}"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="theme-color" content="#000000"/>
<meta name="description" content="Web site created using create-react-app"/>
<title>React App</title>
<base href="${this.webviewUri('/')}">
<link rel="stylesheet" type="text/css" href="${this.webviewUri(mainfest.files['main.css'])}">
<link rel="apple-touch-icon" href="${this.webviewUri('./logo192.png')}"/>
<link rel="manifest" href="${this.webviewUri('./manifest.json')}"/>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="${this.webviewUri(entrypointsJs[0])}"></script>
<script src="${this.webviewUri(entrypointsJs[1])}"></script>
<script src="${this.webviewUri(entrypointsJs[2])}"></script>
</body>
</html>`;
}
}
function readJSON(path: string) {
const jsonString = fs.readFileSync(path, 'utf-8');
return JSON.parse(jsonString);
}
实作的方法大致与我们之前WebView(四)时提到的结构相同。
小有不同的是我们改变了WebView显示的位置,我们会将其显示於侧边的editor。
private createPanel(context: vscode.ExtensionContext) {
return vscode.window.createWebviewPanel(
this.viewType,
'SnippetManager',
vscode.ViewColumn.Beside,
{
enableScripts: true,
localResourceRoots: [
vscode.Uri.joinPath(context.extensionUri, 'out', 'build'),
vscode.Uri.joinPath(context.extensionUri, 'out', 'build', 'assets')
]
}
);
}
对外我们也会暴露onDidReceiveMessage
方法,让外部也可以监听收到Webview传来的资料,进行对应处理。
...
public get onDidReceiveMessage() {
return this._eventEmitter.event;
}
...
完成WebviewPanel之後,我们一样照先前教学将web专案命名为webview,并让webview资料夹与src资料夹一样位於根目录。
启动Webview後,我们会在当前编辑中的文件旁另开一个editor,如下所示。
好啦,今天我们开始导入WebviewPanel到专案里,明天也会继续有更多实作。
我们明天见,谢谢大家。
<<: [Day 27] 损失视觉化 Loss Visualization
今天就接续来讲中部地区的制作吧! 资料夹建立 lib/scareens/food_Middle/fo...
今天用这个阳春的版面来介绍版面、字体、图示还有间距的设定。刚刚跟接案的客户谈完流程,也收了头款,大家...
使用存到文字档的log取代print 解决相对网格里面,分母部位过小的问题 ...
由於不是设计师,对於UI/UX相关的东西懂得可能就跟完全没接触过的人一样, 所以在想做一个自己的Ap...
前言 接下来来讲讲如何透过 VSCode 快速上传图片到 imgur 吧! imgur 前面章节「(...