mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-06-23 19:22:47 +08:00
2. 存储模块性能提升,添加LRU缓存、批量操作支持,优化内存使用 3. 多语言模块性能与内存管理优化,组件查询性能提升 4. 时间模块类型安全与性能优化,使用泛型替代any,对象池机制减少内存分配 5. 事件系统修复双重注册、重复注册等严重问题,实现EventData对象池减少GC压力 6. RandomManager修复4个逻辑BUG,包括边界问题和越界问题 7. 音频模块内存与性能优化,避免重复加载,优化数据结构,添加完整清理机制 8. CCView与CCViewVM合并,支持按需启用MVVM 9. Collection模块优化,AsyncQueue添加队列容量限制,Collection查询性能提升 10. ECS系统全面优化,对象池复用减少内存分配,循环性能提升 11. 优化MVVM组件性能
217 lines
6.6 KiB
TypeScript
217 lines
6.6 KiB
TypeScript
import type { Node } from 'cc';
|
||
import { _decorator, CCString, error } from 'cc';
|
||
import { StringFormatFunction } from './StringFormat';
|
||
import { VMBase } from './VMBase';
|
||
import { VMEnv } from './VMEnv';
|
||
|
||
const { ccclass, property, menu, executeInEditMode, help } = _decorator;
|
||
|
||
const LABEL_TYPE = {
|
||
CC_LABEL: 'cc.Label',
|
||
CC_RICH_TEXT: 'cc.RichText',
|
||
CC_EDIT_BOX: 'cc.EditBox'
|
||
};
|
||
|
||
// 缓存正则表达式,避免重复创建
|
||
const REGEX_ALL = /\{\{(.+?)\}\}/g; // 匹配: 所有的{{value}}
|
||
const REGEX_SINGLE = /\{\{(.+?)\}\}/; // 匹配: {{value}} 中的 value
|
||
|
||
/**
|
||
* [VM-Label]
|
||
* 专门处理 Label 相关 的组件,如 ccLabel,ccRichText,ccEditBox
|
||
* 可以使用模板化的方式将数据写入,可以处理字符串格式等
|
||
* todo 加入stringFormat 可以解析转换常见的字符串格式
|
||
*/
|
||
@ccclass
|
||
@executeInEditMode
|
||
@menu('OopsFramework/Mvvm/VM-Label (标签)')
|
||
@help('https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037641&doc_id=2873565')
|
||
export default class VMLabel extends VMBase {
|
||
/**
|
||
* 动态绑定组件
|
||
* @param node 目标节点
|
||
* @param watchPath 监听数据路径
|
||
*/
|
||
static bind(node: Node, watchPath: string | string[]) {
|
||
const label = node.addComponent(VMLabel);
|
||
if (watchPath instanceof Array) {
|
||
label.templateMode = true;
|
||
label.watchPathArr = watchPath;
|
||
}
|
||
else {
|
||
label.watchPath = watchPath;
|
||
}
|
||
}
|
||
|
||
@property({
|
||
tooltip: '是否启用模板代码,只能在运行时之前设置,\n将会动态解析模板语法 {{0}},并且自动设置监听的路径'
|
||
})
|
||
templateMode = false;
|
||
|
||
@property({
|
||
visible() {
|
||
// @ts-ignore
|
||
return this.templateMode === false;
|
||
}
|
||
})
|
||
watchPath = '';
|
||
|
||
@property({
|
||
readonly: true
|
||
})
|
||
protected labelType: string = LABEL_TYPE.CC_LABEL;
|
||
|
||
@property({
|
||
type: [CCString],
|
||
visible() {
|
||
// @ts-ignore
|
||
return this.templateMode === true;
|
||
}
|
||
})
|
||
/** 按照匹配参数顺序保存的 path 数组 (固定) */
|
||
protected watchPathArr: string[] = [];
|
||
|
||
/** 按照路径参数顺序保存的 值的数组(固定)*/
|
||
protected templateValueArr: any[] = [];
|
||
|
||
/** 保存着字符模板格式的数组 (只会影响显示参数) */
|
||
private templateFormatArr: string[] = [];
|
||
|
||
/** 源字符串 */
|
||
protected originText: string | null = null;
|
||
|
||
onRestore() {
|
||
this.checkLabel();
|
||
}
|
||
|
||
onLoad() {
|
||
super.onLoad();
|
||
this.checkLabel();
|
||
|
||
if (VMEnv.editor) return;
|
||
|
||
if (this.templateMode) {
|
||
this.originText = this.getLabelValue();
|
||
this.parseTemplate();
|
||
}
|
||
}
|
||
|
||
start() {
|
||
if (VMEnv.editor) return;
|
||
|
||
this.onValueInit();
|
||
}
|
||
|
||
/** 解析模板 获取初始格式化字符串格式的信息 */
|
||
parseTemplate() {
|
||
const res = this.originText!.match(REGEX_ALL); // 匹配结果数组
|
||
if (res == null) return;
|
||
for (let i = 0; i < res.length; i++) {
|
||
const e = res[i];
|
||
const arr = e.match(REGEX_SINGLE);
|
||
const matchName = arr![1];
|
||
// let paramIndex = parseInt(matchName) || 0;
|
||
const matchInfo = matchName.split(':')[1] || '';
|
||
this.templateFormatArr[i] = matchInfo;
|
||
}
|
||
}
|
||
|
||
/** 获取解析字符串模板后得到的值 */
|
||
getReplaceText() {
|
||
if (!this.originText) return '';
|
||
const res = this.originText.match(REGEX_ALL); // 匹配结果数组 [{{value}},{{value}},{{value}}]
|
||
if (res == null) return ''; // 未匹配到文本
|
||
let str = this.originText; // 原始字符串模板 "name:{{0}} 或 name:{{0:fix2}}"
|
||
|
||
for (let i = 0; i < res.length; i++) {
|
||
const e = res[i];
|
||
const arr = e.match(REGEX_SINGLE); // 匹配到的数组 [{{value}}, value]
|
||
const indexNum = parseInt(arr![1] || '0') || 0; // 取出数组的 value 元素 转换成整数
|
||
const format = this.templateFormatArr[i]; // 格式化字符 的 配置参数
|
||
const getValue = this.templateValueArr[indexNum];
|
||
str = str.replace(e, this.getValueFromFormat(getValue, format));//从路径缓存值获取数据
|
||
}
|
||
return str;
|
||
}
|
||
|
||
/** 格式化字符串 */
|
||
getValueFromFormat(value: number | string, format: string): string {
|
||
return StringFormatFunction.deal(value, format);
|
||
}
|
||
|
||
/** 初始化获取数据 */
|
||
onValueInit() {
|
||
//更新信息
|
||
if (this.templateMode === false) {
|
||
this.setLabelValue(this.VM.getValue(this.watchPath)); //
|
||
}
|
||
else {
|
||
const max = this.watchPathArr.length;
|
||
for (let i = 0; i < max; i++) {
|
||
this.templateValueArr[i] = this.VM.getValue(this.watchPathArr[i], '?');
|
||
}
|
||
this.setLabelValue(this.getReplaceText()); // 重新解析
|
||
}
|
||
}
|
||
|
||
/** 监听数据发生了变动的情况 */
|
||
onValueChanged(n: any, o: any, pathArr: string[]) {
|
||
if (this.templateMode === false) {
|
||
this.setLabelValue(n);
|
||
}
|
||
else {
|
||
const path = pathArr.join('.');
|
||
// 寻找缓存位置
|
||
const index = this.watchPathArr.findIndex((v) => v === path);
|
||
|
||
if (index >= 0) {
|
||
//如果是所属的路径,就可以替换文本了
|
||
this.templateValueArr[index] = n; // 缓存值
|
||
this.setLabelValue(this.getReplaceText()); // 重新解析文本
|
||
}
|
||
}
|
||
}
|
||
|
||
setLabelValue(value: string) {
|
||
const component: any = this.getComponent(this.labelType);
|
||
component.string = value + '';
|
||
}
|
||
|
||
getLabelValue(): string {
|
||
const component: any = this.getComponent(this.labelType);
|
||
return component.string;
|
||
}
|
||
|
||
private checkLabel() {
|
||
const checkArray = [
|
||
'cc.Label',
|
||
'cc.RichText',
|
||
'cc.EditBox',
|
||
];
|
||
|
||
for (let i = 0; i < checkArray.length; i++) {
|
||
const e = checkArray[i];
|
||
const comp = this.node.getComponent(e);
|
||
if (comp) {
|
||
this.labelType = e;
|
||
return true;
|
||
}
|
||
}
|
||
|
||
error('没有挂载任何label组件');
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 组件销毁时清理内存
|
||
*/
|
||
onDestroy() {
|
||
// 清理数组引用
|
||
this.watchPathArr.length = 0;
|
||
this.templateValueArr.length = 0;
|
||
this.templateFormatArr.length = 0;
|
||
this.originText = null;
|
||
}
|
||
}
|