<template> <div id="devtools"> <div v-show="isShowDebug" class="find"> <div v-if="false"> <el-button type="success" @click="onMemoryTest">内存测试</el-button> </div> <div v-if="false"> <span>JS堆栈限制: {{ memory.performance.jsHeapSizeLimit }}</span> <span>JS堆栈大小: {{ memory.performance.totalJSHeapSize }}</span> <span>JS堆栈使用: {{ memory.performance.usedJSHeapSize }}</span> </div> <div class="left"> <div class="tool-btn"> <el-switch active-text="实时监控" v-model="watchEveryTime" @change="onChangeWatchState"></el-switch> <div class="flex1"></div> <el-button type="success" class="el-icon-refresh" @click="onBtnClickUpdateTree"></el-button> </div> <div class="treeList"> <el-tree :data="treeData" ref="tree" style="display: inline-block;" :props="defaultProps" :highlight-current="true" :default-expand-all="false" :default-expanded-keys="expandedKeys" :expand-on-click-node="false" node-key="uuid" @node-expand="onNodeExpand" @node-collapse="onNodeCollapse" @node-click="handleNodeClick"> <!-- :render-content="renderContent"--> <span slot-scope="{node,data}" class="leaf" :class="data.active?'leaf-show':'leaf-hide'"> <span>{{ node.label }}</span> <!-- <el-button v-if="!!data||true"> 显示</el-button>--> </span> </el-tree> </div> </div> <div class="right"> <properties :all-group="treeItemData"></properties> </div> </div> <div v-show="!isShowDebug" class="no-find"> <span>未发现cocos creator的游戏!</span> <el-button type="success" class="el-icon-refresh" @click="onBtnClickUpdatePage">刷新</el-button> </div> </div> </template> <script lang="ts"> import Vue from "vue"; import {Component} from "vue-property-decorator"; import properties from "./propertys.vue"; import {Msg, Page, PluginEvent} from "@/core/types" import {connectBackground} from "@/devtools/connectBackground"; import {EngineData, Info, TreeData, ObjectData, ObjectItemRequestData} from "@/devtools/data"; import Bus, {BusMsg} from "@/devtools/bus"; @Component({ components: { properties, } }) export default class Index extends Vue { private isShowDebug: boolean = false; treeItemData: Array<Record<string, any>> = []; treeData: Array<TreeData> = [] expandedKeys: Array<string> = []; selectedUUID: string | null = null; // el-tree的渲染key defaultProps = { children: "children", label: "name" }; private watchEveryTime: boolean = false;// 实时监控节点树 memory = { performance: {}, console: {}, } timerID: number = 0; private requestList: Array<{ id: string, cb: Function }> = []; created() { if (chrome && chrome.runtime) { this._initChromeRuntimeConnect(); } window.addEventListener("message", function (event) { console.log("on vue:" + JSON.stringify(event)); }, false); Bus.$on(BusMsg.ShowPlace, (data: EngineData) => { console.log(data) this._expand(data.engineUUID); }) Bus.$on(BusMsg.RequestObjectData, (data: ObjectData, cb: Function) => { if (this.requestList.find(el => el.id === data.id)) { return } this.requestList.push({id: data.id, cb}); this.sendMsgToContentScript(Msg.GetObjectItemData, data) }); } _expand(uuid: string) { let expandKeys: Array<string> = []; function circle(array: any) { for (let i = 0; i < array.length; i++) { let item = array[i]; expandKeys.push(item.uuid); if (item.uuid === uuid) { return true } else { let find = circle(item.children); if (find) { return true; } else { expandKeys.pop(); } } } } circle(this.treeData) expandKeys.forEach(key => { if (!this.expandedKeys.find(el => el === key)) { this.expandedKeys.push(key) } }) // 高亮uuid } renderContent(h: Function, options: any) { let {node, data, store} = options; return h("span", {class: ""}, data.name) // return(<span>1111</span>) } _onMsgListInfo(eventData: Array<TreeData>) { this.isShowDebug = true; if (!Array.isArray(eventData)) { eventData = [eventData] } this.treeData = eventData; if (this.selectedUUID) { this.$nextTick(() => { //@ts-ignore this.$refs.tree.setCurrentKey(this.selectedUUID); // todo 需要重新获取下node的数据 }) } } _onMsgNodeInfo(eventData: any) { this.isShowDebug = true; if (!Array.isArray(eventData)) { eventData = [eventData] } this.treeItemData = eventData; } _onMsgMemory(eventData: any) { this.memory = eventData; } _onMsgSupport(data: boolean) { this.isShowDebug = data; if (data) { // 如果节点树为空,就刷新一次 if (this.treeData.length === 0) { this.onBtnClickUpdateTree(); } } else { this._reset(); } } _reset() { this.treeData = []; this.treeItemData = []; } _initChromeRuntimeConnect() { // 接收来自background.js的消息数据 connectBackground.onBackgroundMessage((data: PluginEvent, sender: any) => { if (!data) { return; } if (data.target === Page.Devtools) { console.log("[Devtools]", data); PluginEvent.finish(data); let eventData: any = data.data; switch (data.msg) { case Msg.TreeInfo: { this._onMsgListInfo(eventData as Array<TreeData>); break; } case Msg.Support: { this._onMsgSupport(!!eventData) break; } case Msg.NodeInfo: { this._onMsgNodeInfo(eventData); break; } case Msg.MemoryInfo: { this._onMsgMemory(eventData) break; } case Msg.UpdateProperty: { this._updateProperty(eventData) break; } case Msg.TabsInfo: { debugger break } case Msg.GetObjectItemData: { let eventData: ObjectItemRequestData = data.data as ObjectItemRequestData; if (eventData.id !== null) { let findIndex = this.requestList.findIndex(el => el.id === eventData.id) if (findIndex > -1) { let del = this.requestList.splice(findIndex, 1)[0]; del.cb(eventData.data); } } break } } } }); } _updateProperty(data: Info) { const uuid = data.path[0]; const key = data.path[1]; const value = data.data; let treeArray: Array<TreeData> = []; function circle(array: Array<TreeData>) { array.forEach(item => { treeArray.push(item); circle(item.children); }) } // 更新指定uuid节点的tree的name circle(this.treeData) let ret = treeArray.find(el => el.uuid === uuid); if (ret) { if (key === "name") { ret.name = value; } if (key === "active") { ret.active = !!value; } } } handleNodeClick(data: TreeData) { this.selectedUUID = data.uuid; let uuid = data.uuid; if (uuid !== undefined) { this.sendMsgToContentScript(Msg.NodeInfo, uuid); } } onChangeWatchState() { if (this.watchEveryTime) { this.timerID = setInterval(() => { this.onBtnClickUpdateTree(); if (this.selectedUUID) { this.sendMsgToContentScript(Msg.NodeInfo, this.selectedUUID); } }, 300); } else { clearInterval(this.timerID); } } sendMsgToContentScript(msg: Msg, data?: any) { if (!chrome || !chrome.devtools) { console.log("环境异常,无法执行函数"); return; } connectBackground.postMessageToBackground(msg, data); } // 问题:没有上下文的权限,只能操作DOM _executeScript(para: Object) { let tabID = chrome.devtools.inspectedWindow.tabId; //@ts-ignore chrome.tabs.executeScript(tabID, {code: `var CCInspectorPara='${JSON.stringify(para)}';`}, () => { //@ts-ignore chrome.tabs.executeScript(tabID, {file: "js/execute.js"}) }); } _inspectedCode() { let injectCode = ""; chrome.devtools.inspectedWindow.eval(injectCode, (result, isException) => { if (isException) { console.error(isException); } else { console.log(`执行结果:${result}`) } }); } onBtnClickUpdateTree() { this.sendMsgToContentScript(Msg.TreeInfo); } onBtnClickUpdatePage() { this.sendMsgToContentScript(Msg.Support); } onMemoryTest() { this.sendMsgToContentScript(Msg.MemoryInfo); } onNodeExpand(data: TreeData) { if (data.hasOwnProperty("uuid") && data.uuid) { this.expandedKeys.push(data.uuid) } } onNodeCollapse(data: TreeData) { if (data.hasOwnProperty("uuid")) { let index = this.expandedKeys.findIndex(el => el === data.uuid); if (index !== -1) { this.expandedKeys.splice(index, 1) } } } } </script> <style scoped lang="less"> @import "../../index.less"; #devtools { display: flex; width: 100%; height: 100%; .no-find { display: flex; flex: 1; flex-direction: row; align-items: center; justify-content: center; span { margin-right: 20px; } } .find { display: flex; flex: 1; flex-direction: row; overflow: hidden; .left { display: flex; flex-direction: column; .tool-btn { display: flex; flex-direction: row; align-items: center; justify-content: center; } .treeList { margin-top: 3px; height: 100%; border-radius: 4px; min-height: 20px; overflow: auto; width: 300px; .leaf { width: 100%; } .leaf-show { color: black; } .leaf-hide { color: #c7bbbb; text-decoration: line-through; } &::-webkit-scrollbar { width: 6px; height: 6px; background: #999; border-radius: 2px; } &::-webkit-scrollbar-thumb { background-color: #333; border-radius: 2px; } } } .right { flex: 1; background: #e5e9f2; overflow-x: hidden; overflow-y: auto; &::-webkit-scrollbar { width: 0; background: #999; border-radius: 2px; height: 6px; } &::-webkit-scrollbar-thumb { background-color: #333; border-radius: 2px; } } } } </style>