Magento中调用和初始化JavaScript

更新

概览

在 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 的例子:

  1. 拷贝 <carousel_name>.carousel.js 文件到 app/design/frontend/<package_name>/<theme_name>/web/js/<carousel_name>/ 目录

  2. 在 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);
         };
     });
    
    
  3. 在 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')
    }
});