import { _decorator, CCString, Component, Enum, log, Node } 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 VMCompsEdit 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; } }) get findTrigger() { return false; } set findTrigger(v: boolean) { this.setComponents(0); } @property({ tooltip: '勾选后,会批量激活 find list 中填写的组件', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.ENABLE_COMPONENT; } }) get enableTrigger() { return false; } set enableTrigger(v: boolean) { this.setComponents(1); } @property({ tooltip: '勾选后,会批量关闭 find list 中填写的组件', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.ENABLE_COMPONENT; } }) get disableTrigger() { return false; } set disableTrigger(v: boolean) { this.setComponents(2); } @property({ tooltip: '允许删除节点的组件,确定需要移除请勾选,防止误操作', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.DELETE_COMPONENT; } }) allowDelete = false; @property({ tooltip: '勾选后,会批量删除 find list 中填写的组件', displayName: '[ X DELETE X ]', visible: function () { // @ts-ignore return this.allowDelete && this.actionType === ACTION_MODE.DELETE_COMPONENT; } }) get deleteTrigger() { return false; } set deleteTrigger(v: boolean) { this.setComponents(3); } @property({ tooltip: '勾选后,会批量替换掉指定的路径', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.REPLACE_WATCH_PATH; } }) get replaceTrigger() { return false; } set replaceTrigger(v: boolean) { this.setComponents(4); } @property({ tooltip: '匹配的路径,匹配规则: 搜索开头为 game的路径', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.REPLACE_WATCH_PATH; } }) targetPath = 'game'; @property({ tooltip: '替换的路径,将匹配到的路径替换', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.REPLACE_WATCH_PATH; } }) replacePath = '*'; @property({ tooltip: '是否搜集绑定VM组件的节点?', visible: function () { // @ts-ignore return this.actionType === ACTION_MODE.SEARCH_COMPONENT; } }) canCollectNodes = 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; const path = this.getNodePath(this.node); console.error('you forget delete MVEditFinder,[path]', path); } setComponents(state: number) { const 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 = 0) { /**收集节点清空 */ this.collectNodes = []; const 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: // 替换指定路径 const targetPath = this.targetPath; const 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) { const pathArr = path.split('.'); const searchArr = search.split('.'); const 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; const array: string[] = []; while (parent) { const p = parent.getParent(); if (p) { array.push(parent.name); parent = p; } else { break; } } return array.reverse().join('/'); } }