vscode源碼分析【九】窗口裏的主要元素

第一篇: vscode源碼分析【一】從源碼運行vscode
第二篇:vscode源碼分析【二】程序的啓動邏輯,第一個窗口是如何建立的
第三篇:vscode源碼分析【三】程序的啓動邏輯,性能問題的追蹤
第四篇:vscode源碼分析【四】程序啓動的邏輯,最初建立的服務
第五篇:vscode源碼分析【五】事件分發機制
第六篇:vscode源碼分析【六】服務實例化和單例的實現
第七篇:vscode源碼分析【七】主進程啓動消息通訊服務
第八篇:vscode源碼分析【八】加載第一個畫面

在上一節中,咱們講到加載第一個畫面時,加載了一個workbench.js
(src\vs\code\electron-browser\workbench\workbench.js)
這個文件中執行了:css

bootstrapWindow.load([
	'vs/workbench/workbench.main',
	'vs/nls!vs/workbench/workbench.main',
	'vs/css!vs/workbench/workbench.main'
]

加載了workbench.main,這個文件負責初始化界面須要用到的庫
它自己不負責執行任何邏輯,但卻加載了三百多個類,哈!
bootstrapWindow.load的回調方法裏,執行了:html

require('vs/workbench/electron-browser/main').main(configuration);

這句代碼很重要
咱們看看這個類的main方法;它執行了:bootstrap

const renderer = new CodeRendererMain(configuration);
	return renderer.open();

CodeRendererMain類也在同一個文件裏
(src\vs\workbench\electron-browser\main.ts)
它的構造函數裏作了一些初始化工做(界面縮放事件設置、文件讀寫庫的設置等)
不重要,先不理會,先看open方法:app

this.workbench = new Workbench(document.body, services.serviceCollection, services.logService);
//......
const instantiationService = this.workbench.startup();

你看到,咱們把body傳給了workbench的實例
workbench的構造函數裏,並無用這個body作什麼事情;
而是把他傳遞給了它的父類:Layout(src\vs\workbench\browser\layout.ts),存儲在父類parent屬性裏
這個類很重要,咱們待會兒會說;
如今咱們看看workbench的startup方法electron

// Layout
				this.initLayout(accessor);
				// Registries
				this.startRegistries(accessor);
				// Context Keys
this._register(instantiationService.createInstance(WorkbenchContextKeysHandler));
				// Register Listeners
				this.registerListeners(lifecycleService, storageService, configurationService);
				// Render Workbench
this.renderWorkbench(instantiationService, accessor.get(INotificationService) as NotificationService, storageService, configurationService);
				// Workbench Layout
this.createWorkbenchLayout(instantiationService);
				// Layout
				this.layout();

initLayout方法,初始化了一堆服務(environmentService,lifecycleService等),監聽了一堆事件(全屏、編輯器顯隱等)
renderWorkbench方法(最重要!),給body和一個叫container的元素加了一系列的樣式;
container元素是在父類Layout裏初始化的,這個元素最終會是全部組件的父親;編輯器

private _container: HTMLElement = document.createElement('div');
	get container(): HTMLElement { return this._container; }

以後,給container元素加了幾個子元素:ide

[
			{ id: Parts.TITLEBAR_PART, role: 'contentinfo', classes: ['titlebar'] },
			{ id: Parts.ACTIVITYBAR_PART, role: 'navigation', classes: ['activitybar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] },
			{ id: Parts.SIDEBAR_PART, role: 'complementary', classes: ['sidebar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] },
			{ id: Parts.EDITOR_PART, role: 'main', classes: ['editor'], options: { restorePreviousState: this.state.editor.restoreEditors } },
			{ id: Parts.PANEL_PART, role: 'complementary', classes: ['panel', this.state.panel.position === Position.BOTTOM ? 'bottom' : 'right'] },
			{ id: Parts.STATUSBAR_PART, role: 'contentinfo', classes: ['statusbar'] }
		].forEach(({ id, role, classes, options }) => {
			const partContainer = this.createPart(id, role, classes);

			if (!configurationService.getValue('workbench.useExperimentalGridLayout')) {				this.container.insertBefore(partContainer, this.container.lastChild);
			}

			this.getPart(id).create(partContainer, options);
		});

這幾個子元素分別是最左側的ACTIVITYBAR_PART,中間的EDITOR_PART,等等(注意:窗口的菜單欄也是他本身渲染的)

這些元素建立出來以後,就加入到container裏去了;
而後把container加入到body裏去了(parent存的是body)函數

this.parent.appendChild(this.container);

在startup方法裏還調用了this.layout()方法源碼分析

position(this.container, 0, 0, 0, 0, 'relative');
				size(this.container, this._dimension.width, this._dimension.height);
				// Layout the grid widget
this.workbenchGrid.layout(this._dimension.width, this._dimension.height);
				// Layout grid views
				this.layoutGrid();

在這裏把container放到到最大,佔據整個body
至此界面主要元素渲染完成!


另外:
想調試界面裏的內容,就不能用第一節講的調試方法來調試了;
你能夠運行:post

.\scripts\code.bat

先啓動畫面,而後按Ctrl+Shift+i打開調試窗口;
若是須要刷新畫面的話,能夠按Ctrl+R刷新畫面;

相關文章
相關標籤/搜索