ThinkPHP 6.x 已彻底移除 Widget 类和 {:widget()} 语法,需改用 {include} 模板包含配合 View::fetch() 动态渲染,并通过配置 taglib_include 支持传参,变量需控制器 assign 且注意作用域隔离。

Widget类已被移除,widget标签无法解析
ThinkPHP 6.x 完全移除了 Widget 类和模板中的 {:widget('xxx')} 语法,硬写会直接报错:ParseError: syntax error, unexpected 'widget' (T_STRING)。这不是配置问题,是底层架构删掉了——别试 extend 目录下手动加旧类,加载器根本找不到。
替代方案不是“找一个新函数叫 widget”,而是换一套思路:用 View 层的原生能力做组件化。
- 所有组件逻辑必须收归
view目录下的独立模板文件(如widget/header.html) - 禁止在模板里调用 PHP 类或方法,只允许
{include file="widget/header" /}这种纯静态包含 - 需要动态数据?必须由控制器提前 assign 进去,不能在 include 时传参(
{include file="xxx" title="abc" /}在 TP6 默认不支持,需开启template.taglib_include配置)
如何让 {include} 支持变量传入(类似旧 Widget 的参数机制)
默认情况下,TP6 的 {include} 标签只做文件合并,不支持运行时传参。想模拟旧 Widget 的 {:widget('login', ['type'=>'mini'])} 行为,得打开模板引擎的扩展开关:
- 修改
config/template.php,把'taglib_include' => true设为true - 之后才能用
{include file="widget/login" type="mini" /},变量会以$type形式在被包含模板中可用 - 注意:该功能依赖
think-templatev2.0+,低于此版本即使开启也无效 - 传参仅限字符串/数字/布尔值,数组和对象会被自动转成空字符串,别指望传
$user对象进去
动态内容封装:用 View::fetch() 替代 Widget::render()
如果旧代码里有 Widget::render('sidebar', ['data' => $list]) 这类服务端主动渲染调用,现在得改写成控制器内手动 fetch:
// 旧写法(已失效)
// return Widget::render('sidebar', ['data' => $list]);
// 新写法:在控制器中
$content = View::fetch('widget/sidebar', ['data' => $list]);
$this->assign('sidebar_html', $content);
return $this->fetch();
-
View::fetch()返回的是渲染后的 HTML 字符串,不是响应体,不会自动输出 - 务必 assign 给模板变量再用
{$sidebar_html|raw}输出,否则会被自动转义 - 高频调用时注意性能:每次
fetch()都会触发模板编译检查,建议对稳定组件开启模板缓存('cache' => true)
组件状态隔离难?别在模板里写逻辑
很多人迁移到 {include} 后发现多个页面共用同一组件时,状态互相污染(比如一个页面改了 $active,另一个页面也跟着变)。根本原因是:模板变量是全局共享的,不是作用域隔离的。
- 解决方案只有一个:每个组件模板开头强制重置所需变量,例如
{% set active = active ?? 'home' %}(需开启template.layout和template.syntax支持 Twig 风格语法) - 更稳妥的做法是彻底放弃模板内逻辑,在控制器层就拆好数据结构,比如传入
['sidebar' => ['items' => $items, 'active' => 'user']],组件模板只做展示 - 切记:TP6 的模板不是前端框架,没有响应式数据绑定,也没有组件实例概念。所谓“组件”,只是带点变量的 HTML 片段而已
真正麻烦的从来不是怎么写 include,而是怎么让不同页面传进来的变量名不冲突、不遗漏、不误判类型——这得靠团队约定,不是靠某个函数能兜底的。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










