madj2k / t3-ajax-api
基于简单 ViewHelpers 和一些 JS 的 TYPO3 AJAX-API
Requires
- php: >=7.4
- ext-dom: *
- ext-json: *
- madj2k/t3-core-extended: ~9.5.4 || ~10.4.0
- masterminds/html5: ^2.0
- typo3/cms-core: ~9.5.0 || ~10.4.0
This package is auto-updated.
Last update: 2024-09-19 15:51:07 UTC
README
它做什么?
它以简单方便的方式为您的扩展添加 AJAX 功能。您无需自己处理 AJAX 请求。只需像往常一样编写您的扩展和模板代码 - ajax_api 将处理其余部分
设置
- 通过 composer 安装扩展
- 在后台激活扩展
- ajax_api 的 TypoScript 设置将自动激活
- 现在您需要通过 TypoScript 激活 AJAX-Js
plugin.tx_ajaxapi {
settings {
# cat=plugin.tx_ajaxapi//a; type=boolean; label=Include JS for AJAX-API (Version 2)?
includeAjaxApiJs = 1
}
}
- 不要忘记将您的常规
page
对象继承到txAjaxApiPage
对象。这应该在完成所有其他设置之后发生,以便这两个对象是相同的。
txAjaxApiPage.10 < page.10
- 您可以通过在浏览器中调用您的网站并在 URL 后附加
?type=250
来测试您的设置。这应该使用所有内容渲染您的网站,但不含 CSS 或 JavaScript。
http://example.local/?type=250
使用方法
基础知识
首先,您必须从 ActionContoller
扩展 AjaxControllerAbstract
。这样,AJAX 功能就被添加到您的扩展中。
class YourController extends \Madj2k\AjaxApi\Controller\AjaxAbstractController
{
[...]
}
基本功能可用后,我们可以使用它。以下是一个示例来说明。
示例
让我们假设您有一个扩展
- 渲染元素列表
- 为该列表提供筛选器
- 用于分页的更多按钮
Fluid 代码可能看起来像这样
<div class="filters">
<select name="filter1">
<option value="1">Value 1</option>
<option value="2">Value 2</option>
</select>
</div>
<div class="list">
<div class="list__inner">
<div class="list__item">
Item 1
</div>
<div class="list__item">
Item 3
</div>
<div class="list__item">
Item 3
</div>
</div>
<div class="button">
<a href="#">More</a>
</div>
</div>
因此,我们可能希望实现以下行为
- 如果用户筛选列表项,则整个列表应通过 AJAX 进行刷新。
- 如果用户点击更多按钮,则应通过 AJAX 将更多项添加到列表中。
- 在这两种情况下,应通过 AJAX 更新更多按钮,以便具有正确的页面号作为参数。
为了实现此行为,我们必须使用 AjaxWrapper-ViewHelper。此 ViewHelper 标记您要用于 Ajax 的 HTML 中的部分。通过它,您还可以定义应执行哪些操作。AjaxWrapper-ViewHelper 期望以下参数
- ajaxId:这是您定义的内部 ID,用于区分您使用的部分。您不需要处理命名空间。只需确保每个 ID 都是数字,并且在整个模板、部分和布局中只使用一次。
- ajaxAction:在这里,您定义当通过 Ajax 加载 ViewHelper 标签内的代码时将发生什么。如果您将其值设置为 "replace",则将替换现有内容;如果您将其值设置为 "append",则将在现有内容的末尾添加它;如果您将其值设置为 "prepend",则将在现有内容之前添加它。
- ajaxHelper:在这里,您简单地设置 AjaxHelper 对象。
首先,让我们看看在尝试解释我们为什么要这样做之前更改后的代码
<div class="filters">
<form>
<select name="filter1">
<option value="1">Value 1</option>
<option value="2">Value 2</option>
</select>
<button type="submit">Send</button>
<form>
</div>
<ajaxApi:ajaxWrapper ajaxHelper="{ajaxHelper}" ajaxAction="replace" ajaxId="1">
<div class="list">
<ajaxApi:ajaxWrapper ajaxHelper="{ajaxHelper}" ajaxAction="append" ajaxId="2">
<div class="list__inner">
<div class="list__item">
Item 1
</div>
<div class="list__item">
Item 3
</div>
<div class="list__item">
Item 3
</div>
</div>
</ajaxApi:ajaxWrapper>
<ajaxApi:ajaxWrapper ajaxHelper="{ajaxHelper}" ajaxAction="replace" ajaxId="3">
<div class="button">
<a href="#">More</a>
</div>
</ajaxApi:ajaxWrapper>
</div>
</ajaxApi:ajaxWrapper>
这将像这样渲染到前端
<div class="filters">
<form>
<select name="filter1">
<option value="1">Value 1</option>
<option value="2">Value 2</option>
</select>
<button type="submit">Send</button>
<form>
</div>
<div class="list" id="773bc02ea02b903280d609bb6a883735afbd7f14-1" data-tx-ajax-api-id="1" data-tx-ajax-api-action="replace">
<div class="list__inner" id="773bc02ea02b903280d609bb6a883735afbd7f14-2" data-tx-ajax-api-id="2" data-tx-ajax-api-action="append">
<div class="list__item">
Item 1
</div>
<div class="list__item">
Item 3
</div>
<div class="list__item">
Item 3
</div>
</div>
<div class="button" id="773bc02ea02b903280d609bb6a883735afbd7f14-3" data-tx-ajax-api-id="3" data-tx-ajax-api-action="replace">
<a href="#">More</a>
</div>
</div>
如您所见,AjaxWrapper-ViewHelper 将向其第一个子元素添加一些属性。请注意,这些属性仅添加到定义的合法 HTML 标签集(例如 DIV 和 FORM)。我们做了什么?我们告诉扩展
- 完全刷新具有 ID "773bc02ea02b903280d609bb6a883735afbd7f14-1" 的 DIV 的 innerHTML - 因为:如果用户筛选列表项,则整个列表应通过 AJAX 进行刷新。
- 将项添加到具有 ID "773bc02ea02b903280d609bb6a883735afbd7f14-2" 的 DIV 的 innerHTML 中 - 因为:如果用户点击更多按钮,则应通过 AJAX 将更多项添加到列表中。
- 完全刷新ID为"773bc02ea02b903280d609bb6a883735afbd7f14-3"的DIV的innerHTML - 原因:在两种情况下,更多按钮都应该通过AJAX更新,以便具有正确的页码作为参数。
目前还缺少关于何时执行这些操作的说明。这是通过将一些参数设置到带有additionalParams属性的链接和表单中实现的。您可以结合以下参数和您扩展的自定义参数。
additionalParams="{your_stuff: '{key: value}', ajax_api: '{key: ajaxHelper.key, cid: ajaxHelper.contentUid, idl: \'2,3\'}'}"
让我们看看这些参数及其作用
- key:只需在这里添加
ajaxHelper.key
。这是一个内部生成的键,旨在防止扩展和插件之间的冲突。 - cid:只需在这里添加
ajaxHelper.contentUid
。这是当前内容元素的uid,以便包含flexform设置。 - idl:这是神奇的部分。在这里,您可以添加一个要通过AJAX更新的Ajax-Ids列表。
让我们将其整合到我们的示例中
<div class="filters">
<f:form noCacheHash="true" action="list" controller="More" extensionName="Example" pluginName="Morecontent" class="ajax"
additionalParams="{ajax_api : '{key: ajaxHelper.key, cid: ajaxHelper.contentUid, idl: \'1\'}'">
<select name="filter1">
<option value="1">Value 1</option>
<option value="2">Value 2</option>
</select>
<button type="submit">Send</button>
</f:form>
</div>
<ajaxApi:ajaxWrapper ajaxHelper="{ajaxHelper}" ajaxAction="replace" ajaxId="1">
<div class="list">
<ajaxApi:ajaxWrapper ajaxHelper="{ajaxHelper}" ajaxAction="append" ajaxId="2">
<div class="list__inner">
<div class="list__item">
Item 1
</div>
<div class="list__item">
Item 3
</div>
<div class="list__item">
Item 3
</div>
</div>
</ajaxApi:ajaxWrapper>
<ajaxApi:ajaxWrapper ajaxHelper="{ajaxHelper}" ajaxAction="replace" ajaxId="3">
<f:link.action action="list" controller="More" extensionName="Example" pluginName="Morecontent"
class="ajax"
title="<f:translate key='partials.default.more.boxes.more.labelMore' extensionName='Example' />"
rel="nofollow" target="_blank"
additionalParams="{tx_example_morecontent: '{pageNumber: pageNumber, filter: filter}', ajax_api : '{key: ajaxHelper.key, cid: ajaxHelper.contentUid, idl: \'2,3\'}'}">
<f:translate key="partials.default.more.boxes.more.labelMore" extensionName="Example" />
</f:link.action>
</ajaxApi:ajaxWrapper>
</div>
</ajaxApi:ajaxWrapper>
这样,带有参数idl=1
的表单将处理ID为1
的AjaxWrapper,并在提交时替换第一个DIV的所有innerHTML。因此,如果用户筛选项目,他将获得一个新的列表和一个新的更多按钮。
带有参数idl=2,3
的更多链接将在点击时处理ID为2
和3
的AjaxWrapper。对于ID为2
的AjaxWrapper,新内容将添加到第一个DIV的innerHTML中(例如,列表的第二页)。对于ID为3
的AjaxWrapper,按钮本身将被替换为一个新的按钮,该按钮现在包含正确的参数以加载第三页。
最后但并非最不重要的是:别忘了将CSS类ajax
添加到所有旨在触发AJAX事件的元素上 ;-)
基本上就是这些魔法。
高级用法选项
在提交时
默认情况下,表单始终在“change”时发送。可以通过使用附加类“ajax-submit-only”将此行为更改为“submit”。
<f:form
action="new"
class="ajax ajax-submit-only"
additionalParams="{ajax_api: '{key: ajaxHelper.key, cid: ajaxHelper.contentUid, idl: \'1\'}'}"
>
滚动到顶部
要提交后滚动到顶部,请使用类“ajax-scroll-top”。
加载指示器
作为数据属性,您可以使用“data-ajax-indicator-id”指定应该使用灰度显示的容器ID。
特殊情况I:在页面加载时执行Ajax调用
要实现这一点,您只需向网站添加一个模板标记。以下示例还检查了登录用户,并且只有在用户登录时才执行AJAX调用。
<template class="ajax" id="tx-example-login-info-ajax"></template>
<f:comment><!-- only do an ajax-call if fe-cookie is set. This is to reduce requests to the server--></f:comment>
<script type="text/javascript">
var txExampleAjaxUrl = "{f:uri.action(action:'loginInfo', absolute:'1', addQueryString: '1', additionalParams:'{ajax_api : \'{key: ajaxHelper.key, cid: ajaxHelper.contentUid, idl: \\\'1\\\'}\'}') -> f:format.raw()}";
if (document.cookie.indexOf('fe_logged_in=') > -1) {
document.getElementById('tx-example-login-info-ajax').setAttribute('data-ajax-url', txExampleAjaxUrl);
}
</script>
如果您将其与表单结合使用,还可以检查表单是否已提交。这样,只有当表单未提交时,才会触发AJAX调用。在这种情况下,如果控制器中出现错误,也很重要使用forward方法,因为forward方法保留了POST变量,从而防止了进一步的AJAX调用。
<template class="ajax" id="tx-example-login-info-ajax"></template>
<f:comment><!-- only do an ajax-call if fe-cookie is set AND the form was not submitted. This is to reduce requests to the server--></f:comment>
<f:if condition="! {ajaxHelper.isPostCall}">
<script type="text/javascript">
var txExampleAjaxUrl = "{f:uri.action(action:'loginInfo', absolute:'1', addQueryString: '1', additionalParams:'{ajax_api : \'{key: ajaxHelper.key, cid: ajaxHelper.contentUid, idl: \\\'1\\\'}\'}') -> f:format.raw()}";
if (document.cookie.indexOf('fe_logged_in=') > -1) {
document.getElementById('tx-example-login-info-ajax').setAttribute('data-ajax-url', txExampleAjaxUrl);
}
</script>
</f:if>
特殊情况II:在页面加载时,仅对特定视口执行Ajax调用
在某些情况下,将AJAX请求绑定到页面加载时的特定视口很有帮助,例如,仅针对移动设备触发它。为此,您只需添加相应的属性data-ajax-max-width
。
<template class="ajax" data-ajax-max-width="1280" data-ajax-url="{f:uri.action(action:'mobileMenu', absolute:'1', additionalParams:'{ajax_api : \'{key: ajaxHelper.key, cid: ajaxHelper.contentUid, idl: \\\'1\\\'}\'}') -> f:format.raw()}"></template>
附加提示
从版本v8.7.57-stable开始,所有请求都作为“POST”发送,以避免JavaScript错误“HTTP错误414。请求URL太长”。