这是很多读者期待的一个激动人心的时刻,从本篇起,本系列将分多集连续全面介绍Drupal系统的AJAX实现,在阅读前需要掌握一些必须的前置知识,请先阅读本系列以下主题:

《全局设置与前端API》

《jQuery表单库jquery.form.js详解》

此外需要读者熟悉jQuery,如果JS编程不熟悉,云客为你准备了以下教程:

《PHP开发者的JavaScript快速教程(phper简明js教程)》

Drupal AJAX概述:

AJAX是在不刷新整个页面的前提下,基于服务器端返回的数据动态更新页面中部分内容或JS变量的过程;在drupal世界中从开发角度看AJAX,可分为两大类:

自定义AJAX:

和通常项目一样的由开发者自定义前端js代码,再从后端拉取数据实现的AJAX,这要求开发者自定义资源库,为了方便通常会依赖核心jquery库,用jquery提供的诸多方法进行AJAX通讯;这一类AJAX灵活自由,可以实现开发者想要的任意功能,是一种任意项目通用的底层操作,而不局限于drupal,缺点是需要开发者处理所有细节,不够简单和便捷,即便一个小功能也需要实现自定义库。

Drupal AJAX API:

为弥补第一类的不足,系统提供了AJAX API,非常便捷、简单,无需写JS代码,只需要依据API的要求为要应用AJAX行为的元素指定一个AJAX配置即可,无需涉及底层细节,系统会自动完成AJAX功能,这是一种更高层级的封装,支持任意元素。

通常最常见的AJAX操作是从服务器拉取html片段并替换页面元素,但也有很多其他操作,比如依据服务器返回的数据更新某个js变量、弹出一个警告框、设置一个css属性、移除一个元素等等,Drupal将各种操作进行了统一,透过现象直达本质,在实现上,将不同种类的操作抽象成一个个不同的命令,每个命令由一个对应的js函数来完成该种操作,比如替换html就是一个“insert”命令,参数是替换的html片段以及如何替换、替换谁等;这样一来,后端仅需以json方式返回一个纯数据对象即可,对象中包含了命令的名字,以及完成命令需要的参数数据,在前端该对象称为AJAX命令对象,后端仅返回AJAX命令对象,且在一次AJAX请求中可以返回多个命令,从而一次性进行多种操作,关于命令会在后续主题详细解释。

API的缺点是如果系统提供的AJAX命令不能满足需求,那么需要新增命令,但很棒的是系统默认提供的命令足够丰富且扩展简单。

在设计上AJAX API主要用于以下元素:

渲染数组中具备“#ajax”属性的表单元素

具备“use-ajax”类属性的链接元素

具备“use-ajax-submit” 类属性的表单按钮

但这并不是说仅能用于这些元素,准确的说法是最常用于这些元素,AJAX API是可以用于任意元素的,见下文示例三的说明。

准备:

为演示本篇的示例,需要一个模块来运行相关代码,这里以“yunke_help”模块为列,该模块是本系列的配套模块,专门用于研究学习drupal,有非常多的辅助功能,请先到云客的博客下载安装,须注意这里只是为了起演示作用,并不依赖特定模块,以下以“yunke_help”模块来说明示例步骤。

示例一:在表单非提交元素上运用AJAX

目的:一个表单元素输入改变,从服务器获取数据联动改变其他元素

第一步:

建立文件:yunke_help/src/Form/YunkeForm.php

内容如下:

<?php
/*** 演示表单AJAX操作*/namespace Drupal\yunke_help\Form;use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;class YunkeForm extends FormBase
{public function getFormId(){return 'yunke_help_form';}public function buildForm(array $form, FormStateInterface $form_state){$form['content_one'] = ['#type'       => 'html_tag','#tag'        => 'div','#value'      => 'ajax获取的内容将显示在这里:','#attributes' => ['id' => 'content_one'],];$form['input'] = ['#type'        => 'textfield','#title'       => '任意输入字符:','#description' => '输入的内容将通过ajax发送到服务器','#size'        => '60','#ajax'        => ['callback' => '::yunkeTest','event'    => 'blur','wrapper'  => 'content_one','method'   => 'append','effect'   => 'slide','speed'    => 1000,'prevent'  => 'click','progress' => ['type'    => 'throbber','message' => '正在进行ajax...',],],];$form['#attributes']['target'] = "_blank";$form['actions']['#type'] = 'actions';$form['actions']['submit'] = array('#type'        => 'submit','#value'       => $this->t('Submit'),'#button_type' => 'primary',);return $form;}public function yunkeTest(array &$form, FormStateInterface $form_state){//\Drupal::messenger()->addStatus('AJAX消息测试'); //默认也会发生消息管理器中的内容$markup = '你的输入是:' . $form_state->getValue('input') . '<br>';return ['#markup' => $markup];}public function validateForm(array & $form, FormStateInterface $form_state){}public function submitForm(array & $form, FormStateInterface $form_state){$form_state->cleanValues();print_r($form_state->getValues());die;}
}

第二步:

然后在控制器:\Drupal\yunke_help\Controller\Test::test中执行以下代码:

return \Drupal::formBuilder()->getForm("\Drupal\yunke_help\Form\YunkeForm");

访问连接:http://www.你的域名.com/yunke-help/test

或点击“yunke_help”模块主页的测试按钮

说明:

在该例中关键在于表单元素的“#ajax”项设置,她为前端提供了一个AJAX配置,前端系统会据此为具备该属性的元素附加AJAX行为,AJAX配置可用的设置项及解释见下文的AJAX配置说明。

示例二:在dialog弹框显示链接内容

目的:点击页面中的链接,然后将链接内容通过AJAX获取后显示到页面dialog弹框中:

第一步:

先在控制器:\Drupal\yunke_help\Controller\Test::test_1中放入以下内容供AJAX获取:

        $msg = '<div>我是ajax获取的内容' . time() . '</div>';return array('#markup' => $msg,);

第二步:

然后在控制器:\Drupal\yunke_help\Controller\Test::test中执行以下示例代码:

$elements['#title'] = '示例二:用dialog显示链接目标';$url = \Drupal\Core\Url::fromUri('internal:/yunke-help/test-1');$elements['link'] = ['#type'       => 'link','#title'      => '点击本链接将以dialog方式打开','#url'        => $url,'#attributes' => ['class'            => ['use-ajax'],'data-dialog-type' => 'dialog',],];return $elements;

第三步:

这样就可以点击“yunke_help”模块主页的测试按钮查看示例效果了

说明:

该例没有像示例一那样用到“#ajax”属性,没有AJAX配置传递到前端,但是前端系统发现链接具备类属性“use-ajax”就会结合 “data-dialog-type” 属性、href属性自动产生AJAX配置并附加AJAX行为

示例三:点击链接后在任意位置显示

目的:示例二以dialog显示AJAX获取的内容,本例将获取的内容显示到特定的页面元素中

第一步:

示例二中控制器:\Drupal\yunke_help\Controller\Test::test_1中所放AJAX获取的内容不变

然后在控制器:\Drupal\yunke_help\Controller\Test::test中执行以下示例代码:

        $elements['#title'] = '示例三:在特定元素中显示链接目标';$elements['content_one'] = array('#type'       => 'html_tag','#tag'        => 'div','#value'      => '容器元素','#attributes' => ['id' => 'content_one'],);$url = \Drupal\Core\Url::fromUri('internal:/yunke-help/test-1');$elements['link'] = ['#type'       => 'link','#title'      => '点击本链接将在容器元素中呈现目标内容','#url'        => $url,'#attributes' => ['id' => 'yunkeID'],];$elements['link']['#attached']['drupalSettings']['ajax']['yunkeID'] = [ //以链接ID做键名'event'    => 'click','wrapper'  => 'content_one', //赋值容器元素ID,以使得显示位置指向容器元素'method'   => 'append','effect'   => 'slide','speed'    => 1000,'prevent'  => 'click','progress' => ['type'    => 'throbber','message' => '正在进行ajax...',],];$elements['link']['#attached']['drupalSettings']['ajaxTrustedUrl'][$url->toString()] = TRUE;$elements['link']['#attached']['library'][] = 'core/jquery.form';$elements['link']['#attached']['library'][] = 'core/drupal.ajax';return $elements;

第二步:

这样就可以点击“yunke_help”模块主页的测试按钮查看示例效果了

说明:

在该例中关键在于通过系统前端设置机制传递了一个AJAX配置,这以触发AJAX事件元素的id做键名(这里是yunkeID),键值是AJAX配置,该配置和示例一中的“#ajax”是一样的,实际上在内部,示例一中的“#ajax”也会被转化成这种形式,这里使用了更加底层的操作,由于没有采用自动处理,因此必须手动附加相关的库和可信AJAX请求链接设置

以示例三这种方法可以为任意前端元素指定AJAX行为,如图片、按钮、文字等等,只需要元素具备ID属性,并以ID属性值做AJAX配置的键名即可,但需要注意由于本例中触发AJAX的元素是一个链接元素(a标签),AJAX请求url可以被前端系统从链接上自动获取,因此可以省略,如果是其他元素,那么必须在配置中指定url项,其值必须是一个字符串值,不能是url对象,如果是url对象必须用“$url->toString()”进行转化

示例四:在任意元素上设置AJAX行为

目的:在任意元素上设置AJAX行为,并将结果显示在对话框中,这里以span元素为列

第一步:

前例控制器:\Drupal\yunke_help\Controller\Test::test_1中所放AJAX获取的内容不变

然后在控制器:\Drupal\yunke_help\Controller\Test::test中执行以下示例代码:

        $elements['#title'] = '示例四:任意元素触发AJAX,并在dialog中显示内容';$url = \Drupal\Core\Url::fromUri('internal:/yunke-help/test-1');$elements['span'] = ['#type'       => 'html_tag','#tag'        => 'span','#value'      => '点击这里将在dialog中呈现ajax内容','#attributes' => ['id' => 'yunkeID'],];$elements['link']['#attached']['drupalSettings']['ajax']['yunkeID'] = [ //以触发元素ID做键名'event'      => 'click','dialogType' => 'dialog', //该项使得显示位置在对话框中'url'        => $url->toString(),'method'     => 'append','effect'     => 'slide','speed'      => 1000,'prevent'    => 'click','progress'   => ['type'    => 'throbber','message' => '正在进行ajax...',],];$elements['link']['#attached']['drupalSettings']['ajaxTrustedUrl'][$url->toString()] = TRUE;$elements['link']['#attached']['library'][] = 'core/jquery.form';$elements['link']['#attached']['library'][] = 'core/drupal.ajax';return $elements;

第二步:

这样就可以点击“yunke_help”模块主页的测试按钮查看示例效果了

说明:

该例的目的是让读者明白drupal的AJAX API可以用于任意元素,这里仅以span元素的点击事件为例

示例五:通过AJAX提交表单

目的:在表单提交元素上设置AJAX行为,这将执行提交处理器,并将结果显示在特定位置

和示例一完全相同,仅将表单类替换如下:

<?php
/*** 演示表单AJAX操作*/namespace Drupal\yunke_help\Form;use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;class YunkeForm extends FormBase
{public function getFormId(){return 'yunke_help_form';}public function buildForm(array $form, FormStateInterface $form_state){$form['title'] = array('#type'    => 'textfield','#title'   => '标题,仅能输入数字','#pattern' => '[0-9]+',);$form['input'] = ['#type'  => 'textfield','#title' => '输入任意字符:','#id'    => 'yunkeID','#required' => TRUE,];$form['actions']['#type'] = 'actions';$form['actions']['content_one'] = [ //用于显示AJAX提交反馈'#type'       => 'html_tag','#tag'        => 'div','#attributes' => ['id' => 'content_one'],];$form['actions']['submit'] = array('#type'        => 'submit','#value'       => 'AJAX提交','#button_type' => 'primary','#ajax'        => ['callback'        => '::yunkeTest','event'           => 'click','disable-refocus' => true,'wrapper'         => 'content_one','method'          => 'html','effect'          => 'fade','speed'           => 1000,'prevent'         => 'click',//阻止非ajax提交,其实不需要这行,默认已阻止'progress'        => ['type'    => 'throbber','message' => '表单正在提交中...',],],);return $form;}public function yunkeTest(array &$form, FormStateInterface $form_state){/*//返回渲染数组,该方式将返回消息服务中的数据,以此显示错误if($errors=$form_state->getErrors()){return ['#markup' => '表单已成功提交'];}else{return ['#markup' => '提交失败,请检查错误'];}*///如果不想反回消息数据,则使用以下代码返回json响应:if ($errors = $form_state->getErrors()) {$message = ['提交失败,请检查错误:'];foreach ($errors as $error) {$message[] = $error;}//错误会沉积在消息系统中,体验不好故删除,但不要删除非表单错误的消息$errorMessages = \Drupal::messenger()->deleteByType('error');foreach ($errors as $key => $error) {$errors[$key] = (string)$error;//可能是翻译对象}foreach ($errorMessages as $key => $error) {if (!in_array((string)$error, $errors)) {\Drupal::messenger()->addMessage($error, 'error');}}} else {$message = ['表单已成功提交'];}$response = new \Drupal\Core\Ajax\AjaxResponse();$html = ['#markup' => implode('<br>', $message)];$command = new \Drupal\Core\Ajax\InsertCommand(NULL, $html);$response->addCommand($command);return $response;}public function validateForm(array & $form, FormStateInterface $form_state){if (empty($form_state->getValue('title'))) {$form_state->setErrorByName('title', '标题不能为空');}file_put_contents('yunkeAJAX.txt', __CLASS__ . "验证器\n", FILE_APPEND);//在根目录写入信息以便测试}public function submitForm(array & $form, FormStateInterface $form_state){file_put_contents('yunkeAJAX.txt', __CLASS__ . "提交器\n", FILE_APPEND);$form_state->cleanValues();$d = print_r($form_state->getValues(), true);file_put_contents('yunkeAJAX.txt', "提交内容\n:{$d}\n", FILE_APPEND);}
}

说明:

该列演示了在提交元素上采用“#ajax”属性设置表单ajax提交,这和示例一不同之处在于该列会执行提交处理器

示例六:

目的:在提交元素上采用类属性“use-ajax-submit”进行提交与显示

很遗憾,目前(V8.7,2019.7)系统在该功能上存在BUG,如下:

1、在该种情况下,系统本应自动添加“core/jquery.form”和“core/drupal.ajax”库,但其并没有,该bug已经被社区成员提交,现处于修复阶段

2、在该种情况下,提交处理器需在表单状态对象中设置一个ajax响应,这在成功提交的情况下将工作的很好,但是如果验证失败(此时不会执行提交处理器),控制器将返回表单数组,接着由AJAX主内容渲染器将其渲染成AJAX响应,由于该响应中,insert命令缺乏指向错误显示元素的选择器,因此页面并不显示错误,这虽然可以在验证器中将表单数组的元素类型设置成“ajax”以在前端通过警告框进行错误提示,但显然这并不优雅

由于以上bug尚未修复,建议目前以示例五代替

AJAX配置:

AJAX配置是前端系统所需的用来为页面元素设置一个AJAX行为的信息(在下集原理篇中会有更深入的体会),在后端以数组形式存在,在前端以数据对象形式存在,通常通过JS配置设置机制传递到前端全局变量drupalSettings中,但有些情况为了更加便捷,系统支持部分元素只需要设置少许属性即可实现AJAX,此时不需要传递AJAX配置,典型的是设置了类属性“use-ajax”的链接和设置了类属性“use-ajax-submit”的表单按钮,前端系统会为它们自动产生AJAX配置并设置AJAX行为。

从系统流程角度看,AJAX配置在系统中有三种存在形式(或存在位置):

元素“#ajax”属性值:

也就是元素渲染数组的“#ajax”属性值,需要注意的是并不是所有元素都能使用“#ajax”属性,仅在渲染过程中能调用到以下方法的元素才可以:

\Drupal\Core\Render\Element\RenderElement::preRenderAjaxForm

这通常是表单元素,该方法会将“#ajax”属性值处理成JS设置中的AJAX配置后传递到前端(准确说是传递到附属物中)

JS设置值:

在后端这也称为位于渲染附属物中,也就是渲染数组中以下项的值:

$element ['#attached']['drupalSettings']['ajax']['元素ID']

渲染数组的$element ['#attached']['drupalSettings']用于给前端传递设置信息,位于这里的AJAX配置称为标准AJAX配置,或最终AJAX配置,不会再被处理,将直接传递给前端,在前端位于以下全局变量中:

drupalSettings.ajax.元素ID

注意:以JS设置值这种方式直接传递AJAX配置,看起来更加底层,但并不能完全代替表单元素的“#ajax”属性值方式传递,主要原因在于回调参数并不通过前端传递,在内部系统会先找到触发元素,再通过其:['#ajax']['callback']属性找到回调,这种机制要求回调仅设置在“#ajax”属性中

前端自动产生:

为一些特殊元素设置AJAX行为时,由前端自动产生,如前文提到的设置了类属性“use-ajax”的链接和设置了类属性“use-ajax-submit”的表单按钮

AJAX配置项说明:

AJAX配置可用键名及其解释如下(部分选项根据存在位置不同,可能会有所不同):

callback:

表单AJAX请求时服务器端的回调,仅用于表单元素,且仅用于表单元素的“#ajax”属性中,在该属性中是必须的,用在JS设置值的AJAX配置中无效(因为该项并不通过前端传递),和设置提交处理器或验证器方法一样,如“::yunkeTest”,可以是任意有效php回调,按次序接收三个参数:&$form、$form_state和请求对象,可以用他们获取用户当前的输入,回调应该返回渲染数组,字符串需用['#markup' => $markup]包装成渲染数组,此时除返回值外,消息管理器(\Drupal::messenger())中的全部内容也会被返回;回调也可以返回json响应对象:

\Drupal\Core\Ajax\AjaxResponse

此时不会自动返回消息管理器中的内容,但可以明确通过命令的方式添加。

注意:回调在表单流程之后执行,如果AJAX用在非提交元素中,在回调执行前,表单验证器会执行,但验证错误被镇压,提交处理器不会被执行,如果用在提交元素中,验证器会执行,错误不会镇压,验证通过时提交器已执行,提交器返回的响应被忽略,最后执行回调,响应以回调的返回值为准

url:

AJAX请求地址,如果AJAX配置是在#ajax属性中指定,那么表明元素是表单元素,那么该项可以省略,内部会采用当前表单地址,如果不省略的话,则必须是url对象(\Drupal\Core\Url),如果AJAX配置是在附属物中指定,那么该项是必须的,且必须是一个字符串值,在前端以此项作为AJAX请求地址,并不关注callback

options:

仅当AJAX配置是在#ajax属性中指定时才有用,在url为url对象时,用于url对象的选项参数,在附属物中,AJAX配置的url项已经被转变成字符串,此时该项已经不需要存在了

wrapper:

在AJAX请求返回html内容时,用来放置内容的元素的id属性值,将来会用“selector”代替,以便可使用任意选择器来指定元素,目前只支持id,注意其值不要有“#”前缀

dialogType:

可选值为dialog、modal,表示以这些方式之一显示AJAX内容,优先级高于wrapper,在渲染数组的“#ajax”属性中设置无效,因为内部实际上据此包装格式会有不同的主内容渲染器,而“#ajax”属性仅支持AJAX主内容渲染器

method:

在使用wrapper 放置内容时,采用的jQuery放置方法,可选值有:replaceWith(替换整个id元素,这是默认值)、html(替换子内容)、append(在里面尾部追加)、prepend(在里面头部追加)、before(在外部前面追加)、after(在外面后面追加)

effect:

在放置内容时,采用的jQuery动画效果,可选值有:none (默认值,无效果)、slide(下拉显示)、fade(慢慢淡出)

speed:

在使用放置动画时的动画速度,可选值有:slow(慢)、fast(快)、none(默认值,jQuery默认速度)或者一个以毫秒为单位的数字

event:

在该元素上触发AJAX的js事件(后称AJAX事件),有默认值时是可选的,默认会依据表单元素的类型自动选择,见下文,如果提供了值将以提供值为准,如果没有默认值则必须指定,不带on前缀,如change、keyup、input等,当有多个时使用空格分隔,最终将传递给jquery的on方法,可带名字空间

prevent:

当触发AJAX的js事件发生时要阻止的其他事件,比如触发事件是mousedown,此时你可能会想阻止click事件,当有多个时使用空格分隔,最终将传递给jquery的on方法,可带名字空间,事件传播和默认动作都会被阻止;可与AJAX事件相同,不会影响AJAX,仅会阻止该事件的传播和默认动作,但这没有必要,因为AJAX行为默认会阻止事件的传播和默认动作

progress:

用于配置进度指示器,当不需要显示进度指示时,可以设置为false,一个数组值,各子键为:

type:进度指示器的类型,可选值有:throbber(在元素后边显示一个转圈的等待动画图片,默认值)、bar(结合其他选项以进度条方式显示)、fullscreen(全屏居中显示一个等待动画图标)、false(禁用指示器,布尔值)

message:提示消息,字符串值,如“请稍后…”,应该是被翻译过的,默认为Drupal.t('Please wait...')

url:使用进度条时,获取进度数据的url,字符串值,在#ajax属性中也可以是url对象

method:请求进度条更新url时使用的http方法,get或post,默认为get

interval:使用进度条时,多长时间更新一次,单位毫秒,默认1500毫秒

当数组中仅有type时,该项可简写为type表示的字符串值

disable-refocus:

布尔值,指示ajax调用后,是否禁止重新获得焦点,默认为false,也就是会重新获得焦点,很多时候需要被设置为true,否则焦点会被反复拉回到元素导致用户无法使用

keypress:

布尔值,是否在元素上监听键盘事件,以便可以通过按压空格或回车键触发AJAX事件,默认为true,将在元素上监听“keypress”事件,注意有四种类型的表单元素:text、textarea、tel、number即便设置了该项,也不会通过空格触发AJAX事件,但回车可以

submit:

额外提交到服务器的数据,一个数组值,键名为name,键值为value;前端系统默认的并不会设置是哪一个元素触发了ajax请求(也可以理解成不会设置是哪个元素触发了表单AJAX提交),如果AJAX配置是在#ajax属性中指定,为了告诉后端触发元素,系统在该项添加了以下变量:

_triggering_element_name:触发元素名

_triggering_element_value:触发元素值,可选

如果AJAX配置是在附属物中指定,需要用户来设定触发元素,如果没有设置,那么后端在不知道触发元素的情况,会以第一个按钮元素当做触发元素

trigger_as:

是一个数组,用于指定一个表单提交元素(让后端知道是哪个元素触发了表单提交),键名name为触发元素名,value为触发元素值,该项是可选的,默认以本元素的name和value作为触发元素名和值,仅在#ajax属性中有效,该项在附属物中的AJAX配置里会被删除(信息已经提取到submit项中)

setClick:

布尔值,仅用于表单提交元素,如提交按钮,指示将当前元素当做触发表单提交的元素,并传递其名值到服务器,在内部普通表单元素该项默认为false,使用“.use-ajax-submit”类的表单元素默认为true ,因为普通表单元素本就会被传递,且“.use-ajax-submit”类的表单元素会自动设置为true,因此该项用户无需理会,这里列出仅供程序研究参考,注:不要将该项和trigger_as项混淆,任何表单元素的AJAX操作都会提交整个表单,trigger_as项常用在当前元素为非提交元素时,指定提交元素,而该项仅用于提交元素,如按钮,指示是否将本元素当做提交元素,当发生冲突时,该项优先级高于trigger_as项。

AJAX配置默认事件:

在没有指定事件名时,以下元素类型(渲染数组类型)将采用默认事件:

submit、button、image_button

默认事件名:mousedown,同时在没有设置阻止事情的情况下阻止click事件

password、textfield、number、tel、textarea

默认事件名:blur

radio、checkbox、select、date

默认事件名:change

link

默认事件名:click

注意:除以上这些元素类型外,其他元素类型必须设置事件名,否则不被设置ajax行为

官网参考文档:

AJAX API概述:

https://api.drupal.org/api/drupal/core!core.api.php/group/ajax/

创建Ajax菜单链接:

https://www.drupal.org/docs/8/api/menu-api/making-ajax-menu-links

AJAX表单示例:

https://www.drupal.org/docs/8/api/javascript-api/ajax-forms

命令:

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Ajax%21CommandInterface.php/interface/implements/CommandInterface

补充:

1、如果在具备#ajax属性的元素上设置#ajax_processed,那么不论何值(NULL除外),只要设置了,那么就不会被附加AJAX行为,相当于没有给元素添加#ajax属性,调试时比较有用,被附加#ajax的元素处理后,会附加该属性,值为true。

2、在AJAX API中表单元素的AJAX操作总是提交整个表单值到后端,所有AJAX均以POST方式发起

我是云客,【云游天下,做客四方】,联系方式见主页,欢迎转载,但须注明出处

云客Drupal源码分析之系统AJAX(一):概述与示例相关推荐

  1. 云客Drupal源码分析之系统AJAX(二):前端原理

    前端概述: drupal AJAX API前端系统主要是指核心库:core/drupal.ajax,下文简称AJAX库,前端AJAX行为均由该库完成,她主要依赖以下几个重要的库: jquery库cor ...

  2. 云客Drupal源码分析之配置系统Configuration(一)

    各位<云客drupal源码分析>系列的读者: 本系列一直以每周一篇的速度进行博客原创更新,希望帮助大家理解drupal8底层原理,并缩短学习时间,但自<插件系统(上)>主题开始 ...

  3. 云客Drupal源码分析之国际化Internationalization:核心翻译系统

    各位<云客drupal源码分析>系列的读者: 本系列一直以每周一篇的速度进行博客原创更新,希望帮助大家理解drupal底层原理,并缩短学习时间,但自<插件系统(上)>主题开始博 ...

  4. 云客Drupal源码分析之插件系统(上)

    各位<云客drupal源码分析>系列的读者: 本系列一直以每周一篇的速度进行博客原创更新,希望帮助大家理解drupal底层原理,并缩短学习时间,但自<插件系统(上)>主题开始博 ...

  5. 云客Drupal源码分析之Session进阶

    在本系列之前写过<云客Drupal源码分析之Session系统>,但那部分仅仅讲到了drupal会话的基础:Symfony的Session组件 至于drupal怎么去使用这个基础就是本主题 ...

  6. 云客Drupal源码分析之类型化数据Typed Data API

    各位<云客drupal源码分析>系列的读者: 本系列一直以每周一篇的速度进行博客原创更新,希望帮助大家理解drupal底层原理,并缩短学习时间,但自<插件系统(上)>主题开始博 ...

  7. 云客Drupal源码分析之前端js中的翻译

    从本主题开始<云客Drupal源码分析>系列将连续发布和前端js相关的内容,如果您对JavaScript还不熟悉或者需要来一次系统性的整理回顾,在此云客为您准备了以下资料: <PHP ...

  8. 云客Drupal源码分析之前言

    Drupal是一个非常优秀的网站系统,可以说她是一个网站应用开发框架,也可以说是一个cms,她在世界范围内被广泛使用,最为人所知的是美国白宫.联合国等知名机构的官方网站使用了她,随着Drupal8的来 ...

  9. 云客Drupal源码分析之实体表单显示EntityFormDisplay

    以下内容仅是一个预览,完整内容请见文尾: 实体的显示分为表单显示和视图显示,前者用于不同情况下的信息输入,后者用于不同情况下的信息展示,本篇很多内容不止用于本篇所讲的表单主题,也是学习drupal视图 ...

最新文章

  1. E20180525-hm
  2. 健身环爆打老头环!超高难度击败boss,宫崎英高估计也想不到,代码+硬件教程已开源...
  3. Java中Socket通信-客户端与服务端相互传输对象数据
  4. html5中音乐播放器怎么写,打造属于自己的音乐播放器 HTML5之audio标签
  5. 只有ajax会跨域吗_为什么跨域Ajax是安全问题?
  6. 敏捷个人学习----为什么的力量
  7. vmware安装报错及注册时无权输入许可证密钥的解决办法及步骤
  8. 【问题描述】3.2.6 中国余数定理:“有物不知几何,三三数余一,五五数余二,七七数余三,问:物有几何?”。编程求1~1000以内所有解。
  9. Activiti学习之根据条件判断流程走向
  10. 深眸分享——一文看懂倍频器的原理及其应用
  11. CERC2017 F-Faulty Factorial【数论】
  12. Buoyant的Conduit服务网格正式成为Linkerd 2
  13. 接着外挂教程 VB 从零开始编外挂
  14. Java实现字符串反转的几种方法
  15. 【上】CS229 吴恩达机器学习 习题作业答案 problem sets 03 PS03(全部问题解答,欢迎各位前辈指教)
  16. 用户权限控制(Token登录)
  17. 【OpenCV入门到精通之九】OpenCV之视频截取、图片与视频互转
  18. windows-sys5:升级win11——此版本Windws不支持该处理器、该电脑必须支持TPM2.0等问题解决
  19. Windows运行单个.bat文件或运行多个.bat文件
  20. ik php分词,IK中文分词的配置和使用

热门文章

  1. 计算机 英语折算学分规定,泰州学院奖励学分制度实施细则
  2. vue+springboot文件预览
  3. 设计模式 - 适应设计模式 - Iterator模式(一)
  4. 基于nodejs+vue的高校作业布置批改管理系统
  5. 计算机软件3dmax在展览中的研究,博物馆3D扫描技术的应用及前景
  6. seata - 实现xid跨服务传递 - fegin
  7. 一体化Ethercat通信伺服电机在汇川H5U PLC上的应用案例介绍(下)
  8. Cisco系列AP指示灯(LED)解读
  9. RTSP直播延时的深度优化
  10. 人工智能技术为教育带来什么?