在 ThinkPHP 中,默认情况下,一个模块(Module)的控制器(Controller)只能渲染其自身模块下的 view 目录中的模板文件。Index 模块的控制器会去 view/index/ 目录下找模板。

但在实际开发中,我们经常需要在一个模块中调用另一个模块的模板,
- 在后台管理模块中,调用前台用户模块的某个列表页模板。
- 创建一个公共的布局模板,供所有模块共享。
ThinkPHP 提供了非常灵活和强大的模板调用机制,主要有以下几种方法,我会从最推荐到最灵活的顺序进行介绍。
使用 extend 标签 (推荐,用于布局和继承)
这是最常用、最符合 ThinkPHP 设计思想的方法,主要用于实现模板的布局和继承,它可以在当前模板中引入并继承另一个模板的结构。
适用场景:

- 创建一个全局的
layout.html作为基础布局。 - 让各个模块的页面继承这个基础布局,只需填充内容块。
操作步骤:
-
创建公共布局模板 假设我们创建一个公共布局模板,放在
view/public/layout.html。<!-- view/public/layout.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>{block name="title"}默认标题{/block}</title> <link rel="stylesheet" href="/static/css/common.css"> </head> <body> <header>网站公共头部</header> <main> {block name="content"}这里是默认内容{/block} </main> <footer>网站公共底部</footer> </body> </html> -
在子模块模板中继承布局 我们希望在
index模块的index控制器所对应的模板view/index/index.html中使用这个公共布局。<!-- view/index/index.html --> {extend name="public/layout" /} {block name="title"}首页 - 我的应用{/block} {block name="content"} <h1>欢迎来到首页!</h1> <p>这是首页的内容。</p> {/block}
说明:

{extend name="public/layout" /}: 这行代码告诉当前模板要继承public/layout.html。- ThinkPHP 会自动在
view目录下查找public/layout.html。 {block}...{/block}: 这些标签会覆盖掉父模板(layout.html)中同名的{block}
跨模块使用:
如果想继承 admin 模块下的布局模板 view/admin/layout.html,只需修改路径即可:
{extend name="admin/layout" /}
ThinkPHP 会自动在 view/admin/ 目录下查找。
使用 include 标签 (简单,用于引入片段)
include 标签用于在当前位置直接引入并解析另一个模板文件的内容,类似于 PHP 的 include,它不涉及继承,只是简单地把一个模板文件“粘贴”过来。
适用场景:
- 引入一个通用的头部、底部、侧边栏等。
- 引入一个在其他模块中定义的某个小部件模板。
操作步骤:
假设 admin 模块需要一个侧边栏,而这个侧边栏的模板定义在 index 模块里。
-
创建侧边栏模板
view/index/sidebar.html:<!-- view/index/sidebar.html --> <div class="sidebar"> <h3>用户菜单</h3> <ul> <li><a href="#">个人中心</a></li> <li><a href="#">我的订单</a></li> <li><a href="#">账户设置</a></li> </ul> </div> -
在目标模板中引入 在
admin模块的某个页面view/admin/dashboard.html中引入它:<!-- view/admin/dashboard.html --> <div class="dashboard"> <div class="main-content"> <h1>管理面板</h1> <p>欢迎管理员!</p> </div> <div class="aside"> {include file="index/sidebar" /} </div> </div>
说明:
{include file="index/sidebar" /}: 这行代码会引入view/index/sidebar.html文件。- 路径是相对于当前模块的
view目录的,如果你想引入public模块的模板,可以写成{include file="public/header" /}。
使用 template 属性 (最灵活,完全自定义路径)
如果你不想依赖 ThinkPHP 的默认 view 目录结构,或者需要动态地指定一个完全不同路径的模板,可以在控制器中使用 template 属性来指定模板文件的完整路径。
适用场景:
- 模板文件存放在项目根目录的
templates文件夹下。 - 根据用户权限或某些条件,动态加载不同模块、不同位置的模板。
- 第三方库或插件自带了模板文件,需要直接调用。
操作步骤:
假设我们有一个公共模板文件,放在 app/templates/common/about_us.html。
-
在控制器中指定模板路径
<?php namespace app\index\controller; use think\Controller; class Index extends Controller { public function about() { // 使用 template 属性指定模板的完整路径 // 注意:这里的路径是相对于应用(app)根目录的 $this->template = '../templates/common/about_us'; // 也可以使用助手函数,效果一样 // return view('../templates/common/about_us'); // 你仍然可以传递数据给模板 $this->assign('site_name', '我的ThinkPHP应用'); return $this->fetch(); } }
说明:
$this->template = '../templates/common/about_us';:这里指定的路径是相对于当前模块的视图目录(view)的。Index模块的view目录是app/view/index/, 会回到app/目录,然后找到templates/common/about_us.html。- 推荐使用助手函数
view():在现代 ThinkPHP 版本中,直接在控制器方法中返回view()是更简洁的方式。public function about() { return view('../templates/common/about_us', ['site_name' => '我的ThinkPHP应用']); } - 绝对路径:如果你觉得相对路径容易混淆,可以使用绝对路径(从
public目录开始)。// 从 public 目录开始 return view('../../templates/common/about_us');或者使用
APP_PATH常量来构建绝对路径:$templatePath = APP_PATH . 'templates/common/about_us'; return view($templatePath);
总结与对比
| 方法 | 标签/函数 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 继承布局 | {extend name="..." /} |
创建公共布局、页面框架 | 结构清晰,代码复用率高,符合MVC思想 | 不适合引入独立的、不依赖结构的模板片段 |
| 引入片段 | {include file="..." /} |
引入头部、底部、小部件等 | 简单直接,灵活 | 每次引入都是完整解析,不适合大段重复代码 |
| 自定义路径 | $this->template / view() |
路径不固定、动态加载、第三方模板 | 最灵活,可以指定任何位置的模板 | 破坏了模块化的视图组织,路径管理稍显复杂 |
最佳实践建议:
- 优先使用
{extend}:对于网站的公共布局(如 header, footer, main 结构),使用{extend}和{block}是最优雅、最强大的方式。 - 次选
{include}:对于一些可复用的、不依赖父模板结构的独立模板片段(如一个商品卡片、一个评论框),使用{include}。 - 慎用自定义路径:仅在特殊需求(如模板文件在非标准目录、动态加载)下使用
$this->template或view()的完整路径功能,因为它会让视图的查找变得不那么直观。
希望这个详细的解释能帮助你完全掌握 ThinkPHP 的跨模块模板调用!
