121. 系统AJAX(四):命令
在drupal AJAX api中,AJAX请求获取的数据均是以“命令”方式在页面中进行更新,命令由两部分核心内容组成:执行更新的JS函数、函数操作所需的数据(参数),实现命令概念需要前后端配合。
命令概述:
在前端:
一条命令就是一个对象,称为命令对象,是一个纯js数据对象,该对象必须存在属性:command,她的值是命令名,命令名是一个js函数的函数名,该函数称为命令函数,必须存在于以下前端全局变量中:
Drupal.AjaxCommands.prototype
如果不存在,那么命令是无效的,命令对象的其他属性属于命令携带的数据,根据命令不同而不同。
所有命令函数均按序接受三个参数:AJAX对象、命令对象、状态信息,AJAX结果动作由命令函数完成
在后端:
每一个AJAX命令由一个类表示,这些类均需要实现以下接口:
\Drupal\Core\Ajax\CommandInterface
该接口仅有一个render()方法,用于返回一个命令数组,该数组将被序列化成json字符串,传递到前端后就是前文所述的命令对象
同样的,命令也可以传递附属物(资源库、配置变量),这样的命令需要实现以下接口:
\Drupal\Core\Ajax\CommandWithAttachedAssetsInterface
在实现上可以直接使用以下特征:
\Drupal\Core\Ajax\CommandWithAttachedAssetsTrait
命令由以下AJAX响应对象传递到前端:
\Drupal\Core\Ajax\AjaxResponse
一次AJAX请求可以传递多个命令,通过该AJAX响应对象的以下方法添加:
public function addCommand(CommandInterface $command, $prepend = FALSE)
参数$command为命令对象,添加顺序就是前端执行命令的顺序,如果需要后添加但先执行,那么需要将参数$prepend设置为true
如果后端传递的命令,在前端不支持将是没有用的,接下来我们看一看系统默认提供了哪些命令。
插入命令insert:
命令名:insert,用于向页面插入html内容
在前端:
前端方法:Drupal.AjaxCommands.prototype.insert(ajax, response)
(前文已讲了所有js命令函数按序接收三个参数:AJAX对象、命令对象、状态信息,因此此处及下文不再解释命令函数的参数含义)
响应对象除包含command属性外(值为insert,下文所有命令均包含该属性,仅值不同,将不再赘述),还有以下属性:
selector:可选,执行插入操作的目标元素的jquery选择器,字符串值,含义等同AJAX配置中的wrapper项,但优先级更高
method:可选,插入所用的方法,含义等同AJAX配置中的method项,但优先级更高
effect:可选,插入或替换动画效果,含义等同AJAX配置中的effect项,但优先级更高
speed:可选,插入或替换动画速度,含义等同AJAX配置中的speed项,但优先级更高
data:必选,字符串值,通常是要插入的html片段,里面如包含JS,会被执行,当使用empty方法时该项被忽视,此时可以是空字符串
settings:可选,一个设置对象,当成功插入DOM后,用于对插入的各根元素执行Drupal.attachBehaviors,这允许其他组件为其添加js事件,当有元素移除时(插入是替换操作),用于Drupal.detachBehaviors方法;优先级最高,其次是AJAX配置中的settings项,最后是drupalSettings
在后端:
插入命令类:\Drupal\Core\Ajax\InsertCommand
使用示例:
$ajaxResponse = new \Drupal\Core\Ajax\AjaxResponse();
$html = ['#markup' => '示例'];
$command = new \Drupal\Core\Ajax\InsertCommand(NULL, $html);
$ajaxResponse->addCommand($command);
return $ajaxResponse;
该命令的构造函数接收三个参数:
$selector:执行插入操作的目标元素的jquery选择器,字符串值,见前文
$content:可以是一个渲染数组,或html字符串片段,当是渲染数组时附属物会自动处理
$settings:js设置数组,见前文的js设置对象
该命令无法直接指定插入方法,当客户端Ajax对象指定了方法时,这样很好,如需指定方法用以下类代替:
在外部前面追加插入:
\Drupal\Core\Ajax\BeforeCommand
在外面后面追加插入:
\Drupal\Core\Ajax\AfterCommand
在里面头部追加插入:
\Drupal\Core\Ajax\PrependCommand
在里面尾部追加插入:
\Drupal\Core\Ajax\AppendCommand
整个元素替换插入:
\Drupal\Core\Ajax\ReplaceCommand
替换全部子内容插入:
\Drupal\Core\Ajax\HtmlCommand
以上这些类全部继承插入类,实例化方法也一样,仅仅方法不同而已
移除命令remove:
命令名:remove,用于移除页面元素
在前端:
前端方法:Drupal.AjaxCommands.prototype.remove(ajax, response, status);
响应对象必须包含selector属性,字符串值,jquery选择器,指示要移除的元素,否则命令无效,可选的传递settings属性,用于移除时,对各元素执行Drupal.detachBehaviors方法
在后端:
命令类:\Drupal\Core\Ajax\RemoveCommand
构造函数仅接收一个字符串值的jquery选择器做参数
标记改变命令changed:
命令名:changed,用于标记一个元素被更改,而不是更改一个元素
在前端:
前端方法:Drupal.AjaxCommands.prototype.changed(ajax, response, status)
响应对象必须包含selector属性,字符串值,jquery选择器,指示哪个元素要被标记为已更改,否则命令无效,可选的传递asterisk属性,也是一个jquery选择器,应是selector所指元素的子元素,如果指定了将在该元素内追加一个星号标记
在后端:
命令类:\Drupal\Core\Ajax\ChangedCommand
构造函数接收两个参数:
$selector:必选,一个字符串值的jquery选择器
$asterisk:可选,一个字符串值的jquery选择器
警告弹框命令alert:
命令名:alert,用于通过alert方法弹出警告框
在前端:
前端方法:Drupal.AjaxCommands.prototype.alert(ajax, response, status);
响应对象包含两个属性,text弹框内容,title弹框标题(bug:该参数是无意义的)
在后端:
命令类:\Drupal\Core\Ajax\AlertCommand
构造函数仅接收一个字符串值参数做弹框内容
无障碍消息通知命令announce:
命令名:announce,用于向残障设备发送消息通知,详见前端Drupal.announce方法
在前端:
前端方法:Drupal.AjaxCommands.prototype.announce(ajax, response);
响应对象包含两个属性:
text:被通知的消息
priority:可选值,优先级
在后端:
命令类:\Drupal\Core\Ajax\AnnounceCommand
构造函数按序参数为:$text, $priority = NULL,该命令会加载核心库:core/drupal.announce
重定向页面命令redirect:
命令名:redirect,用于将页面跳转到指定的url地址
在前端:
前端方法:Drupal.AjaxCommands.prototype.redirect(ajax, response, status);
响应对象包含一个属性,url重定向地址,将赋值给window.location以实现重定向
在后端:
命令类:\Drupal\Core\Ajax\RedirectCommand
构造函数仅接收一个字符串值的url参数做重定向
CSS样式修改命令css:
命令名:css,用于执行jquery的css方法修改元素样式
在前端:
前端方法:Drupal.AjaxCommands.prototype.css(ajax, response, status);
响应对象包含两个属性:
selector:要运用样式的元素的选择器
argument:jquery的css方法的参数
在后端:
命令类:\Drupal\Core\Ajax\CssCommand
构造函数按序参数为:$selector, array $css = []
js配置命令settings:
命令名:settings,用于为其他命令设置配置对象或修改全局配置对象drupalSettings
在前端:
前端方法:Drupal.AjaxCommands.prototype.settings(ajax, response, status);
响应对象包含两个属性:
settings:一个配置对象
merge:布尔值,如果为true,那么将把settings配置对象深度递归合并到全局配置对象drupalSettings中,否则将把配置对象赋值给Ajax对象的settings属性,以供该Ajax对象上的其他命令使用,比如插入命令就用到了该配置对象(这使得在AJAX请求后可以设置新的AJAX行为)。
该命令还会将已经失效的AJAX配置从全局配置:drupalSettings.ajax中删除
在后端:
命令类:\Drupal\Core\Ajax\SettingsCommand
构造函数按序参数为:array $settings, $merge = FALSE,
数据设置命令data:
命令名:data,用于通过jquery的data方法为元素设置数据
在前端:
前端方法:Drupal.AjaxCommands.prototype.data(ajax, response, status);
响应对象包含三个属性:
selector:被附加数据的元素的jquery选择器
name:数据键名
value:数据键值
在后端:
命令类:\Drupal\Core\Ajax\DataCommand
构造函数按序参数为:$selector, $name, $value
jquery方法执行命令invoke:
命令名:invoke,用于在jquery对象上执行一个jquery方法
在前端:
前端方法:Drupal.AjaxCommands.prototype.invoke(ajax, response, status);
响应对象包含三个属性:
selector:选择器字符串,将在该选择器产生的jquery对象上执行jquery方法
method:任意有效的jquery方法
args:方法所需的参数,是一个数据对象,将通过“…”运算符展开后传递给方法
在后端:
命令类:\Drupal\Core\Ajax\InvokeCommand
构造函数按序参数为:$selector, $method, array $arguments = []
重构表命令restripe:
命令名:restripe,用于给表中的行重新设置奇偶数类名(odd、even)
在前端:
前端方法:Drupal.AjaxCommands.prototype.restripe(ajax, response, status);
响应对象包含一个属性:
selector:选择器字符串,将作用在该选择器指定的元素的子元素上
在后端:
命令类:\Drupal\Core\Ajax\RestripeCommand
构造函数仅接收一个字符串值的jquery选择器参数
更新表单id命令update_build_id:
命令名:update_build_id,用于更新表单id的值
在前端:
前端方法:Drupal.AjaxCommands.prototype.update_build_id(ajax, response, status);
响应对象包含两个属性:
old:旧表单id值
new:新表单id值
在后端:
命令类:\Drupal\Core\Ajax\UpdateBuildIdCommand
构造函数按序参数为:$old, $new
CSS文件或标签加载命令add_css:
命令名:add_css,用于加载一个css样式表文件或<style>标签到页面,这不同于“css”命令,后者仅修改一个样式属性
在前端:
前端方法:Drupal.AjaxCommands.prototype.add_css(ajax, response, status);
响应对象包含一个属性:
data:字符串值的html片段,可以是一个加载css文件的link标签,也可以是一个<style>标签,将通过prepend方法(里面、前面)追加到head标签中,预追加操作意味着添加的样式优先级是很低的,样式标签中的@import将得到处理
在后端:
命令类:\Drupal\Core\Ajax\AddCssCommand
构造函数仅接收一个字符串值的$styles参数,含义同data
自定义命令:
如果系统默认提供的命令不能满足需求,那么可以自定义,一个命令需要前后端配合执行,缺一不可,因此需要在前后端均进行扩展:
在前端:
向以下全局变量添加命令函数:
Drupal.AjaxCommands.prototype
函数名必须和命令名相同,由此也可看出命令名必须满足js函数名要求,接收以下参数:
AJAX对象、命令对象、状态信息
该函数在前端执行js动作,通过命令对象的属性获取后端传递的数据
在后端:
实现一个命令类,必须实现以下接口:
\Drupal\Core\Ajax\CommandInterface
类名随意,最佳实践是以命令名的驼峰命名法加“Command”做后缀,在方法render()中返回一个数组,其中必须存在键名:command,其对应的键值为命令名,可选的传递其他代表命令所需数据的数组元素(注意:这不是js命令函数的参数),在前端该数组键名将作为命令对象的属性名
如果命令有附属物需要处理,还应实现以下接口:
\Drupal\Core\Ajax\CommandWithAttachedAssetsInterface
此时可以使用以下特征:
\Drupal\Core\Ajax\CommandWithAttachedAssetsTrait
补充:
1、后端提供了基础命令类:\Drupal\Core\Ajax\BaseCommand,可以指定命令名和数据,有时会很有用
2、关于dialog、modal主内容渲染器、相关AJAX命令、前端实现将在专门的主题中讲解