第一篇: 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刷新画面;