import { CCString, Component, Enum, log, Node, _decorator } from "cc"; import { VMEnv } from "./VMEnv"; const { ccclass, property, executeInEditMode, menu, help } = _decorator; enum ACTION_MODE { SEARCH_COMPONENT, ENABLE_COMPONENT, REPLACE_WATCH_PATH, DELETE_COMPONENT } /** * 用于搜索的MV 组件列表,挂载在父节点后, * 会遍历搜索下面的所有MV组件, 并且显示其观察值的路径 */ @ccclass @executeInEditMode @menu('OopsFramework/Mvvm/Edit-Comps (快速组件操作)') @help('https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037632&doc_id=2873565') export default class MVCompsEdit extends Component { @property({ type: [CCString] }) findList: string[] = ["VMBase", "VMParent"]; @property({ type: Enum(ACTION_MODE) }) actionType: ACTION_MODE = ACTION_MODE.SEARCH_COMPONENT; @property({ tooltip: '勾选后,会自动查找 find list 中填写的组件', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.SEARCH_COMPONENT; } }) public get findTrigger() { return false; } public set findTrigger(v: boolean) { this.setComponents(0); } @property({ tooltip: '勾选后,会批量激活 find list 中填写的组件', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.ENABLE_COMPONENT; } }) public get enableTrigger() { return false; } public set enableTrigger(v: boolean) { this.setComponents(1); } @property({ tooltip: '勾选后,会批量关闭 find list 中填写的组件', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.ENABLE_COMPONENT; } }) public get disableTrigger() { return false; } public set disableTrigger(v: boolean) { this.setComponents(2); } @property({ tooltip: '允许删除节点的组件,确定需要移除请勾选,防止误操作', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.DELETE_COMPONENT; } }) allowDelete: boolean = false; @property({ tooltip: '勾选后,会批量删除 find list 中填写的组件', displayName: '[ X DELETE X ]', visible: function () { // @ts-ignore return this.allowDelete && this.actionType === ACTION_MODE.DELETE_COMPONENT; } }) public get deleteTrigger() { return false; } public set deleteTrigger(v: boolean) { this.setComponents(3); } @property({ tooltip: '勾选后,会批量替换掉指定的路径', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.REPLACE_WATCH_PATH; } }) public get replaceTrigger() { return false; } public set replaceTrigger(v: boolean) { this.setComponents(4); } @property({ tooltip: '匹配的路径,匹配规则: 搜索开头为 game的路径', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.REPLACE_WATCH_PATH; } }) targetPath: string = 'game'; @property({ tooltip: '替换的路径,将匹配到的路径替换', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.REPLACE_WATCH_PATH; } }) replacePath: string = '*'; @property({ tooltip: '是否搜集绑定VM组件的节点?', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.SEARCH_COMPONENT; } }) canCollectNodes: boolean = false; @property({ type: [Node], readonly: true, tooltip: '收集到绑定了VM组件相关的节点,可以自己跳转过去', visible: function () { // @ts-ignore return this.canCollectNodes && this.actionType === ACTION_MODE.SEARCH_COMPONENT } }) collectNodes: Node[] = []; onLoad() { if (VMEnv.editor) return; let path = this.getNodePath(this.node); console.error('you forget delete MVEditFinder,[path]', path); } setComponents(state: number) { let array = this.findList; let title = '搜索到当前节点下面的组件'; switch (state) { case 0: title = '搜索到当前节点下面的组件'; break; case 1: title = '激活以下节点的组件'; break; case 2: title = '关闭以下节点的组件'; break; case 3: title = '删除以下节点的组件'; break; case 4: title = '替换以下节点的路径'; break; default: break; } log(title) log('______________________') array.forEach(name => { this.searchComponent(name, state) }) log('______________________') } /** * * @param className * @param state 0-查找节点组件 1-激活节点组件 2-关闭节点组件 3-移除节点组件 */ searchComponent(className: string, state: number = 0) { /**收集节点清空 */ this.collectNodes = []; let comps = this.node.getComponentsInChildren(className); if (comps == null || comps.length < 1) return; log('[' + className + ']:'); comps.forEach((v: any) => { let ext = ''; if (state <= 3) { //区分模板模式路径 if (v.templateMode === true) { ext = v.watchPathArr ? ':[Path:' + v.watchPathArr.join('|') + ']' : '' } else { ext = v.watchPath ? ':[Path:' + v.watchPath + ']' : '' } } log(this.getNodePath(v.node) + ext); switch (state) { case 0://寻找组件 if (this.canCollectNodes) { if (this.collectNodes.indexOf(v.node) === -1) { this.collectNodes.push(v.node); } } break; case 1: // 激活组件 v.enabled = true; break; case 2: // 关闭组件 v.enabled = false; break; case 3: // 删除组件 v.node.removeComponent(v); break; case 4: // 替换指定路径 let targetPath = this.targetPath; let replacePath = this.replacePath; if (v.templateMode === true) { for (let i = 0; i < v.watchPathArr.length; i++) { const path = v.watchPathArr[i]; v.watchPathArr[i] = this.replaceNodePath(path, targetPath, replacePath); } } else { v.watchPath = this.replaceNodePath(v.watchPath, targetPath, replacePath); } default: break; } }); } replaceNodePath(path: string, search: string, replace: string) { let pathArr = path.split('.'); let searchArr = search.split('.'); let replaceArr = replace.split('.') let match = true; for (let i = 0; i < searchArr.length; i++) { //未匹配上 if (pathArr[i] !== searchArr[i]) { match = false; break; } } //匹配成功准备替换路径 if (match === true) { for (let i = 0; i < replaceArr.length; i++) { pathArr[i] = replaceArr[i]; } log(' 路径更新:', path, '>>>', pathArr.join('.')) } return pathArr.join('.'); } getNodePath(node: Node) { let parent = node; let array = []; while (parent) { let p = parent.getParent(); if (p) { array.push(parent.name); parent = p; } else { break; } } return array.reverse().join('/'); } }