跳至主要内容
版本: 5.1

步骤 9 添加 Ajax

在本步骤中,我们将 Ajax 添加到 mod_hello,并说明

  • 如何将语言字符串传递到 JavaScript 代码,以及
  • 如何从 JavaScript 显示系统消息。

源代码可在 mod_hello 步骤 9 中找到。

com_ajax

Joomla 提供了一个组件 com_ajax(描述 这里),它允许模块的 JavaScript 代码进行 Ajax 调用并获取 Ajax 响应。

待办

com_ajax 文档移至手册后更新上述链接

在 JavaScript 代码中,我们对 index.php?option=com_ajax&module=hello&method=count&format=json 发起 Ajax 调用。URL 参数的解释如下:

  • option=com_ajax 表示 Joomla 将此 HTTP 请求路由到 com_ajax 组件。com_ajax 将解释剩余的 URL 参数
  • module=hello 我们希望路由到 mod_hello 模块
  • method=count com_ajax 将调用模块辅助类的 countAjax() 方法
  • format=json 我们希望响应以 JSON 格式

序列图显示了它是如何工作的

com_ajax 接收到结果后,使用 Joomla JsonResponse 类将结果返回到 JavaScript 代码。

待办

JsonResponse 文档移至手册后更新上述链接

mod_hello 变更

为了演示 Ajax 功能,我们将在模块上提供一个按钮,单击该按钮将触发一个 Ajax 请求以获取已登录用户的数量。Ajax 响应将是

  • 如果当前用户已登录,则为已登录用户的数量
  • 如果当前用户未登录,则为“未授权”错误

我们在 mod_hello 中的代码变更如下:

  1. 在 tmpl 文件中输出一个按钮,用户可以单击该按钮
  2. 创建用于执行 Ajax 调用和处理响应的 js
  3. 在辅助类中创建 countAjax 函数

tmpl 文件变更

以下是更新后的 tmpl 文件

mod_hello/tmpl/default.php
<?php
defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;

$document = $this->app->getDocument();
$wa = $document->getWebAssetManager();
$wa->getRegistry()->addExtensionRegistryFile('mod_hello');
$wa->useScript('mod_hello.add-suffix');

// Pass the suffix to add down to js
$document->addScriptOptions('vars', ['suffix' => '!']);

$h = $params->get('header', 'h4');
$greeting = "<{$h} class='mod_hello'>{$hello}</{$h}>";

Text::script('MOD_HELLO_AJAX_OK');
Text::script('JLIB_JS_AJAX_ERROR_OTHER');
?>

<?php echo $greeting; ?>
<div>
<p><?php echo Text::_('MOD_HELLO_NUSERS'); ?><span class="mod_hello_nusers"></span></p>
<button class="mod_hello_updateusers"><?php echo Text::_('MOD_HELLO_UPDATE_NUSERS'); ?></button>
</div>

这里我们使用的是 Text::script 函数将语言字符串传递到 JavaScript 代码。

Text::script('MOD_HELLO_AJAX_OK');

将传递语言字符串 'MOD_HELLO_AJAX_OK' 以使其可供 js 代码使用。

然后,我们可以使用以下方法在 JavaScript 中解释此语言字符串

Joomla.Text._('MOD_HELLO_AJAX_OK')

您可以在 media/system/js/core.js 中的 core.js 库中找到 Joomla.text

语言字符串 'JLIB_JS_AJAX_ERROR_OTHER' 位于 lib_joomla.ini 语言文件中,它始终由 Joomla 在其初始化期间加载。

JavaScript 变更

为了方便起见,我们将 Ajax 代码添加到 add-suffix.js 中。新增行如下:

const countUsers = (event) => {
const nusers = event.target.parentElement.querySelector('span.mod_hello_nusers');
Joomla.request({
url: 'index.php?option=com_ajax&module=hello&method=count&format=json',
method: 'GET',
onSuccess(data) {
const response = JSON.parse(data);
if (response.success) {
nusers.innerText = response.data;
const confirmation = Joomla.Text._('MOD_HELLO_AJAX_OK').replace('%s', response.data);
Joomla.renderMessages({ 'info': [confirmation] });
} else {
const messages = { 'error': [response.message] };
Joomla.renderMessages(messages);
}
},
onError(xhr) {
Joomla.renderMessages(Joomla.ajaxErrorsMessages(xhr));
const response = JSON.parse(xhr.response);
Joomla.renderMessages({ 'error': [response.message] }, undefined, true);
}
});
};

document.querySelectorAll('.mod_hello_updateusers').forEach(element => {
element.addEventListener('click', countUsers);
});

我们在更新按钮上设置了 onclick 监听器,单击该监听器将触发 Ajax 调用。

Joomla.request 位于 core.js 中,描述 这里。当然,您可以使用您自己的首选方法来发起 Ajax 请求。

Joomla.renderMessages 位于 media/system/js/messages.js 中,用于在 HTML 文档的系统消息区域中显示消息。查看 messages.js 代码了解如何使用它。

由于我们的代码现在依赖于“messages”和“core”,因此我们需要更新 joomla.asset.json。

此外,我们还应更新 JavaScript 版本号,这将确保浏览器缓存的任何 add-suffix.js 代码都被刷新。

mod_hello/media/joomla.asset.json
{
"$schema": "https://developer.joomla.net.cn/schemas/json-schema/web_assets.json",
"name": "mod_hello",
"version": "1.0.0",
"description": "Joomla Module Tutorial",
"license": "GPL-2.0-or-later",
"assets": [
{
"name": "mod_hello.add-suffix",
"type": "script",
"uri": "mod_hello/add-suffix.js",
"dependencies": [
"jquery", "core", "messages"
],
"version": "1.1.0"
}
]
}

辅助文件变更

当您登录到管理员后台时,Joomla 会显示已登录用户的列表。经过一番调查,您可以发现这是由管理员模块 administrator/modules/mod_logged 输出的,其中包含其辅助文件中的 getList 方法,该方法返回已登录用户的列表。

一种选择是通过调用 \Joomla\Module\Logged\Administrator\Helper\LoggedHelper::getList() 直接使用此代码,但重用像这样的 Joomla 代码风险很大,因为它可能在不同版本之间发生变化。特别是在将模块从旧样式(Joomla 3)更新到包括依赖注入时,getList 函数会从静态函数变为实例函数。

因此,更直接的方法是复制这种方法并使用类似的数据库查询,辅助文件中的新增行如下所示:

mod_hello/src/Helper/HelloHelper.php
use Joomla\Database\DatabaseInterface;
use Joomla\CMS\Language\Text;
...
public function countAjax()
{
$user = Factory::getApplication()->getIdentity();

if ($user->id == 0) {
// not logged on
throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'));
}

$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->getQuery(true)
->select('COUNT(*)')
->from('#__session AS s')
->where('s.guest = 0');

$db->setQuery($query);

return (string) $db->loadResult();
}

请注意,com_ajax 在模块 Extension 类上使用 $module->getHelper(...) 来查找 Helper 类(如 步骤 8 所述)。因此,您必须在 services/provider.php 文件中设置 HelperFactory,正如我们在依赖注入步骤中所做的那样。

新的语言字符串

mod_hello/language/en-GB/mod_hello.ini
; language strings used inside mod_hello 
MOD_HELLO_NAME="Joomla Module Tutorial"
MOD_HELLO_DESCRIPTION="Source code for the Joomla module tutorial"
MOD_HELLO_GREETING="Hello "
MOD_HELLO_HEADER_LEVEL="Header level of greeting"
MOD_HELLO_HEADER_LEVEL_3="Header level 3"
MOD_HELLO_HEADER_LEVEL_4="Header level 4"
MOD_HELLO_HEADER_LEVEL_5="Header level 5"
MOD_HELLO_HEADER_LEVEL_6="Header level 6"
MOD_HELLO_NUSERS="Number of logged-on users: "
MOD_HELLO_UPDATE_NUSERS="Update"
MOD_HELLO_AJAX_OK="Ajax response: %s received ok"

清单文件变更

mod_hello/mod_hello.xml
<?xml version="1.0" encoding="utf-8"?>
<extension type="module" client="site" method="upgrade">
<name>MOD_HELLO_NAME</name>
<version>1.0.9</version>
<author>me</author>
<creationDate>today</creationDate>
<description>MOD_HELLO_DESCRIPTION</description>
<namespace path="src">My\Module\Hello</namespace>
<files>
<folder module="mod_hello">services</folder>
<folder>src</folder>
<folder>tmpl</folder>
<folder>language</folder>
</files>
<scriptfile>script.php</scriptfile>
<media destination="mod_hello" folder="media">
<filename>joomla.asset.json</filename>
<folder>js</folder>
</media>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="header"
type="list"
label="MOD_HELLO_HEADER_LEVEL"
>
<option value="h3">MOD_HELLO_HEADER_LEVEL_3</option>
<option value="h4">MOD_HELLO_HEADER_LEVEL_4</option>
<option value="h5">MOD_HELLO_HEADER_LEVEL_5</option>
<option value="h6">MOD_HELLO_HEADER_LEVEL_6</option>
</field>
</fieldset>
</fields>
</config>
</extension>