# mm_tpl

超级美眉模板引擎模块，基于art-template模板引擎，提供强大的MVC模式视图渲染功能，支持钩子系统、主题切换和缓存机制。

[English Documentation](README_EN.md) | [中文文档](README.md)

## 目录

- [特性](#特性)
- [安装](#安装)
- [快速开始](#快速开始)
- [高级特性](#高级特性)
- [API 参考](#api-参考)
- [注意事项](#注意事项)
- [开发](#开发)
- [许可证](#许可证)

## 特性

- 🚀 基于art-template高性能模板引擎
- 🔧 支持多种模板语法规则
- 🎨 主题切换和模板文件优先级搜索
- ⚡ 内置缓存机制提升性能
- 🔌 强大的钩子系统支持
- 📁 灵活的目录结构支持
- 🛡️ 完善的错误处理机制

## 安装

```bash
npm install mm_tpl
```

## 快速开始

### 1. 安装依赖

```bash
npm install mm_tpl
```

### 2. 初始化模板引擎

```javascript
const {Tpl} = require('mm_tpl');

// 创建模板实例
const tpl = new Tpl({
    root: process.cwd(),           // 根目录
    default_dir: "./template/",    // 默认模板目录
    default_theme: 'default',      // 默认主题
    extname: ".html",             // 模板文件扩展名
    cache_root: './cache',        // 缓存目录
    cache_extname: '.cache.html', // 缓存文件扩展名
    rules: [nativeRule, artRule, htmlRule, jsRule, pyRule, pyRule2] // 模板规则
});
```

### 3. 基础模板渲染

```javascript
// 简单变量替换
const result = tpl.render("<div>${message}</div>", {
    message: "Hello World"
});
// 输出: <div>Hello World</div>

// 编译模板函数
const compiled = tpl.compile("<div>${name} - ${age}</div>");
const result2 = compiled({ name: "张三", age: 25 });
// 输出: <div>张三 - 25</div>
```

### 4. 循环渲染

```javascript
// 数组循环
const arrayResult = tpl.render(`
    <ul>
        ${loop arr value idx}
            <li>${idx}: ${value}</li>
        ${/loop}
    </ul>
`, { 
    arr: [123, 234] 
});

// 对象循环
const objectResult = tpl.render(`
    <dl>
        ${loop obj value key}
            <dt>${key}</dt>
            <dd>${value}</dd>
        ${/loop}
    </dl>
`, { 
    obj: { name: "张三", age: 25 } 
});

// 传统for循环
const forResult = tpl.render(`
    <ul>
        <!--[ for(var i = 0; i < arr.length; i++){ ]-->
            <li>${arr[i]}</li>
        <!--[ } ]-->
    </ul>
`, {
    arr: [123, 234]
});

// each循环
const eachResult = tpl.render(`
    <ul>
        ${each arr}
            <li>${$value}</li>
        ${/each}
    </ul>
`, {
    arr: [123, 234]
});
// 输出: 
// <ul>
//     <li>123</li>
//     <li>234</li>
// </ul>
```

### 5. 视图渲染

```javascript
// 设置全局变量
$.globalBag.siteName = "我的网站";

// 设置视图变量
tpl.set({
    title: "首页",
    keywords: "关键词"
});

// 渲染视图文件
const html = tpl.view("./views/index.html", {
    user: { name: "张三" }
});
// 输出: 渲染结果 <div>Hello World</div>

// 获取视图变量
const title = tpl.get("title");

// 删除视图变量
tpl.del("keywords");
```

### 6. 缓存机制

```javascript
// 使用缓存渲染视图
const html = tpl.view("./views/page", {
    data: someData
}, {
    cache: true,                // 是否使用缓存
    cache_filename: "./cache"   // 缓存文件名
});

// 清除缓存
tpl.clearCache('./views/mall'); // 清除指定目录缓存
// 或
tpl.clearCache(); // 清除所有缓存
```

### 7. 钩子系统

#### 添加函数钩子
```javascript
$.hook.addFunc('list', async function(viewBag, req, type) {
    // 处理列表逻辑
    var query = req.query;
    if (query.user_id) {
        viewBag.user_id = query.user_id;
    }
    return someData;
}, 100, 'listFunc'); // sort: 优先级, alias: 别名
```

#### 添加动作钩子
```javascript
$.hook.addAction('header', function(viewBag, param) {
    return "<header>网站头部</header>";
}, 1, "headerAction");
```

#### 添加过滤器钩子
```javascript
$.hook.addFilter('content', function(viewBag, content, param) {
    return content.replace("旧文本", "新文本");
}, 1, "contentFilter");
```

#### 执行钩子
```javascript
// 执行函数钩子
const result = await tpl.runFunc('list', { query: { page: 1 } }, 'article');

// 执行动作钩子
const actionResult = tpl.runHook('header', { param: 'value' });

// 在模板中使用钩子
const html = tpl.render(`
    <div>
        ${hookAction('header')}
        ${hookFilter('content', '原始内容')}
    </div>
`, data);
```

#### 删除钩子
```javascript
// 删除指定钩子
$.hook.delFunc('list', 'listFunc');
$.hook.delAction('header', 'headerAction');
$.hook.delFilter('content', 'contentFilter');

// 清空所有钩子
$.hook.clear();
```

## 高级特性

### 1. 主题和目录支持
```javascript
// 设置当前主题
tpl.current_theme = "dark";

// 模板文件查找顺序（优先级从高到低）：
// 1. diy目录（自定义目录）
// 2. 当前主题目录
// 3. 默认主题目录
```

### 2. 模板规则
模块内置支持多种模板规则，包括：
- nativeRule: 原生语法规则
- artRule: art-template语法规则
- htmlRule: HTML注释语法规则
- jsRule: JavaScript语法规则
- pyRule: Python风格语法规则

### 3. 错误处理
```javascript
const html = tpl.view("./template.html", data);
if (tpl.error) {
    console.error("渲染错误:", tpl.error);
}
```

### 4. 字符转义
```javascript
// 自动转义特殊字符
const escaped = tpl.escape("<div>${content}</div>");
// 输出: <div>·$·{content}</div>

// 还原转义字符
const restored = tpl.escape(escaped, true);
// 输出: <div>${content}</div>
```

### 5. 全局挂载
```javascript
// 自动挂载到全局对象
if (global.$ && !$.Tpl) {
    $.Tpl = Tpl;
    $.tpl = new Tpl();
}
```

## API 参考

### Tpl 类方法

- `constructor(config)` - 构造函数，创建模板实例
- `setConfig(config)` - 设置配置参数
- `render(body, model, options)` - 渲染模板字符串
- `compile(body, options)` - 编译模板为函数
- `view(file, model, options)` - 渲染模板文件
- `set(obj)` - 设置视图数据
- `get(key)` - 获取视图数据
- `del(keys)` - 删除视图数据
- `clearCache(path, file)` - 清除缓存
- `runFunc(name, req, ...args)` - 执行函数钩子
- `runHook(name, req, ...args)` - 执行动作钩子（runFunc别名）
- `escape(body, restore)` - 转义/还原字符

### Hook 类方法

- `addFunc(name, func, sort, alias)` - 添加函数钩子
- `addAction(name, func, sort, alias)` - 添加动作钩子
- `addFilter(name, func, sort, alias)` - 添加过滤器钩子
- `runFunc(name, model, req, ...args)` - 执行函数钩子
- `runAction(name, model, ...args)` - 执行动作钩子
- `runFilter(name, model, ret, ...args)` - 执行过滤器钩子
- `delFunc(name, alias)` - 删除函数钩子
- `delAction(name, alias)` - 删除动作钩子
- `delFilter(name, alias)` - 删除过滤器钩子
- `clear(name)` - 清空钩子

## 注意事项

1. **依赖要求**: 需要安装 `art-template` 和 `mm_expand` 依赖包
2. **目录权限**: 确保模板目录具有读写权限
3. **缓存管理**: 及时清理过期缓存，避免内存泄漏
4. **钩子优先级**: 数值越小优先级越高，执行顺序越靠前
5. **异步处理**: 钩子函数支持异步操作，注意错误处理
6. **文件查找**: 模板文件按优先级顺序查找，确保文件存在
7. **字符转义**: 自动处理模板语法字符，避免冲突

## 开发

```bash
# 运行测试
npm test

# 查看代码覆盖率
npm run coverage
```

## 许可证

MIT License