概览
在 Magento2 中调用 和 初始化 JavaScript 主要有两种方式:
- 在 .phtml 页面文件中插入 JavaScript 组件。
- 在 javascript(.js)文件中调用需要初始化的Javascript组件
强烈建议使用上述方法来使用 JavaScript 而不是以 inline 方式使用 JavaScript .
在 PHTML 模版文件中插入 JS 组件
根据你的任务,你可以使用声明式 declarative 或命令式 imperative 标记来插入JS组件到PHTML模板中。如果一个组件需要初始化,就使用声明式标记,其他情况下应使用命令式声明符。
声明式标记 Declarative notation
使用声明式标记插入一个JS组件,在后台准备好所有的配置,并使用标准工具将其输出到页面源。如果你的JavaScript组件需要初始化,请使用 声明式标记 。
在Magento 2中,你有两个选项来指定声明性标记。
-
使用 data-mage-init 属性
这是用来针对一个特定的HTML元素。它比较容易实现,通常用于jQuery UI小工具。这个方法只能在指定的HTML标签上实现。例如,。这种方法因其简洁的语法和对HTML元素的直接访问而受到青睐。
-
使用 ... 标签
这是用来针对一个CSS选择器或*。如果CSS选择器匹配了多个HTML元素,脚本将为每个匹配的HTML元素运行。对于*,没有HTML元素被选中,脚本将以HTML DOM为目标运行一次。这个方法可以在代码库的任何地方实现,以任何HTML元素为目标。当直接访问HTML元素受到限制,或者没有目标HTML元素时,这是首选。
来看一个 增加自定义 carousel JS 的例子:
-
拷贝 <carousel_name>.carousel.js 文件到 app/design/frontend/<package_name>/<theme_name>/web/js/<carousel_name>/ 目录
-
在 app/design/frontend/<package_name>/<theme_name>/web/js/carousel.js 添加你的 RequireJS module
define(['jquery','<carousel_name>'], function($) { return function(config, element) { $(element).<carousel_name>(config); }; });
-
在 app/design/frontend/<package_name>/<theme_name>/requirejs-config.js 文件添加 RequireJS 配置
var config = { map: { '*': { 'carousel': 'js/carousel', '<carousel_name>': 'js/<carousel_name>/<carousel_name>.carousel' } } };
现在, 我们有两个选择来 指定声明标记
-
在元素中使用 data-mage-init 属性插入 carousel
<div data-mage-init='{"carousel":{"option": value}}'> <div class="item">Item 1</div> ... <div class="item">Item n</div> </div>
-
使用
<div id="<carousel_name>" class="carousel"> <div class="item">Item 1</div> ... <div class="item">Item n</div> </div> <script type="text/x-magento-init"> { "#<carousel_name>": { "carousel": {"option": value} } } </script>
声明式标记 using the data-mage-init
attribute
使用 data-image-init 属性在指定的HTML元素中插入一个JS组件。下面的例子在元素中插入了一个JS组件。
<nav data-mage-init='{"<component_name>": {...}}'></nav>
当Javascript被插入到指定的元素中时,该脚本只对这个特定的元素被调用。它不会自动为页面上的其他这种类型的元素调用。
How data-mage-init
is processed
在DOM准备好后,data-mage-init属性被解析,以提取组件名称和配置,以应用于该元素。根据插入的JS组件的类型,处理过程如下。
-
如果返回的是一个对象,初始化器会尝试找到<component_name>键。如果对应的值是一个函数,初始化器会将配置和元素值传递给这个函数。比如说
return { '<component_name>': function(config, element) { ... } };
其中<component_name>是一个本地Magento JS组件,例如:菜单、可折叠、工具提示......。
<nav data-mage-init='{"tooltip": {"content": "<?= /* @noEscape */ $content ?>"}}'></nav>
或者一个自定义的JS组件,用一个组件路径实现。Vendor_Module/js/component,或在requirejs-config.js中声明的别名。
<nav data-mage-init='{"Vendor_Module/js/component": {"status":"<?= /* @noEscape */ $block->getStatus(); ?>"}}'></nav>
-
如果返回一个函数,初始化器将配置和元素值传递给这个函数。比如说。
return function(config, element) { ... };
-
如果既没有一个函数,也没有一个"<component_name>"键的对象被返回,那么初始化器会尝试在jQuery原型中搜索"<component_name>"。如果找到,初始化器将其应用为$(element).<component_name>;(config)。比如说。
$.fn.<component_name> = function() { ... }; return;
-
如果前面的情况都不是真的,那么这个组件就会被执行,不需要进一步处理。这样的组件既不需要配置也不需要元素。推荐使用标签来声明此类组件。
声明式标记 using the <script type="text/x-magento-init">
tag
要在一个HTML元素上调用一个JS组件,而不直接访问该元素或与某个元素没有关系,可以使用标签和属性语法,如下例所示。
<script type="text/x-magento-init">
{
// components initialized on the element defined by selector
"<element_selector>": {
"<js_component1>": ...,
"<js_component2>": ...
},
// components initialized without binding to an element
"*": {
"<js_component3>": ...
}
}
</script>
其中:
- <element_selector>是一个选择器(就querySelectorAll而言),用于调用以下JS组件的元素。
- <js_component1>和<js_component2>是在元素上被初始化的JS组件,选择器被指定为<element_selector>。
- <js_component3>是被调用的JS组件,没有绑定到一个元素。
下面的例子提供了一个使用调用widget的工作代码样本。在这里,手风琴和导航部件被添加到具有#main-container选择器的元素中,并且pageCache脚本被插入,没有与任何元素绑定。
<script type="text/x-magento-init">
{
"#main-container": {
"navigation": <?php echo $block->getNavigationConfig(); ?>,
"accordion": <?php echo $block->getNavigationAccordionConfig(); ?>
},
"*": {
"pageCache": <?php echo $block->getPageCacheConfig(); ?>
}
}
</script>
命令式标记 Imperative notation
在PHTML模板中使用命令式标记,在页面上包含原始的 JavaScript 代码来执行指定的业务逻辑。这种方法使用没有 type="text/x-magento-init " 属性的标签,如以下例子所示。
<script>
require([
'jquery',
'accordion' // the alias for "mage/accordion"
], function ($) {
$(function () { // to ensure that code evaluates on page load
$('[data-role=example]') // we expect that page contains the <tag data-role="example">..</tag> markup
.accordion({ // now we can use "accordion" as jQuery plugin
header: '[data-role=header]',
content: '[data-role=content]',
trigger: '[data-role=trigger]',
ajaxUrlElement: "a"
});
});
});
</script>
为了更好地控制脚本的执行,请使用声明式语法而不是命令式语法。当使用命令式语法时,就会失去利用现有JS类的能力,并可能阻碍页面的渲染。
在JS文件中调用需要初始化的JS组件
要用JS代码调用一个部件,使用类似于(手风琴部件)的符号。它被初始化在[data-role=example]元素上,如下图)
$('[data-role=example]').accordion();
要用选项初始化一个小组件,请使用与下面类似的符号。
$(function () { // to ensure that code evaluates on page load
$('[data-role=example]') // we expect that page contains markup <tag data-role="example">..</tag>
.accordion({ // now we can use "accordion" as jQuery plugin
header: '[data-role=header]',
content: '[data-role=content]',
trigger: '[data-role=trigger]',
ajaxUrlElement: 'a'
});
});
以类似的方式,你可以初始化任何JS组件,其返回的回调函数接受一个配置对象和元素(一个DOM节点)。
比如说。
define ([
'jquery',
'mage/gallery/gallery'
], function ($, Gallery) {
$(function () { // to ensure that code evaluates on page load
$('[data-role=example]') // we expect that page contains markup <tag data-role="example">..</tag>
.each(function (index, element) {
Gallery({
options: {},
data: [{
img: 'https://c2.staticflickr.com/8/7077/27935031965_facd03b4cb_b_d.jpg'
}],
fullscreen: {}
}, element); // 'element' is single DOM node.
});
});
});
在动态内容中执行data-mage-init和x-magento-init
当动态内容被注入时,要在元素上触发.trigger('contentUpdated'),使用
$.ajax({
url: 'https://www.example.com',
method: 'POST',
data: {
id: '1'
},
success: function (data) {
$('.example-element').html(data)
.trigger('contentUpdated')
}
});