[翻译]Drupal 8 模块里面添加 css 和 js
原文链接:https://www.drupal.org/node/2274843
这篇文档是专门针对Drupal模块的。如果要看针对主题的,看添加css和js到Drupal 8 主题。
在Drupal 8里面,css和js是通过相同的系统加载到模块或者主题里面的,都是通过资源库(asset libraries)的方式。资源库能够包含一个或者多个的css资源,一个或者多个js资源,一个或者多个js配置。
Drupal 使用一个高层次原则:资源(css 或者 js)只有在你告诉drupal你需要加载它们的时候它们才会被加载进来。Drupal 不会再所有的页面都加载所有的资源(css/js),因为这样不利于前端的性能优化。
和Drupal 7相比的不同之处
对于开发者来说,和drupal 7相比,有一个很重要的区别:
-
只有javascript是在特别的页面是必须的时候,js才会被加载进去。特别是,默认的情况下,匿名用户看到的大多数页面的js都不是必须的。这也意味着jQuery不会被自动加载到所有的页面。
所以,如果你的主题需要jQuery或者其他的javascript(在资源库里面已经定义的)。你要告诉Drupal在这种情况下,需要在所需的资源库里面通过声明依赖的方式加载它们。
过程
加载资源库(css/js)通常的步骤:
-
保存css和js文件
-
定义包含css和js文件的库
-
把这个库附加到钩子的渲染数组里面
但是在主题里面,第三步有一个替代方式:主题能够选择加载任意数量的资源库到所有的页面。
定义资源库
定义一个或者多个资源库的时候,添加一个*.libraries.yml文件到你的模块目录。(如果你的模块名叫 fluffiness,文件名就应该是 fluffiness.libraries.yml)。这个文件的每个库都包含了css和js文件详细信息的条目,例如:
cuddly-slider: version: 1.x css: theme: css/cuddly-slider.css: {} js: js/cuddly-slider.js: {}
你可能注意到了指定css的“theme”关键词并没有添加给js,这指定css文件所属的样式类型。
你能够通过5种不同级别的类型设置css的权重。
-
base 关键词赋值权重 CSS_BASE = -200
-
layout 关键词赋值权重 CSS_LAYOUT = -100
-
component 关键词赋值权重 CSS_COMPONENT = 0
-
state 关键词赋值权重 CSS_STATE = 100
-
theme 关键词复制权重 CSS_THEME = 200
这个是根据SMASS标准定义的。所以如果你指定了theme关键词,意味着这个CSS文件包含了显示外观和感觉的theme相关的样式。获取更多资料。你不能够使用其他的关键字,否则的话会导致严格警告信息。
这个例子假设你的js文件 cuddle-slider.js位于你的模块子目录js目录下面。你同样可以引入一个外部的js文件,css文件或者其他的可能。参考CDN / externally hosted libraries获取更多信息。
记住,drupal 8不再在所有的页面都默认加载jQuery,只在需要的地方加载。因此,我们需要声明模块的 cuddle-slider 库的时候声明包含jQuery的依赖。既不是模块也不是主题会提供jQuery,而是drupal的核心:core/jquery 是我们想要声明的依赖。(一个扩展名,后面跟着一个斜杠,在后面跟着库名,所以如果其他的库想要依赖cuddly-slider库的话,就必须声明依赖 fluffiness/cuddly-slider,因为 fluffiness是我们的主题名称)
所以,确保js/cuddly-slider可使用jQuery,我们需要更新以上的代码:
cuddly-slider: version: 1.x css: theme: css/cuddly-slider.css: {} js: js/cuddly-slider.js: {} dependencies: - core/jquery
正如你期待的,css和js的资源列表里面的顺序就是他们在页面加载的顺序。
把库附加到页面
取决于你需要加载哪些资源,你可以使用不同的方式附加对应的资源库。毕竟,一些资源库在所有的页面需要被加载,而有一些库只有很少页面被加载,而有一些在大多数页面被加载,但是并不是所有页面。
最重要的是drupal8不会通过当前是在哪个页面而加载library,而是通过当前页面的可见元素来加载,比如一个页面包含类似于以下的元素
'#type' => 'table', a '#type' => 'dropbutton' and a '#type' => 'foobar'
那么drupal将会加载跟这些types相关的libraries。
但是不仅仅局限于#type:可能我们想要为某一些#type实例加载某一些资源库,这种情况下,我们只需要把libraries添加到这个实例的返回数组里面去就行了。
当然,在很少情况下,我们有一个合理的理由需要在每一个页面都加载libraries,而不管页面上的东西,例如分析一些页面加载的分析代码。
以下是一些例子来说明如何做到这些。
通过当前存在的#type加载library,针对所有实例的话,我们使用hook_element_info_alter()
function fluffy_element_info_alter(array &$types) { if (isset($types['table'])) { $types['table']['#attached']['library'][] = 'fluffiness/fancy_table'; } }
然后清除缓存以便drupal能够意识到这个新的钩子实现。
通过返回数组的方式加载library。
$build['the_element_that_needs_the_asset_library']['#attached']['library'][] = 'fluffiness/fancy_element';
附加到区块插件的返回数组中。
这个是通过返回数组的方式加载library的另外一个例子。
return [ '#theme' => 'your_module_theme_id', '#someVariable' => $some_variable, '#attached' => array( 'library' => array( 'your_module/library_name', ), ), ];
在所有页面加载library。
function contextual_page_attachments(array &$attachments) { if (!\Drupal::currentUser()->hasPermission('access contextual links')) { return; } $attachments['#attached']['library'][] = 'contextual/drupal.contextual-links'; }
在preprocess function里面加载library。
function fluffy_preprocess_maintenance_page(&$variables) { $variables['#attached']['library'][] = 'fluffy/cuddly-slider'; }
在twig模板加载library
{{ attach_library('contextual/drupal.contextual-links') }}<div>Some markup {{ message }}</div>
加载可配置的javascript。
在某一些情况下,你可能需要基于php的一些计算来添加js代码。
这种情况下,先按照以前的方式定义library,但是同时需要加载Javasript Settings,并且,让这个javascript文件通过drupalSettings(继承drupal7 里面的Drupal.settings)。同时需要加载jQuery,我们需要声明一些依赖来做到这些。
cuddly-slider: version: 1.x js: js/cuddly-slider.js: {} dependencies: - core/jquery - core/drupalSettings
并且在模块的hook_page_attachments_alter(&$build)函数里面,
$build['#attached']['library'][] = 'fluffiness/cuddly-slider'; $build['#attached']['drupalSettings']['fluffiness']['cuddlySlider']['foo'] = 'bar';
最后cuddly-slider.js这个文件就可以通过以下方式得到bar。
drupalSettings.fluffiness.cuddlySlider.foo (and it will === 'bar').