yangweijie/think-stempler

Stempler Template Engine Driver for ThinkPHP 8.0

v0.9.0 2025-06-26 13:02 UTC

This package is auto-updated.

Last update: 2025-06-29 15:42:48 UTC


README

基于 Spiral Stempler 核心功能的 ThinkPHP 模板引擎扩展,提供现代化的模板特性。

🚀 特性

✅ 完全实现的功能

  • 基本语法: 变量输出、转义控制、注释
  • 指令系统: 条件、循环、判断、工具指令
  • 布局继承: 完整的模板继承系统
  • 栈系统: 强大的内容栈管理
  • 组件系统: 可复用的 UI 组件
  • ThinkPHP 集成: 完全兼容 ThinkPHP 框架

🎯 性能表现

  • 渲染速度: 平均 1-2ms
  • 内存使用: 优化的临时文件执行
  • 安全性: 移除 eval,使用安全的文件执行
  • 缓存机制: 智能的编译缓存

📦 安装

composer require yangweijie/think-stempler

🔧 配置

在 ThinkPHP 配置文件中添加:

// config/view.php
return [
    'type' => 'Stempler',
    'view_path' => app()->getRootPath() . 'view' . DIRECTORY_SEPARATOR,
    'cache_path' => app()->getRuntimePath() . 'temp' . DIRECTORY_SEPARATOR,
    'view_suffix' => '.dark.php',
    'tpl_cache' => true,
    
    // Stempler 特性开关
    'enable_layout' => true,
    'enable_stack' => true,
    'enable_component' => true,
];

📖 基本语法

变量输出

<!-- 自动转义输出 -->
<h1>{{ $title }}</h1>
<p>用户: {{ $user ?? '访客' }}</p>

<!-- 原始输出(不转义) -->
<div>{!! $htmlContent !!}</div>

<!-- 转义 @ 符号 -->
<p>邮箱格式: user@@domain.com</p>

条件指令

@if($user)
    <p>欢迎,{{ $user->name }}!</p>
@elseif($guest)
    <p>欢迎,访客!</p>
@else
    <p>请登录</p>
@endif

@unless($errors)
    <p>操作成功</p>
@endunless

@empty($items)
    <p>暂无数据</p>
@endempty

@isset($user->email)
    <p>邮箱: {{ $user->email }}</p>
@endisset

循环指令

@foreach($users as $user)
    <div class="user">
        <h3>{{ $user->name }}</h3>
        <p>{{ $user->email }}</p>
    </div>
@endforeach

@for($i = 1; $i <= 10; $i++)
    <span>{{ $i }}</span>
@endfor

@while($condition)
    <!-- 循环内容 -->
    @break
    @continue
@endwhile

选择指令

@switch($status)
    @case('active')
        <span class="badge badge-success">活跃</span>
        @break
    @case('inactive')
        <span class="badge badge-warning">非活跃</span>
        @break
    @default
        <span class="badge badge-secondary">未知</span>
@endswitch

工具指令

<!-- JSON 输出 -->
<script>
    var config = @json($config);
    var users = @json($users);
</script>

<!-- PHP 代码 -->
@php
    $computed = $price * $quantity;
    $total = number_format($computed, 2);
@endphp
<p>总计: {{ $total }}</p>

🏗️ 布局继承

定义布局

<!-- layout/base.dark.php -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title><block:title>默认标题</block:title></title>
    <block:head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </block:head>
</head>
<body>
    <header>
        <h1>网站头部</h1>
        <nav><block:nav>默认导航</block:nav></nav>
    </header>
    
    <main>
        <block:content>
            <p>默认内容</p>
        </block:content>
    </main>
    
    <footer>
        <p>网站底部</p>
    </footer>
</body>
</html>

继承布局

<!-- page/index.dark.php -->
<extends:layout.base/>

<block:title>首页 - 我的网站</block:title>

<block:head>
    <block:parent/>
    <link rel="stylesheet" href="/css/home.css">
</block:head>

<block:nav>
    <a href="/">首页</a>
    <a href="/about">关于</a>
    <a href="/contact">联系</a>
</block:nav>

<block:content>
    <h2>欢迎来到首页</h2>
    <p>这是首页内容</p>
</block:content>

📚 栈系统

栈系统允许你在模板的任何地方推送内容,然后在指定位置收集和渲染。

收集栈内容

<!-- 在布局中定义栈收集点 -->
<head>
    <stack:collect name="styles">
        <link rel="stylesheet" href="/css/app.css">
    </stack:collect>
</head>

<body>
    <!-- 页面内容 -->
    
    <stack:collect name="scripts">
        <script src="/js/app.js"></script>
    </stack:collect>
</body>

推送到栈

<!-- 在任何模板中推送内容 -->
<stack:push name="styles">
    <link rel="stylesheet" href="/css/page.css">
</stack:push>

<stack:prepend name="styles">
    <link rel="stylesheet" href="/css/reset.css">
</stack:prepend>

<stack:push name="scripts">
    <script src="/js/page.js"></script>
</stack:push>

渲染顺序

  • <stack:prepend>: 添加到栈顶(最先渲染)
  • 默认内容: 中间渲染
  • <stack:push>: 添加到栈底(最后渲染)

🧩 组件系统

内置组件

Alert 组件

<ui:alert type="success" message="操作成功!"/>
<ui:alert type="error" message="操作失败!"/>
<ui:alert type="warning" message="请注意!"/>

Card 组件

<ui:card title="用户信息" class="user-card">
    <p>姓名: {{ $user->name }}</p>
    <p>邮箱: {{ $user->email }}</p>
</ui:card>

Button 组件

<ui:button type="submit" class="btn btn-primary" onclick="submitForm()">
    提交
</ui:button>

Input 组件

<ui:input type="text" name="username" placeholder="请输入用户名" class="form-control"/>
<ui:input type="email" name="email" value="{{ $user->email }}" class="form-control"/>

Modal 组件

<ui:modal id="userModal" title="编辑用户" size="lg">
    <form>
        <div class="form-group">
            <label>用户名:</label>
            <ui:input type="text" name="username" class="form-control"/>
        </div>
        <div class="form-actions">
            <ui:button type="submit" class="btn btn-primary">保存</ui:button>
        </div>
    </form>
</ui:modal>

Table 组件

<ui:table striped bordered class="data-table">
    <thead>
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>邮箱</th>
        </tr>
    </thead>
    <tbody>
        @foreach($users as $user)
            <tr>
                <td>{{ $user->id }}</td>
                <td>{{ $user->name }}</td>
                <td>{{ $user->email }}</td>
            </tr>
        @endforeach
    </tbody>
</ui:table>

自定义组件

你可以注册自定义组件:

// 在控制器或服务中
$engine = app('view')->getEngine();
$engine->registerComponent('my-component', function($attributes, $content) {
    return "<div class='my-component'>{$content}</div>";
});

🎮 控制器使用

基本使用

<?php
namespace app\controller;

use think\Controller;

class Index extends Controller
{
    public function index()
    {
        $data = [
            'title' => '首页',
            'users' => [
                ['name' => '张三', 'email' => 'zhangsan@example.com'],
                ['name' => '李四', 'email' => 'lisi@example.com'],
            ]
        ];
        
        return view('index', $data);
    }
}

使用布局

public function profile()
{
    $user = $this->getUser();
    
    return view('user/profile', [
        'user' => $user,
        'pageTitle' => '个人资料',
        'breadcrumbs' => ['首页', '用户中心', '个人资料']
    ]);
}

🔧 高级配置

组件路径

// config/view.php
return [
    'type' => 'Stempler',
    'component_path' => app()->getRootPath() . 'view/components/',
    // 其他配置...
];

功能开关

// 禁用某些功能
return [
    'type' => 'Stempler',
    'enable_layout' => true,   // 布局继承
    'enable_stack' => true,    // 栈系统
    'enable_component' => false, // 组件系统(如果不需要)
];

🚀 性能优化

启用缓存

return [
    'type' => 'Stempler',
    'tpl_cache' => true,
    'cache_path' => app()->getRuntimePath() . 'temp/',
];

生产环境优化

return [
    'type' => 'Stempler',
    'tpl_cache' => true,
    'view_debug' => false,
    'strip_space' => true, // 移除多余空白
];

🐛 调试

启用调试模式

return [
    'type' => 'Stempler',
    'view_debug' => true,
];

查看编译后的代码

$engine = app('view')->getEngine();
$compiled = $engine->compile($templateContent, $templateFile);
echo $compiled;

📝 更新日志

v2.0.0 (2024-06-26)

  • 🎉 完全重构,基于 Spiral Stempler 设计理念
  • ✨ 新增布局继承系统
  • ✨ 新增栈系统
  • ✨ 新增组件系统
  • 🚀 性能大幅提升
  • 🔒 安全性增强
  • 📚 完善的文档

📄 许可证

MIT License

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📞 支持

如有问题,请提交 Issue 或联系维护者。