@TOC
vConsole
核心类的实现,该工具由腾讯开发,用于在移动端进行调试。代码主要涉及 vConsole
的初始化、插件管理、事件触发和销毁等功能。以下是对代码的详细解析:
概述
vConsole
是一个用于移动端的调试工具。- 提供日志、网络、系统信息、元素查看和存储等调试功能。
- 使用 Svelte 作为前端框架来构建调试面板。
核心类 VConsole
1. 导入模块和定义常量
javascript
import type { SvelteComponent } from 'svelte';
import type { VConsoleOptions } from './options.interface';
import * as tool from '../lib/tool';
import $ from '../lib/query';
import { default as CoreCompClass } from './core.svelte';
import type { IVConsoleTopbarOptions, IVConsolePluginEventName } from '../lib/plugin';
import { VConsolePlugin } from '../lib/plugin';
import { VConsoleLogPlugin } from '../log/log';
import { VConsoleDefaultPlugin } from '../log/default';
import { VConsoleSystemPlugin } from '../log/system';
import { VConsoleNetworkPlugin } from '../network/network';
import { VConsoleElementPlugin } from '../element/element';
import { VConsoleStoragePlugin } from '../storage/storage';
import { VConsoleLogExporter } from '../log/log.exporter';
import { VConsoleNetworkExporter } from '../network/network.exporter';
const VCONSOLE_ID = '#__vconsole';
- 导入必要的模块和类型。
- 定义常量
VCONSOLE_ID
,用于标识vConsole
的 DOM 元素。
2. 类的定义和构造函数
javascript
export class VConsole {
public version: string = __VERSION__;
public isInited: boolean = false;
public option: VConsoleOptions = {};
protected compInstance: SvelteComponent;
protected pluginList: { [id: string]: VConsolePlugin } = {}; // plugin instance
// Export plugin methods
public log: VConsoleLogExporter;
public system: VConsoleLogExporter;
public network: VConsoleNetworkExporter;
// Export static classes
public static VConsolePlugin: typeof VConsolePlugin;
public static VConsoleLogPlugin: typeof VConsoleLogPlugin;
public static VConsoleDefaultPlugin: typeof VConsoleDefaultPlugin;
public static VConsoleSystemPlugin: typeof VConsoleSystemPlugin;
public static VConsoleNetworkPlugin: typeof VConsoleNetworkPlugin;
public static VConsoleElementPlugin: typeof VConsoleElementPlugin;
public static VConsoleStoragePlugin: typeof VConsoleStoragePlugin;
constructor(opt?: VConsoleOptions) {
if (!!VConsole.instance && VConsole.instance instanceof VConsole) {
console.debug('[vConsole] vConsole is already exists.');
return VConsole.instance;
}
VConsole.instance = this;
this.isInited = false;
this.option = {
defaultPlugins: ['system', 'network', 'element', 'storage'],
log: {},
network: {},
storage: {},
};
// merge options
if (tool.isObject(opt)) {
for (let key in opt) {
this.option[key] = opt[key];
}
}
// check deprecated options
if (typeof this.option.maxLogNumber !== 'undefined') {
this.option.log.maxLogNumber = this.option.maxLogNumber;
console.debug('[vConsole] Deprecated option: `maxLogNumber`, use `log.maxLogNumber` instead.');
}
if (typeof this.option.onClearLog !== 'undefined') {
console.debug('[vConsole] Deprecated option: `onClearLog`.');
}
if (typeof this.option.maxNetworkNumber !== 'undefined') {
this.option.network.maxNetworkNumber = this.option.maxNetworkNumber;
console.debug('[vConsole] Deprecated option: `maxNetworkNumber`, use `network.maxNetworkNumber` instead.');
}
// add built-in plugins
this._addBuiltInPlugins();
// try to init
const _onload = () => {
if (this.isInited) {
return;
}
this._initComponent();
this._autoRun();
};
if (document !== undefined) {
if (document.readyState === 'loading') {
$.bind(<any>window, 'DOMContentLoaded', _onload);
} else {
_onload();
}
} else {
// if document does not exist, wait for it
let _timer;
const _pollingDocument = () => {
if (!!document && document.readyState == 'complete') {
_timer && clearTimeout(_timer);
_onload();
} else {
_timer = setTimeout(_pollingDocument, 1);
}
};
_timer = setTimeout(_pollingDocument, 1);
}
}
- 定义
VConsole
类,并在构造函数中进行初始化。 - 检查是否已有实例存在,如果有则返回现有实例。
- 初始化选项并合并用户传入的选项。
- 检查并处理已弃用的选项。
- 添加内置插件。
- 尝试初始化组件,等待文档加载完成后进行初始化。
3. 添加内置插件
javascript
/**
* Add built-in plugins.
*/
private _addBuiltInPlugins() {
// add default log plugin
this.addPlugin(new VConsoleDefaultPlugin('default', 'Log'));
// add other built-in plugins according to user's config
const list = this.option.defaultPlugins;
const plugins = {
'system': { proto: VConsoleSystemPlugin, name: 'System' },
};
if (__TARGET__ === 'web') {
plugins['network'] = { proto: VConsoleNetworkPlugin, name: 'Network' };
plugins['element'] = { proto: VConsoleElementPlugin, name: 'Element' };
plugins['storage'] = { proto: VConsoleStoragePlugin, name: 'Storage' };
}
if (!!list && tool.isArray(list)) {
for (let i = 0; i < list.length; i++) {
const pluginConf = plugins[list[i]];
if (!!pluginConf) {
this.addPlugin(new pluginConf.proto(list[i], pluginConf.name));
} else {
console.debug('[vConsole] Unrecognized default plugin ID:', list[i]);
}
}
}
}
- 根据用户配置添加内置插件。
- 支持日志、系统、网络、元素查看和存储等插件。
4. 初始化 Svelte 组件
javascript
/**
* Init svelte component.
*/
private _initComponent() {
if (! $.one(VCONSOLE_ID)) {
const switchX = <any>tool.getStorage('switch_x') * 1;
const switchY = <any>tool.getStorage('switch_y') * 1;
let target: HTMLElement;
if (typeof this.option.target === 'string') {
target = document.querySelector(this.option.target);
} else if (this.option.target instanceof HTMLElement) {
target = this.option.target;
}
if (! (target instanceof HTMLElement)) {
target = document.documentElement;
}
this.compInstance = new CoreCompClass({
target,
props: {
switchButtonPosition: {
x: switchX,
y: switchY,
},
},
});
// bind events
this.compInstance.$on('show', (e) => {
if (e.detail.show) {
this.show();
} else {
this.hide();
}
});
this.compInstance.$on('changePanel', (e) => {
const pluginId = e.detail.pluginId;
this.showPlugin(pluginId);
});
}
// set options into component
this._updateComponentByOptions();
}
- 初始化 Svelte 组件并绑定事件。
- 设置开关按钮的位置并绑定显示和切换面板事件。
5. 自动运行
javascript
/**
* Auto run after initialization.
* @private
*/
private _autoRun() {
this.isInited = true;
// init plugins
for (let id in this.pluginList) {
this._initPlugin(this.pluginList[id]);
}
// show first plugin
this._showFirstPluginWhenEmpty();
this.triggerEvent('ready');
}
- 初始化所有插件。
- 如果没有激活的插件,显示第一个插件。
- 触发
ready
事件。
6. 添加和移除插件
javascript
/**
* Add a new plugin.
*/
public addPlugin(plugin: VConsolePlugin) {
// ignore this plugin if it has already been installed
if (this.pluginList[plugin.id] !== undefined) {
console.debug('[vConsole] Plugin `' + plugin.id + '` has already been added.');
return false;
}
this.pluginList[plugin.id] = plugin;
// init plugin only if vConsole is ready
if (this.isInited) {
this._initPlugin(plugin);
// if it's the only plugin, show it by default
this._showFirstPluginWhenEmpty();
}
return true;
}
/**
* Remove a plugin.
*/
public removePlugin(pluginID: string) {
pluginID = (pluginID + '').toLowerCase();
const plugin = this.pluginList[pluginID];
// skip
if is has not been installed
if (plugin === undefined) {
console.debug('[vConsole] Plugin `' + pluginID + '` does not exist.');
return false;
}
// trigger `remove` event before uninstall
plugin.trigger('remove');
try {
delete this.pluginList[pluginID];
delete this.compInstance.pluginList[pluginID];
} catch (e) {
this.pluginList[pluginID] = undefined;
this.compInstance.pluginList[pluginID] = undefined;
}
this.compInstance.pluginList = this.compInstance.pluginList;
// show the first plugin by default
if (this.compInstance.activedPluginId == pluginID) {
this.compInstance.activedPluginId = '';
this._showFirstPluginWhenEmpty();
}
return true;
}
addPlugin
方法用于添加新插件,初始化插件并在需要时显示第一个插件。removePlugin
方法用于移除插件,并在需要时显示第一个插件。
7. 显示和隐藏面板
javascript
/**
* Show console panel.
*/
public show() {
if (!this.isInited) {
return;
}
this.compInstance.show = true;
this._triggerPluginsEvent('showConsole');
}
/**
* Hide console panel.
*/
public hide() {
if (!this.isInited) {
return;
}
this.compInstance.show = false;
this._triggerPluginsEvent('hideConsole');
}
/**
* Show switch button
*/
public showSwitch() {
if (!this.isInited) {
return;
}
this.compInstance.showSwitchButton = true;
}
/**
* Hide switch button.
*/
public hideSwitch() {
if (!this.isInited) {
return;
}
this.compInstance.showSwitchButton = false;
}
/**
* Show a plugin panel.
*/
public showPlugin(pluginId: string) {
if (!this.isInited) {
return;
}
if (!this.pluginList[pluginId]) {
console.debug('[vConsole] Plugin `' + pluginId + '` does not exist.');
}
// trigger plugin event
this.compInstance.activedPluginId && this._triggerPluginEvent(this.compInstance.activedPluginId, 'hide');
this.compInstance.activedPluginId = pluginId;
this._triggerPluginEvent(this.compInstance.activedPluginId, 'show');
}
show
和hide
方法用于显示和隐藏调试面板。showSwitch
和hideSwitch
方法用于显示和隐藏开关按钮。showPlugin
方法用于显示指定插件的面板。
总结
vConsole
是一个功能强大的移动端调试工具,通过插件机制提供了日志、网络、系统信息、元素查看和存储等功能。核心类 VConsole
负责初始化、插件管理、事件触发和销毁等操作,使用 Svelte 组件来构建调试面板,并提供了一系列方法来管理插件和显示调试信息。