文档目录
视图模板系统

简介

本文件面向前端开发者,系统化说明 DouPHP 前台视图模板系统(DWT 模板)的使用方法、语法特性与最佳实践。内容涵盖:

  • 模板继承与布局变量注入机制
  • 组件复用(include 片段化)
  • 条件渲染、循环遍历、变量输出与过滤器
  • URL 生成与路由占位符
  • 响应式设计与移动端适配要点
  • 性能优化与调试方法

项目结构

DouPHP 前台模板位于 theme 目录下,默认主题在 theme/default,页面模板以 .dwt 结尾,公共片段以 inc/*.tpl 组织。控制器通过 view() 将数据传递给模板,模板中通过 include 组合头部、导航、页脚等组件,形成完整页面。

graph TB
A["控制器<br/>IndexController"] --> B["视图引擎<br/>BaseController::view()"]
B --> C["页面模板<br/>index.dwt"]
C --> D["组件片段<br/>inc/header.tpl / footer.tpl"]
C --> E["业务片段<br/>inc/recommend_product.tpl 等"]
B --> F["全局布局变量<br/>layoutVars() 合并"]

核心组件

  • 控制器基类 BaseController:提供 view() 渲染入口,自动合并 layoutVars() 作为布局公共变量;支持 JSON 成功响应与重定向分流。
  • 首页控制器 IndexController:组装首页数据并返回 index.dwt;在 layoutVars() 中注入导航与 SEO 信息。
  • 视频控制器 VideoController:演示详情页数据准备与模板渲染流程。
  • 模板与片段:index.dwt、product.dwt 为页面骨架;header.tpl、footer.tpl 等为可复用组件。

架构总览

请求进入控制器后,控制器调用 view() 渲染模板。BaseController::view() 将 action 传入的数据与 layoutVars() 返回的布局变量合并(action 数据优先),再交由模板引擎渲染。模板通过 {include} 引入 header、footer 等片段,并通过 {foreach}/{if} 等语法进行条件与循环渲染。

sequenceDiagram
participant U as "浏览器"
participant C as "控制器"
participant V as "视图引擎(BaseController : : view)"
participant T as "模板(index.dwt)"
participant I as "片段(header.tpl / footer.tpl)"
U->>C : "HTTP 请求"
C->>V : "view('index.dwt', data + layoutVars())"
V->>T : "渲染页面模板"
T->>I : "{include file='inc/header.tpl'}"
I-->>T : "HTML 片段"
T->>I : "{include file='inc/footer.tpl'}"
I-->>T : "HTML 片段"
T-->>U : "最终 HTML"

详细组件分析

模板继承与布局变量

  • 布局变量注入:BaseController::view() 会将 action 数据与 layoutVars() 返回的数组进行合并,键冲突时 action 数据优先。
  • 常用布局变量:导航列表(top/middle/bottom)、SEO 信息(keywords/description/page_title)、站点配置(site.*)等。
  • 扩展方式:在子类中重写 layoutVars() 叠加更多公共变量。
flowchart TD
Start(["控制器调用 view()"]) --> Merge["合并数据:<br/>action_data + layoutVars()"]
Merge --> Render["渲染模板"]
Render --> End(["输出 HTML"])

组件复用(include)

  • 使用 {include file="inc/xxx.tpl"} 将头部、导航、页脚、推荐模块等拆分为独立片段,便于维护与复用。
  • 典型片段:header.tpl(顶部导航、登录态、搜索框)、footer.tpl(底部导航、联系方式、版权信息)。
graph LR
P["页面模板<br/>index.dwt"] --> H["头部片段<br/>inc/header.tpl"]
P --> R["推荐片段<br/>inc/recommend_*.tpl"]
P --> F["页脚片段<br/>inc/footer.tpl"]

条件渲染与循环遍历

  • 条件:{if $features.xxx} ... {/if} 控制功能开关或模块显示。
  • 循环:{foreach from=$nav_middle_list item=nav} ... {/foreach} 用于渲染多级导航、商品列表、相册缩略图等。
  • 示例:产品详情页中的画廊缩略图、属性值列表、优惠券列表均通过 foreach 渲染。
flowchart TD
A["读取数据源"] --> B{"是否满足条件?"}
B -- 否 --> C["跳过该区块"]
B -- 是 --> D["遍历集合"]
D --> E["渲染每个条目"]
E --> F["结束"]

变量输出与过滤器

  • 变量输出:{$page_title}、{$site.home_url}、{$dou.user.user_name} 等。
  • 过滤器:|escape 用于转义输出,避免 XSS;nofilter 用于安全地输出富文本(如 {$product.content nofilter})。
  • 建议:对用户输入一律使用 |escape;对可信后端富文本谨慎使用 nofilter。

URL 生成与路由

  • 模板中使用 {url link='...'} 生成链接,结合路由规则与短地址配置,保证链接稳定且可读。
  • 路由占位符:支持 {year}/{month}/{id} 等段,以及分类别名段 {category_slug},便于构建归档与详情 URL。
flowchart TD
Tpl["模板 {url link='...'}"] --> R["路由解析"]
R --> S["短地址规则匹配"]
S --> U["生成最终 URL"]

控制器到模板的数据流(以视频详情为例)

  • 控制器准备 SEO、导航、面包屑、结构化数据等数据。
  • 通过 view('video.dwt', [...]) 将数据传给模板。
  • 模板渲染页面骨架与片段,展示详情内容。
sequenceDiagram
participant VC as "VideoController"
participant BR as "Breadcrumb/Seo/Nav"
participant TR as "TemplateRenderer"
participant VT as "video.dwt"
VC->>BR : "构建面包屑/SEO/导航"
VC->>TR : "view('video.dwt', 数据)"
TR->>VT : "渲染模板"
VT-->>TR : "HTML"
TR-->>VC : "响应"

依赖关系分析

  • 控制器依赖服务:导航、SEO、用户认证、路由等。
  • 模板依赖片段:header、footer、推荐模块、评论等。
  • 路由依赖配置:短地址与占位符决定 URL 形态。
graph TB
subgraph "控制器层"
BC["BaseController"]
IC["IndexController"]
VC["VideoController"]
end
subgraph "模板层"
IDX["index.dwt"]
PRD["product.dwt"]
HDR["inc/header.tpl"]
FTR["inc/footer.tpl"]
end
subgraph "配置层"
RT["config/route.php"]
end
IC --> BC
VC --> BC
IC --> IDX
VC --> PRD
IDX --> HDR
IDX --> FTR
PRD --> HDR
PRD --> FTR
IDX --> RT
PRD --> RT

性能与优化

  • 减少不必要的 include:仅在需要时引入大片段,避免重复加载。
  • 合理使用过滤器:|escape 增加开销,仅在必要时使用;富文本用 nofilter 但要确保来源可信。
  • 缓存静态资源:CSS/JS 加版本或 CDN,减少请求体积。
  • 控制循环复杂度:大数据集分页或懒加载,避免一次性渲染过多节点。
  • 利用布局变量复用:将通用数据放入 layoutVars(),减少重复计算。

故障排查指南

  • 模板未找到:检查 view() 传入的模板名与 theme 目录结构是否一致。
  • 变量为空:确认控制器是否传递了对应键;检查 layoutVars() 是否被覆盖。
  • 输出乱码或 XSS:确认字符集设置与 |escape/noFilter 的使用是否正确。
  • 链接错误:核对 {url link='...'} 与 config/route.php 的短地址规则是否匹配。
  • 片段未生效:确认 include 路径与文件名大小写正确。

结论

DouPHP 前台模板系统通过“控制器 + 模板 + 片段”的分层设计,实现了清晰的职责分离与高复用性。借助布局变量注入、include 组件化、条件与循环语法、URL 生成与路由占位符,开发者可以快速构建响应式、可维护的前台页面。遵循本文的最佳实践,可在保证性能与安全的前提下高效开发。

附录:模板语法速查

  • 变量输出:{$var}、{$obj.prop}、{$arr.key}
  • 过滤器:{$var|escape}、{$html nofilter}
  • 条件:{if $flag} ... {/if}、{if $a eq $b} ... {/if}
  • 循环:{foreach from=$list item=item name=loop} ... {/foreach}
  • 片段:{include file="inc/header.tpl"}
  • 链接:{url link='user.login'}、{url link='search'}
  • 站点信息:{$site.home_url}、{$site.root_url}、{$site.site_logo}
  • 用户信息:{$dou.auth.is_login}、{$dou.user.user_name}
添加日期:2026-10-05