首页 » 资讯中心 » 文档

ThinkTemplate SSR 数据渲染指南

文档 作者:求元工坊 发布时间:2026-10-16 阅读:36

求元工坊CMS 基于 ThinkPHP6 + ThinkTemplate 模板引擎,采用服务端渲染(SSR)模式。本文档面向前端模板开发者,介绍在模板中如何调用和渲染数据。

一、全局变量标签

以下变量在 GlobalView 中间件中自动注入到所有前台模板,所有页面均可直接调用:

变量含义示例
{$web.site_name}站点名称<span class="cn">{$web.site_name}</span>
{$web.site_description}站点简介{$web.site_description}
{$web.contact_email}联系邮箱{$web.contact_email}
{$web.contact_phone}联系电话{$web.contact_phone}
{$web.site_copyright}版权信息{$web.site_copyright}
{$web.site_beian}备案号{$web.site_beian}
{$siteWww}站点根地址<link href="{$siteWww}/static/home/css/cms.css">
{$navList}栏目导航树{volist name="navList" id="nav"}

二、循环标签 volist

volist 是 ThinkTemplate 的核心循环标签,用于遍历控制器传递的数组数据。

2.1 基本语法

{volist name="list" id="item" key="k"}
  <li>
    <a href="{$siteWww}/article/{$item.id}.html">{$item.title}</a>
    <span>{$item.created_at_fmt}</span>
  </li>
{/volist}

属性说明:

  1. name="list" — 控制器传递的变量名(必须)
  2. id="item" — 循环体中单条数据的别名(必须)
  3. key="k" — 自增序号(从1开始,可选)
  4. offset="0" — 从第几条开始(可选)
  5. length="10" — 最多输出几条(可选)

2.2 文档列表调用示例

<div class="doc-list">
{volist name="list" id="item"}
  <div class="doc-item">
    <h3><a href="{$siteWww}/article/{$item.id}.html">{$item.title}</a></h3>
    <p>{$item.summary}</p>
    <div class="meta">
      <span>{$item.author}</span>
      <span>{$item.views} 次阅读</span>
      <span>{$item.publishing_time}</span>
    </div>
  </div>
{/volist}
</div>

注解:遍历文档列表,输出标题、摘要、作者、浏览量和发布时间。

2.3 客户案例列表调用示例

<div class="case-grid">
{volist name="list" id="item"}
  <div class="case-card">
    <img src="{$item.cover}" alt="{$item.title}">
    <h4>{$item.title}</h4>
    <p>{$item.image_count} 张图</p>
  </div>
{/volist}
</div>

注解:遍历图库/案例列表,输出封面图、标题和图片数量。

三、条件判断 if

使用 if 标签对数据进行条件渲染。

3.1 基本语法

{if condition="!empty($item['cover'])"}
  <img src="{$item.cover}" alt="{$item.title}">
{else /}
  <div class="no-img">暂无封面</div>
{/if}

3.2 多条件判断

{if condition="$item.status == 1"}
  <span class="status-active">已发布</span>
{elseif condition="$item.status == 0" /}
  <span class="status-inactive">草稿</span>
{else /}
  <span>未知</span>
{/if}

3.3 空态处理

{if condition="!empty($list)"}
  {volist name="list" id="item"}
    ... 渲染列表 ...
  {/volist}
{else /}
  <div class="empty">暂无数据</div>
{/if}

四、分页渲染

分页数据由控制器传入,在模板中使用分页变量输出链接。

4.1 分页调用示例

{if condition="$pagination['lastPage'] > 1"}
<div class="pagination">
  {if condition="$pagination['currentPage'] > 1"}
    <a href="{$siteWww}/case?page={$pagination['currentPage'] - 1}">上一页</a>
  {/if}
  <span>第 {$pagination.currentPage} / {$pagination.lastPage} 页</span>
  {if condition="$pagination['currentPage'] < $pagination['lastPage']"}
    <a href="{$siteWww}/case?page={$pagination['currentPage'] + 1}">下一页</a>
  {/if}
</div>
{/if}

注解:仅在有多页时显示分页控件,支持上一页/下一页。

五、常用助手函数

函数功能示例
get_site_name()获取站点名称{$seo_title} ?: get_site_name()
get_site_config()获取全部站点配置get_site_config()['seo_title']
site_url($path)将相对路径转为绝对URLsite_url('/upload/1.jpg')
site_abs_content($html)将内容中的相对地址转为绝对地址site_abs_content($item.content)
htmlspecialchars()HTML实体编码输出{$item.title|htmlspecialchars}
date('Y-m-d', $ts)时间戳格式化date('Y-m-d', $item.created_at)

六、TDK 渲染

每个页面通过控制器传入 $seo_title、$seo_keywords、$seo_description,在模板 head 中输出:

<title>{$seo_title}</title>
<meta name="keywords" content="{$seo_keywords}">
<meta name="description" content="{$seo_description}">

注解:全站TDK统一由后台「网站设置」驱动,详情页可叠加内容自身SEO。

七、公共模板包含

ThinkTemplate 支持模板继承和包含,减少重复代码:

<!-- 包含公共头部 -->
{include file="common/header" /}

<!-- 包含公共底部 -->
{include file="common/footer" /}

<!-- 包含 Banner 区域 -->
{include file="common/bannet" /}

八、完整示例:单页控制器 + 模板

8.1 控制器(Sample.php)

<?php
namespace app\home\controller;
use app\BaseController;
use app\common\model\Gallery as GalleryModel;
use app\common\service\home\CateSeoService;

class Sample extends BaseController
{
    public function index()
    {
        $page = (int)input('page', 1);
        $list = GalleryModel::where('status', 1)
            ->order('sort', 'asc')
            ->order('id', 'desc')
            ->paginate(['list_rows' => 12, 'page' => $page]);

        $items = $list->items();
        foreach ($items as &$item) {
            $images = json_decode($item['images'], true) ?: [];
            $item['cover'] = !empty($images) ? site_url($images[0]) : '';
            $item['image_count'] = count($images);
        }

        $seoTdk = CateSeoService::getByAlias('home/case');
        return view('index', [
            'seo_title'  => $seoTdk['seo_title'] ?: ('客户案例 - ' . get_site_name()),
            'seo_keywords'    => $seoTdk['seo_keywords'],
            'seo_description' => $seoTdk['seo_description'],
            'list' => $items,
            'pagination' => [
                'total' => $list->total(),
                'currentPage' => $list->currentPage(),
                'lastPage' => $list->lastPage(),
                'listRows' => $list->listRows(),
            ],
            'total' => $list->total(),
        ]);
    }
}

8.2 模板(index.html)

{include file="common/header" /}

<section class="hero">
  <div class="container">
    <h1>客户案例</h1>
    <p>共 {$total} 套案例</p>
  </div>
</section>

<section class="section">
  <div class="container">
    {if condition="!empty($list)"}
    <div class="grid">
      {volist name="list" id="item"}
      <div class="card">
        {if condition="!empty($item['cover'])"}
        <img src="{$item.cover}" alt="{$item.title}">
        {/if}
        <h3>{$item.title}</h3>
        <p>{$item.image_count} 张图</p>
      </div>
      {/volist}
    </div>

    {if condition="$pagination['lastPage'] > 1"}
    <div class="pagination">
      <span>第 {$pagination.currentPage} / {$pagination.lastPage} 页</span>
    </div>
    {/if}

    {else /}
    <div class="empty">暂无案例</div>
    {/if}
  </div>
</section>

{include file="common/footer" /}

本文档适用于求元工坊CMS v1.0 及以上版本。如有疑问,请参考 帮助中心 或 提交源码申请 获取技术支持。