TYPO3扩展:点击事件链接在同容器加载详情而非刷新插件区域
实现TYPO3扩展中事件详情的Ajax无刷新替换
我来帮你搞定这个Ajax无刷新替换的需求,分几个清晰的步骤来实现:
1. 修改前端列表模板(list.html)
首先调整事件链接的行为,阻止默认页面跳转,同时添加JavaScript处理Ajax请求:
<div id="dncalendar-container"></div> <f:flashMessages /> <div class="tx_tbpartnereventcal"> <f:for each="{events}" as="event"> <!-- 替换原链接为自定义标签,用data属性存储事件UID --> <a href="#" class="event-cont event-link" data-event-uid="{event.uid}"> <span class="event-title">{event.title}</span> <span class="event-date"><f:format.date format="Y-m-d">{event.date}</f:format.date></span><br> </a> </f:for> </div> <!--<f:debug>{_all}</f:debug>--> <f:format.raw>{scriptDates}</f:format.raw> <script type="text/javascript"> // 获取TYPO3生成的CSRF Token(用于请求合法性验证) const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content; // 监听事件链接点击 document.querySelectorAll('.event-link').forEach(link => { link.addEventListener('click', function(e) { e.preventDefault(); // 阻止默认页面跳转 const eventUid = this.dataset.eventUid; const container = document.querySelector('.tx_tbpartnereventcal'); // 发送Ajax请求加载详情 fetch('{f:uri.action(action: 'show', controller: 'Events', pageType: 123)}', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRF-Token': csrfToken }, body: `events=${eventUid}` }) .then(response => response.text()) .then(html => { container.innerHTML = html; // 替换容器内容为详情 }) .catch(error => { console.error('加载失败:', error); container.innerHTML = '<p>事件详情加载失败,请稍后重试。</p>'; }); }); }); // 原日历生成脚本保留 // script to generate calendar </script>
这里的关键细节:
- 用
data-event-uid存储事件ID,避免硬编码URL - 引入CSRF Token是TYPO3的安全要求,必须携带
- 指定
pageType:123用来区分Ajax请求,后续会配置这个页面类型
2. 配置TYPO3特殊页面类型
要让showAction返回不带页面布局的纯详情内容,需要在扩展的ext_localconf.php中添加配置:
// 注册页面类型123用于Ajax请求 $GLOBALS['TYPO3_CONF_VARS']['FE']['pageTypeNum'] = array_merge( $GLOBALS['TYPO3_CONF_VARS']['FE']['pageTypeNum'], [ 123 => 'Ajax Event Content', ] ); // 为该页面类型禁用全局布局和头部代码 $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript'] .= ' [globalVar = GP:type = 123] page.config.disableAllHeaderCode = 1 page.config.disablePrefixComment = 1 page.config.metaCharset = utf-8 page.config.xhtml_cleaning = 0 page.config.admPanel = 0 [global] ';
这样当请求携带type=123参数时,TYPO3只会渲染控制器返回的局部内容,不会包含整个页面框架。
3. 调整控制器与模板
创建详情局部模板
在Resources/Private/Templates/Events/ShowAjax.html中编写纯详情内容:
<div class="event-detail"> <h2>{events.title}</h2> <p><strong>日期:</strong> <f:format.date format="Y-m-d H:i">{events.date}</f:format.date></p> <p>{events.description}</p> <!-- 可根据需求添加更多字段 --> <button class="back-to-list">返回事件列表</button> </div> <script> // 返回列表的Ajax逻辑 document.querySelector('.back-to-list').addEventListener('click', function() { fetch('{f:uri.action(action: 'list', controller: 'Events', pageType: 123)}', { method: 'GET', headers: { 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content } }) .then(response => response.text()) .then(html => { document.querySelector('.tx_tbpartnereventcal').innerHTML = html; }); }); </script>
修改控制器方法
调整showAction,根据页面类型切换模板:
/** * action show * * @param \TBPartnerNet\TbPartnerTerminkalender\Domain\Model\Events $events * @return void */ public function showAction(\TBPartnerNet\TbPartnerTerminkalender\Domain\Model\Events $events) { $this->view->assign('events', $events); // 判断是否为Ajax请求,切换到局部模板 if (($this->request->getQueryParams()['type'] ?? 0) === 123) { $this->view->setTemplate('ShowAjax'); } }
同理,给listAction也添加Ajax适配,创建ListAjax.html(仅保留列表内容),并在listAction中添加模板切换逻辑:
// 在listAction末尾添加 if (($this->request->getQueryParams()['type'] ?? 0) === 123) { $this->view->setTemplate('ListAjax'); }
4. 确保CSRF Token正常输出
如果你的根模板中没有自动生成CSRF标签,需要在<head>部分添加:
<f:security.csrfToken />
这个ViewHelper会生成类似<meta name="csrf-token" content="xxx">的标签,供Ajax请求验证使用。
完成以上步骤后,点击事件列表项就会通过Ajax加载详情内容替换列表容器,点击返回按钮又能重新加载列表,全程无页面刷新~
内容的提问来源于stack exchange,提问作者Alex S.
相关产品推荐
相关产品推荐

