“中国要复兴、富强,必须在开源软件领域起到主导作用,为了国家安全和人类发展,责无旁贷,我们须为此而奋斗”——By:云客
由于drupal前端js内容庞大,本系列将分多个主题逐个讲述较常用和较重要的前端资源库,并以序号进行标识,推荐按序号阅读
前言:
在开始前端js探索前有一些注意事项:
ES6升级:
从Drupal8.4开始核心使用ES6开发js程序,但为每个ES6版本的js文件都添加了自动转码的ES5版本文件,因此我们在查看源代码时应该查看ES6版本(也就是.es6.js后缀的文件),里面有开发者清晰的注释说明,ES5版本的js是依据ES6版本自动转码生成的,注释均被去除了,在使用上目前依然使用ES5版本的js
JS代码风格:
在Drupal中js程序采用airbnb编码风格,参看地址:
https://github.com/airbnb/javascript
也可以查看drupal官网上对代码风格的介绍:
https://www.drupal.org/docs/develop/standards/javascript
drupal使用ESLint来检查代码风格,ESLint 是一个js代码规范和错误检查工具,官网地址为:
https://cn.eslint.org/
在核心目录下存放了ESLint的配置文件,drupal以前的js编码风格存放在“.eslintrc.legacy.json”配置中,现在推荐的风格保存在“.eslintrc.json”中
准备:
如果你还不清楚后端是怎么处理js文件的,请参考本系列以下主题:
《资源库assets library详解》
《响应附属处理attachments_processor》
《资源解析器AssetResolver》
如果你需要整理补充自己的js知识体系,云客为你准备了以下资料:
《PHP开发者的JavaScript快速文档》
核心库core/drupalSettings:
用于后端向前端提供js设置信息,渲染数组的“$render_array['#attached']['drupalSettings']”键和资源库的“drupalSettings”键用于在后端保存将传递到前端的js设置信息,在最终页面上设置信息将被合并,并以json方式保存到前端的如下标签中:
<script type="application/json" data-drupal-selector="drupal-settings-json"></script>
该标签称为js设置保存标签,后端模块可以通过以下钩子向页面提供js设置数据:
hook_js_settings_build(&$settings, $assets);
hook_js_settings_alter(array &$settings, \Drupal\Core\Asset\AttachedAssetsInterface $assets)
详见本系列《资源解析器AssetResolver》,对应类:\Drupal\Core\Asset\AssetResolver::getJsAssets
渲染数组提供的设置优先级高于资源库。“core/drupalSettings”库仅有一个js文件:
/core/misc/drupalSettingsLoader.js
该文件读取上文js设置保存标签的内容并在window对象上建立一个全局变量:drupalSettings,前端任何依赖“core/drupalSettings” 库的js都可以访问全局变量drupalSettings获得配置信息,不管在head还是在body中加载“core/drupalSettings”库,设置标签总是出现在其前,该库也总是出现在依赖她的库前,如果js需要使用设置功能,必须声明依赖“core/drupalSettings”库,该库本身提供了一些设置信息:
path:
baseUrl:值为$request->getBaseUrl() . '/'
scriptPath:脚本路径
pathPrefix:路径前缀
currentPath:当前路径
currentPathIsAdmin:当前路径是否为管理路径
isFront:当前页是否为首页
currentLanguage:当前语言的语言代码
currentQuery:当前查询参数,如果存在才有
pluralDelimiter:复数字符串的分隔符"\03";
ajaxPageState:
theme_token:保护令牌,仅在当前主题不是默认主题时存在
theme:当前主题机器名
libraries:已被加载的库集的最小表示(集合中被其他库依赖的库不存在)
这些设置信息由system_js_settings_alter()负责初始化,其他模块提供的比较常用的设置有:
user.uid:当前用户id
user.permissionsHash:当前用户权限哈希
editor:编辑器配置
该库仅一个js文件:
/core/assets/vendor/domready/ready.min.js
用于在文档加载完成后(派发DOMContentLoaded事件时)自动执行回调:
domready(fn);
参数fn是用于执行的回调,该库添加了一个全局(window对象的属性)函数domready用于添加回调,可反复调用以添加多个需要文档就绪后执行的回调,添加的异步回调在事件循环中属于宏任务,在已经就绪后调用该函数添加的回调,将立即放入事件列队
系统JS的API,依赖于设置和core/domready,有两个js文件:
文件一:/core/misc/drupal.js:
整个文件在运行一个闭包,其中参数window.drupalTranslations来自翻译数据文件,详见本系列《前端js中的翻译》篇,参数window.drupalSettings是后端提供的设置数据;该文件定义了一个全局变量Drupal,用作名字空间,全部drupal提供的前端API接口函数被定义在该变量下,但该文件并没有包含全部API接口,因为部分API是可选加载的,比如进度条、Ajax等,这些可选组件定义的接口也在全局变量Drupal上,只在加载后才可用;该文件定义的API接口函数如下:
Drupal.throwError(error)
以异步方式抛出错误,方便调试,这种方式不会中断当前列队任务的执行
Drupal.formatString(str, args);
格式化一个字符串,字符串中可以包含占位参数,占位参数的值在args中传递,args是一个对象,属性值代表要替换占位参数的值,属性名的第一个字符有特殊含义:
如果是“@”那么意指属性值是一个原始文本,里面不会存在标签,将先进行html转义处理后再替换
如果是“!”那么代表属性值是安全的,将直接替换
如果既不是“@”也不是“!”,那么将先进行html转义并放入“<em class="placeholder"></em>”中再替换
将字符串参数中的“&”、“<”、“>”以及单双引号全部替换为html实体(&、<,>、',")后返回
Drupal.stringReplace(str, args, keys):
用参数替换字符串中的占位符后返回,参数str是包含占位符的字符串,参数args是一个对象,属性名为占位符,属性值为要替换的值,参数keys可以指定仅替换哪些占位符,以数组方式列出占位符,如果要替换args中的全部参数可以指定为非数组值,比如null
Drupal.t(str, args, options):
返回单数翻译,str为要翻译的字符串,args为可选翻译参数,options为选项参数,其属性仅context可使用,以指定翻译上下文;在使用该函数时参数尽量以字面量方式使用,而不要使用变量,这是为了让后端从js文件中提取翻译源字符串和上下文,详见本系列《前端js中的翻译》篇
Drupal.formatPlural(count, singular, plural, args, options):
复数翻译,参数count代表传递的数量,参数singular代表单数时的字符串,参数plural代表复数时的字符串,参数args代表需要替换的额外占位符,参数options代表选项,其属性仅context可用,以指定翻译上下文,该方法内部使用单数翻译方法,同理参数尽量使用字面量方式。
典型的用于传递一个路由中的路径,然后返回一个完整的drupal路径,该方法可以让调用者不用考虑语言前缀、协议等问题,这些自动添加到返回路径中,如Drupal.url('node/36');将返回“/zh-hans/node/36”,注意传递的路径不要以“/”开头
Drupal.url.toAbsolute(url):
传递一个不带协议、主机的路径,返回一个带协议的绝对路径,该方法的协议和主机来自当前页面,如果传递的路径以“/”开始,那么会在其前追加协议和主机(此情况不会考虑语言前缀等,此时可与Drupal.url(path)组合使用),如果不以“/”开始,那么返回的绝对路径是相对于当前页面的路径,假设当前页面为:
http://www.dp.com/zh-hans/node/36
Drupal.url.toAbsolute('/node/36');返回:
http://www.dp.com/node/36
Drupal.url.toAbsolute('node/36');返回:
http://www.dp.com/zh-hans/node/node/36
如果传递带协议的绝对路径将原封不动返回
Drupal.url.isLocal(url):
判断一个url是否为本站的地址,返回布尔值,true代表是,参数可以是绝对路径,也可以是非绝对路径,https和http视为同一个站,其他协议将返回false
Drupal.encodePath(item):
用于对url的组成部分进行编码(不是对整个url编码),内部采用encodeURIComponent方法,但不对“/”编码,注意和encodeURI()的区别,后者是对整个url编码,前者仅对url的各组成部分编码,因此前者会编码url各组成部分之间的分隔符,如冒号、正斜杠、问号和井字号。
Drupal.theme(func, ...args):
用于输出一些有固定特征内容的格式化字符串,通常是一些标签块,这称为主体化输出,如进度条标签、占位符标签等等;这是一个路由方法,参数func应该是Drupal.theme对象的一个函数类型的属性的属性名,意为调用这个属性函数并将随后的参数传递给它,最后返回该属性函数的返回值
Drupal.theme.placeholder(str):
将传递的字符串进行html转义后包装在“<em class="placeholder"></em>”中返回
用于全局保存行为对象,其属性是行为对象behavior,行为是指页面元素上事件触发的动作,每个行为对象可选的有一个附加行为方法(attach属性)或分离行为方法(detach属性),也就是:
“Drupal.behaviors.behavior.attach”
“Drupal.behaviors.behavior.detach”,
她们都应是方法function类型,参数默认为文档对象:document和设置对象:drupalSettings,用于给元素附加或分离行为,其他js可以在同步阶段通过Drupal.behaviors来注册行为对象,比如“drupal.form”库就注册了一个行为对象:Drupal.behaviors.formSingleSubmit,该行为对象为get方法以外的表单附加了相同值只能提交一次的行为;attach属性会在文档就绪时执行,如果发生异常,将异步抛出错误,不会中断当前任务执行
Drupal.attachBehaviors(context, settings):
在文档准备就绪时自动执行Drupal.behaviors中行为对象的附加行为方法,传入的参数是文档对象:document和设置对象:drupalSettings,这两个参数也是该方法的默认参数值,如果发生异常,将异步抛出错误,不会中断当前任务执行,换句话说就是每个行为对象的附加动作都会被执行
Drupal.detachBehaviors(context, settings, trigger):
用于执行全部行为对象的行为分离动作,也就是“Drupal.behaviors.behavior.detach”,参数默认值是文档对象:document,设置对象:drupalSettings,触发分离的动作名(往往是unload、move、serialize),如果发生异常,将异步抛出错误,不会中断当前任务执行
文件二:/core/misc/drupal.init.js
该文件做三件事:
如果加载了jQuery,那么让渡变量“$”的控制权
给html标签加上“js”类名,样式表可以据此判断前端是否启用了js
在文档就绪时执行:Drupal.attachBehaviors(document, drupalSettings);
补充:
1、前端浏览器中国区使用占比(数据来自百度统计2018.10.01-2019.03.31):
Chrome 45.67%
IE 9.0 9.10%
IE 11.0 6.34%
IE 8.0 5.79%
QQ 5.47%
2345 5.13%
搜狗 4.53%
Firefox 2.62%
Safari 2.45%
其他 12.90%
2、Drupal8在匿名访问时,默认主题首页没有加载任何js文件
3、官方目前还没有较系统的前端文档,仅有较简单的介绍,见:
https://www.drupal.org/docs/8/api/javascript-api/javascript-api-overview
反馈互动