🔄 模板变量

ThinkAdmin 提供完善的模板替换变量系统,支持多种路径类型的自动替换,简化模板开发。

📚 基础概念

什么是模板变量?

模板变量是在 HTML 模板文件中使用的特殊标记(如 __ROOT____APP__ 等),系统在渲染模板时会自动将这些标记替换为实际的路径或值。

简单理解:就像 Word 文档中的"占位符",系统会自动填充真实内容。

举个例子

<!-- 在模板中写 -->
<script src="__ROOT__/static/js/app.js"></script>

<!-- 系统自动替换为 -->
<script src="/static/js/app.js"></script>

为什么需要模板变量?

在 Web 开发中,我们经常需要在 HTML 中引用各种资源文件(CSS、JavaScript、图片等)。如果直接写死路径,会遇到很多问题:

问题1:硬编码路径难以维护

<!-- ❌ 不推荐:硬编码路径 -->
<script src="/static/js/app.js"></script>
<link rel="stylesheet" href="/static/css/admin.css">

如果网站部署到子目录(如 https://domain.com/project/),所有路径都需要修改。

问题2:不同环境路径不同

  • 开发环境:http://localhost/
  • 生产环境:https://domain.com/
  • 测试环境:https://test.domain.com/

使用模板变量后:

<!-- ✅ 推荐:使用模板变量 -->
<script src="__ROOT__/static/js/app.js"></script>
<link rel="stylesheet" href="__ROOT__/static/css/admin.css">

系统会根据当前环境自动替换为正确的路径。

模板变量的优势

  • 路径统一管理:所有路径通过变量统一管理,修改时只需改一处
  • 环境自动适配:不同环境(开发、生产)可以自动使用不同的路径
  • 代码更简洁:使用变量比硬编码路径更简洁易读
  • 易于维护:路径变更时无需修改所有模板文件

模板变量的工作流程

模板变量的替换过程是自动的,无需手动处理:

步骤1:在模板中使用变量

<!-- 模板文件:app/admin/view/index.html -->
<script src="__ROOT__/static/js/app.js"></script>

步骤2:系统解析模板时自动替换 ThinkAdmin 在渲染模板时,会自动识别 __ROOT__ 等变量,并根据当前环境替换为实际路径。

步骤3:输出最终 HTML

<!-- 最终输出给浏览器 -->
<script src="/static/js/app.js"></script>

技术细节

  • 替换发生在模板渲染阶段($this->fetch() 时)
  • 替换结果会被缓存,提升性能
  • 支持多种变量类型,满足不同场景需求

相关概念说明

模板(Template)

  • 用于显示页面的 HTML 文件
  • 位于 app/*/view/ 目录
  • 使用 ThinkPHP 模板引擎解析
  • 支持变量、循环、条件判断等语法

变量替换

  • 将模板中的变量标记替换为实际值的过程
  • 在模板渲染时自动完成
  • 支持缓存机制,提升性能

静态资源

  • CSS、JavaScript、图片等不需要服务器处理的文件
  • 通常存储在 public/static/ 目录
  • 通过 Web 服务器直接访问,不经过 PHP 处理

🚀 主要功能

  • 路径替换: 自动替换模板中的路径变量
  • 多类型支持: 支持动态路径、静态路径、应用路径等
  • 灵活配置: 支持自定义路径配置
  • 自动解析: 自动解析和替换路径变量
  • 第三方支持: 支持生成第三方资源链接
  • 开发简化: 简化模板开发中的路径处理

📋 变量类型

ThinkAdmin 提供了四种模板变量,用于不同场景的路径替换:

__APP__ - 动态路径

__APP__ 用于加载需要通过 PHP 处理的动态脚本文件,系统会自动替换为包含入口文件的完整路径。

什么是动态路径?

  • 动态路径包含入口文件(如 /index.php
  • 请求会经过 PHP 处理,可以执行权限验证、数据处理等
  • 适合加载需要服务器端处理的脚本

替换规则

<!-- 模板中 -->
<script src="__APP__/admin/api/data"></script>

<!-- 替换后 -->
<script src="/index.php/admin/api/data"></script>

使用场景

  1. 加载需要权限验证的 API 数据
<!-- 用户管理页面,加载用户列表(需要登录验证) -->
<script>
    $.get('__APP__/admin/user/list', function(data) {
        console.log(data);
    });
</script>
<!-- 替换后:$.get('/index.php/admin/user/list', ...) -->
  1. 加载动态生成的 JavaScript 配置
<!-- 页面初始化,加载系统配置 -->
<script src="__APP__/admin/config/js"></script>
<!-- 替换后:/index.php/admin/config/js -->
<!-- 这个接口会返回动态生成的 JavaScript 代码 -->
  1. AJAX 请求接口
<script>
    // 提交表单数据
    $.post('__APP__/admin/user/save', {
        name: '张三',
        email: 'zhangsan@example.com'
    }, function(result) {
        if (result.code === 1) {
            alert('保存成功');
        }
    });
</script>

技术细节

  • __APP__ 会替换为 /index.php(或配置的入口文件)
  • 请求会经过 ThinkPHP 路由系统
  • 支持权限验证、中间件等处理
  • 适合需要服务器端逻辑的场景

__ROOT__ - 静态路径

__ROOT__ 用于加载静态资源文件,系统会自动替换为网站根路径(不包含入口文件)。

什么是静态路径?

  • 静态路径不包含入口文件,直接指向资源文件
  • 请求不经过 PHP 处理,由 Web 服务器直接返回
  • 适合加载 CSS、JavaScript、图片等静态文件

替换规则

<!-- 模板中 -->
<link rel="stylesheet" href="__ROOT__/static/css/admin.css">

<!-- 替换后 -->
<link rel="stylesheet" href="/static/css/admin.css">

使用场景

  1. 加载 CSS 样式文件
<!-- 页面头部引入样式 -->
<head>
    <!-- 框架基础样式 -->
    <link rel="stylesheet" href="__ROOT__/static/plugs/admin/css/admin.css">
    
    <!-- 自定义样式 -->
    <link rel="stylesheet" href="__ROOT__/static/css/custom.css">
</head>
  1. 加载 JavaScript 文件
<!-- 页面底部引入脚本 -->
<script src="__ROOT__/static/plugs/admin/js/admin.js"></script>
<script src="__ROOT__/static/js/custom.js"></script>
  1. 加载图片资源
<!-- 显示图片 -->
<img src="__ROOT__/static/images/logo.png" alt="Logo">

<!-- 背景图片 -->
<div style="background-image: url(__ROOT__/static/images/bg.jpg);"></div>
  1. 完整的页面示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>后台管理</title>
    <!-- 使用 __ROOT__ 加载静态 CSS -->
    <link rel="stylesheet" href="__ROOT__/static/plugs/admin/css/admin.css">
</head>
<body>
    <div class="container">
        <h1>欢迎使用 ThinkAdmin</h1>
        <!-- 使用 __ROOT__ 加载图片 -->
        <img src="__ROOT__/static/images/logo.png" alt="Logo">
    </div>
    
    <!-- 使用 __ROOT__ 加载静态 JavaScript -->
    <script src="__ROOT__/static/plugs/admin/js/admin.js"></script>
</body>
</html>

技术细节

  • __ROOT__ 会替换为 /(网站根路径)
  • 请求直接由 Web 服务器(Nginx/Apache)处理
  • 不经过 PHP,性能更好
  • 适合静态资源文件(CSS、JS、图片等)

__PLUG__ - 应用路径

__PLUG__ 用于加载当前应用专属的静态资源,系统会自动替换为应用专属路径。

什么是应用路径?

  • 每个应用(如 adminindex)都有专属的资源目录
  • 资源存储在 public/static/extra/{应用名}/ 目录
  • 不同应用的资源互不干扰,便于管理

替换规则

<!-- 在 admin 应用的模板中 -->
<script src="__PLUG__/js/custom.js"></script>

<!-- 替换后 -->
<script src="/static/extra/admin/js/custom.js"></script>

目录结构说明

public/
  └── static/
      └── extra/
          ├── admin/          # admin 应用的专属资源
          │   ├── js/
          │   ├── css/
          │   └── images/
          └── index/          # index 应用的专属资源
              ├── js/
              └── css/

使用场景

  1. 加载应用专属的 JavaScript
<!-- admin 应用的用户管理页面 -->
<script src="__PLUG__/js/user-manage.js"></script>
<!-- 替换后:/static/extra/admin/js/user-manage.js -->

<!-- 这个文件只属于 admin 应用,其他应用不会加载 -->
  1. 加载应用专属的 CSS
<!-- admin 应用的自定义样式 -->
<link rel="stylesheet" href="__PLUG__/css/admin-custom.css">
<!-- 替换后:/static/extra/admin/css/admin-custom.css -->
  1. 加载应用专属的图片
<!-- admin 应用的专属图标 -->
<img src="__PLUG__/images/admin-icon.png" alt="Admin Icon">
<!-- 替换后:/static/extra/admin/images/admin-icon.png -->
  1. 多应用场景对比
<!-- admin 应用的模板 -->
<script src="__PLUG__/js/admin.js"></script>
<!-- 替换后:/static/extra/admin/js/admin.js -->

<!-- index 应用的模板 -->
<script src="__PLUG__/js/index.js"></script>
<!-- 替换后:/static/extra/index/js/index.js -->

技术细节

  • __PLUG__ 会根据当前应用名自动替换
  • admin 应用中,替换为 /static/extra/admin/
  • index 应用中,替换为 /static/extra/index/
  • 不同应用的资源完全隔离,避免冲突

__FULL__ - 完整路径

__FULL__ 用于生成完整的 URL 链接,包含协议(http/https)和域名,通常用于需要完整 URL 的场景。

什么是完整路径?

  • 完整路径包含:协议://域名/路径
  • 例如:https://www.example.com/static/images/logo.png
  • 适合需要完整 URL 的场景(如分享链接、API 回调等)

替换规则

<!-- 模板中 -->
<img src="__FULL__/static/images/logo.png" alt="Logo">

<!-- 替换后(假设域名是 https://v6.thinkadmin) -->
<img src="https://v6.thinkadmin/static/images/logo.png" alt="Logo">

使用场景

  1. 生成分享链接
<!-- 文章分享功能 -->
<a href="__FULL__/article/123" target="_blank">分享文章</a>
<!-- 替换后:https://v6.thinkadmin/article/123 -->

<!-- 微信分享需要完整 URL -->
<script>
    var shareUrl = '__FULL__/article/123';
    // 替换后:https://v6.thinkadmin/article/123
    // 可以用于微信分享、QQ 分享等
</script>
  1. 生成图片完整链接
<!-- 在邮件中嵌入图片 -->
<img src="__FULL__/static/images/logo.png" alt="Logo">
<!-- 替换后:https://v6.thinkadmin/static/images/logo.png -->

<!-- 用于二维码内容 -->
<div id="qrcode" data-url="__FULL__/article/123"></div>
  1. API 回调地址
<!-- 支付回调地址 -->
<form action="https://pay.example.com/pay">
    <input type="hidden" name="notify_url" value="__FULL__/api/payment/notify">
    <!-- 替换后:https://v6.thinkadmin/api/payment/notify -->
</form>
  1. 社交媒体分享
<!-- 分享到微博 -->
<a href="https://service.weibo.com/share/share.php?url=__FULL__/article/123" target="_blank">
    分享到微博
</a>

<!-- 分享到微信(需要生成二维码) -->
<script>
    var wechatUrl = '__FULL__/article/123';
    // 可以用于生成微信分享二维码
</script>

技术细节

  • __FULL__ 会根据当前请求自动获取协议和域名
  • HTTP 请求替换为 http://
  • HTTPS 请求替换为 https://
  • 域名从当前请求中自动获取
  • 适合需要完整 URL 的外部调用场景

🔧 工作原理

自动替换机制

模板变量的替换是在模板渲染时自动完成的,无需手动处理。

替换时机

  • 当调用 $this->fetch() 渲染模板时
  • ThinkPHP 模板引擎会自动识别变量标记
  • 根据当前环境自动替换为实际路径

替换过程

// 1. 控制器渲染模板
public function index()
{
    return $this->fetch();  // 触发模板渲染
}

// 2. 模板引擎解析
// 模板内容:<script src="__ROOT__/static/js/app.js"></script>

// 3. 自动替换变量
// 替换后:<script src="/static/js/app.js"></script>

// 4. 输出最终 HTML

性能优化

  • 替换结果会被缓存,避免重复计算
  • 缓存存储在 runtime/cache/ 目录
  • 修改模板后会自动更新缓存

路径生成规则

系统根据当前请求自动生成正确的路径:

__ROOT__ 生成规则

// 当前请求:https://www.example.com/admin/index
// __ROOT__ 替换为:/

__APP__ 生成规则

// 当前请求:https://www.example.com/admin/index
// __APP__ 替换为:/index.php
// 完整路径:/index.php/admin/index

__PLUG__ 生成规则

// 当前应用:admin
// __PLUG__ 替换为:/static/extra/admin/

__FULL__ 生成规则

// 当前请求:https://www.example.com/admin/index
// __FULL__ 替换为:https://www.example.com

环境适配

不同环境下,路径会自动适配:

开发环境

<!-- 模板中 -->
<script src="__FULL__/static/js/app.js"></script>

<!-- 开发环境替换后 -->
<script src="http://localhost/static/js/app.js"></script>

生产环境

<!-- 模板中 -->
<script src="__FULL__/static/js/app.js"></script>

<!-- 生产环境替换后 -->
<script src="https://www.example.com/static/js/app.js"></script>

子目录部署

<!-- 模板中 -->
<script src="__ROOT__/static/js/app.js"></script>

<!-- 部署在子目录:https://www.example.com/project/ -->
<!-- 替换后 -->
<script src="/project/static/js/app.js"></script>

💡 完整示例

在模板中使用

模板变量会在模板渲染时自动替换,无需额外处理:

<!DOCTYPE html>
<html>
<head>
    <!-- 使用 __ROOT__ 加载静态 CSS -->
    <link rel="stylesheet" href="__ROOT__/static/css/admin.css">
    
    <!-- 使用 __PLUG__ 加载应用专属 CSS -->
    <link rel="stylesheet" href="__PLUG__/css/custom.css">
</head>
<body>
    <!-- 使用 __FULL__ 生成完整图片链接 -->
    <img src="__FULL__/static/images/logo.png" alt="Logo">
    
    <!-- 使用 __APP__ 加载动态脚本 -->
    <script src="__APP__/admin/api/init"></script>
    
    <!-- 使用 __ROOT__ 加载静态 JavaScript -->
    <script src="__ROOT__/static/js/app.js"></script>
</body>
</html>

在控制器中获取路径

如果需要在控制器中获取替换后的路径,可以使用以下方法:

<?php
declare(strict_types=1);

namespace app\admin\controller;

use think\admin\Controller;

class Example extends Controller
{
    public function index()
    {
        // 获取动态路径
        $appUrl = $this->app->request->domain() . '/index.php';
        
        // 获取根路径
        $rootUrl = $this->app->request->domain();
        
        // 获取应用专属路径
        $plugUrl = $this->app->request->domain() . '/static/extra/' . $this->app->request->module();
        
        // 获取完整 URL
        $fullUrl = $this->app->request->domain() . '/static';
        
        // 传递给模板
        $this->assign([
            'appUrl' => $appUrl,
            'rootUrl' => $rootUrl,
            'plugUrl' => $plugUrl,
            'fullUrl' => $fullUrl,
        ]);
        
        return $this->fetch();
    }
}

在 PHP 代码中使用系统函数

ThinkAdmin 提供了 sysuri() 函数来获取路径:

<?php
// 获取动态路径(包含入口文件)
$appUrl = sysuri();
// 输出:/index.php

// 获取根路径
$rootUrl = sysuri('');
// 输出:/

// 获取完整 URL(包含协议和域名)
$fullUrl = sysuri('', true);
// 输出:https://domain.com

// 生成完整资源链接
$imageUrl = sysuri('/static/images/logo.png', true);
// 输出:https://domain.com/static/images/logo.png

⚠️ 注意事项

使用建议

选择合适的变量类型

  1. __APP__ - 动态路径

    • ✅ 适合:需要权限验证的 API 接口
    • ✅ 适合:动态生成的 JavaScript 配置
    • ✅ 适合:需要服务器端处理的请求
    • ❌ 不适合:静态资源文件(性能较差)
  2. __ROOT__ - 静态路径

    • ✅ 适合:CSS、JavaScript、图片等静态文件
    • ✅ 适合:框架提供的公共资源
    • ✅ 适合:所有应用共享的资源
    • ❌ 不适合:需要权限验证的资源
  3. __PLUG__ - 应用路径

    • ✅ 适合:应用专属的 CSS、JavaScript
    • ✅ 适合:应用特定的图片资源
    • ✅ 适合:需要隔离的应用资源
    • ❌ 不适合:多个应用共享的资源
  4. __FULL__ - 完整路径

    • ✅ 适合:分享链接、API 回调地址
    • ✅ 适合:邮件中嵌入的图片
    • ✅ 适合:需要完整 URL 的外部调用
    • ❌ 不适合:页面内部的资源引用(性能较差)

常见错误

错误1:在静态资源中使用 __APP__

<!-- ❌ 错误:静态文件不需要经过 PHP -->
<script src="__APP__/static/js/app.js"></script>

<!-- ✅ 正确:使用 __ROOT__ -->
<script src="__ROOT__/static/js/app.js"></script>

错误2:在页面内部使用 __FULL__

<!-- ❌ 错误:页面内部不需要完整 URL -->
<link rel="stylesheet" href="__FULL__/static/css/admin.css">

<!-- ✅ 正确:使用 __ROOT__ -->
<link rel="stylesheet" href="__ROOT__/static/css/admin.css">

错误3:跨应用使用 __PLUG__

<!-- ❌ 错误:在 admin 应用中引用 index 应用的资源 -->
<script src="__PLUG__/js/index.js"></script>
<!-- 会替换为:/static/extra/admin/js/index.js(错误) -->

<!-- ✅ 正确:使用 __ROOT__ 引用公共资源 -->
<script src="__ROOT__/static/js/index.js"></script>

性能优化

缓存机制

  • 变量替换结果会被缓存到 runtime/cache/ 目录
  • 首次访问时替换并缓存,后续直接使用缓存
  • 修改模板后会自动更新缓存

CDN 支持

  • 可以通过配置将静态资源指向 CDN
  • 提升静态资源的加载速度
  • 减少服务器带宽压力

最佳实践

  • 静态资源优先使用 __ROOT__(性能最好)
  • 动态请求使用 __APP__(功能完整)
  • 应用专属资源使用 __PLUG__(隔离清晰)
  • 外部调用使用 __FULL__(完整 URL)
最近更新:
Contributors: 邹景立, Anyon