{ Hello Magento 2 }

解决 Magento 2 应用问题,更注重深度挖掘。(ง •̀_•́)ง

0%

type="text/x-magento-init"

我们在 magento 2 的 phtml 中经常会看到 <script type="text/x-magento-init">data-mage-init ,那么这两个标签是用来做什么的?本篇将给出解释,并说明这样设计的用意。

Magento 2 的自定义设计

首先 <script type="text/x-magento-init"> 是 Magento 2 的自定义设计。我们新建一个 html 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
<script type="text/javascript">
alert('common');
</script>
<script type="text/x-magento-init">
alert('magento');
</script>
</body>
</html>

然后从浏览器中访问他,我们会看到 common 的 alert 但不会看到 magento 的 alert 。这是因为浏览器不认识 type="text/x-magento-init" 的这个 <script>,所以会直接忽略它。

创建一个演示模块

我们还是以 ThankIT_HelloWorld 为基础。

创建 Controller

File:app\code\ThankIT\HelloWorld\Controller\Javascript\Example.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
namespace ThankIT\HelloWorld\Controller\Javascript;

class Example extends \Magento\Framework\App\Action\Action
{

protected $resultPageFactory;

/**
* Constructor
*
* @param \Magento\Framework\App\Action\Context $context
* @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
*/
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
) {
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context);
}

/**
* Execute view action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
return $this->resultPageFactory->create();
}
}

创建 layout

File:app\code\ThankIT\HelloWorld\view\frontend\layout\helloworld_javascript_example.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" ?>
<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="ThankIT\HelloWorld\Block\Javascript\Example" name="Javascript.Example" template="ThankIT_HelloWorld::javascript/example.phtml"/>
</referenceContainer>
</body>
</page>

创建 Block

File:app\code\ThankIT\HelloWorld\Block\Javascript\Example.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
namespace ThankIT\HelloWorld\Controller\Javascript;

class Example extends \Magento\Framework\App\Action\Action
{

protected $resultPageFactory;

/**
* Constructor
*
* @param \Magento\Framework\App\Action\Context $context
* @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
*/
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
) {
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context);
}

/**
* Execute view action
*
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
return $this->resultPageFactory->create();
}
}

创建 template

File:app\code\ThankIT\HelloWorld\view\frontend\templates\javascript\example.phtml 内容为空 然后刷新缓存,访问 url http://example/helloworld/javascript/example 我们就会看到带 header 和 footer 的页面,内容为空。 这里没有什么稀奇的,只是一个准备工作,预热一下。

创建一个 requirejs 模块

我们先关闭掉 fpc (Full page caching),这样不用每次清缓存看结果。 我们先在 File:app\code\ThankIT\HelloWorld\view\frontend\templates\javascript\example.phtml 中填入以下内容

1
2
3
4
5
6
<script type="text/javascript">
console.log('hello');
jQuery(function($){
alert("Hello World");
});
</script>

然后我们刷新页面,查看控制台,会发现: jQuery is not defined 这是因为 Magento 2 使用 RequireJS 做基础,对 JS 进行模块化,默认不会使用全局命名空间,jQuery 也不再暴露到全局空间。我们应该使用 RequireJS 的方式来访问 js 模块。 Magento 2 本身就是集成了 jQuery 的,所以我们可以这样访问:

1
2
3
4
5
<script type="text/javascript">
requirejs(['jquery'], function($) {
alert("Hello World");
});
</script>

关于 RequireJS 可以参阅 Magento 2 and RequireJS (翻译) 我们现在创建以下文件: File: app\code\ThankIT\HelloWorld\view\frontend\web\example.js

1
2
3
4
5
6
7
8
define([], function(){
alert("A simple RequireJS module");
var mageJsComponent = function()
{
alert("A simple magento component.");
};
return mageJsComponent;
});

这样我们就定义了一个简单的 RequireJS module,这个模块的位置是 app\code\ThankIT\HelloWorld\view\frontend\web\example.js,那么他的模块名,在没有重新命名的情况下,就是 ThankIT_HelloWorld/example。 然后我们来更改 phtml

1
2
3
4
5
<script type="text/javascript">
requirejs(['ThankIT_HelloWorld/example'], function($) {
alert("Hello World");
});
</script>

刷新网页,然后我们会先看到弹出框 A simple RequireJS module,然后是 Hello World。就是我们先加载 ThankIT_HelloWorld/example 然后执行 alert("Hello World"); 好,这样看来,我们已经会给 Magento 2 加 js module ,并且在 phtml 中使用它了。 要了解更详细的解释,请参阅 Magento 2 Javascript Init Scripts(翻译)

<script type="text/x-magento-init">

让我们来修改 phtml 为以下内容:

1
2
3
4
5
6
7
<script type="text/x-magento-init">
{
"*": {
"ThankIT_HelloWorld/example":{}
}
}
</script>

example 的内容不变:

1
2
3
4
5
6
7
8
define([], function(){
alert("A simple RequireJS module");
var mageJsComponent = function()
{
alert("A simple magento component.");
};
return mageJsComponent;
});

这时候刷新页面(有时也需要情况浏览器缓存),我们会发现,这次先弹出 A simple RequireJS module 然后弹出 A simple magento component. 上面我们用 requirejs 的方法,并没有弹出 A simple magento component. 也就是说,<script type="text/x-magento-init"> 方式不仅会使用 requirejs 的方式加载该模块,而且还湖调用它。

传参

phtml 改成:

1
2
3
4
5
6
7
8
<div id="text"></div>
<script type="text/x-magento-init">
{
"#text": {
"ThankIT_HelloWorld/example":{"config":{"text":"Hello Magento 2, Hello ThankIT ..."&#125;&#125;
}
}
</script>

example 改成:

1
2
3
4
5
6
7
8
define(['jquery'], function($){
var setText = function(config, node) {
console.log(config);
console.log(node);
$(node).html(config.config.text);
}
return setText;
});

清空浏览器缓存,刷新页面,这时候,我们的页面会是这样的: magento 2 x-magento-init magento 2 x-magento-init console log 不过这里console.log 出的结果有点奇怪,按照我的理解,输出的 node 不应该含有 Hello Magento 2, Hello ThankIT ... 内容。。。有清楚的朋友请给我留个言吧,感谢! 通过上面这个例子,我们知道 ** <script type="text/x-magento-init"> 方式可以传递要作用的节点,可以传递配置参数,并且之后被调用执行。**通过这样的设计,Magento 鼓励开发者避免在 RequireJS 模块中硬编码 DOM 节点。传递的配置参数可以由服务器端生成。这进一步分离的会让代码更清晰。

data-mage-init

这个方式实际上和 <script type="text/x-magento-init"> 是一样的。 我们把 phtml 改成下面这样:

1
<div data-mage-init='{"ThankIT_HelloWorld/example": {"config":{"text":"Hello Magento 2, Hello ThankIT ... use data-mage-init ..."&#125;&#125;}'>A single div</div>

刷新页面,是不是先看到 A single div ,随后被替换成了 Hello Magento 2, Hello ThankIT ... use data-mage-init ... 注意,我们的属性中使用的是单引号

1
<div data-mage-init='...'>A single div</div>

这是必要的,data-mage-init 属性会严格按照 JSON 格式解析,就是说 JSON 对象必须使用双引号,所以我们的属性就只能用单引号了。

关于如何实现的 type=”text/x-magento-init”

The code that uses them is located in lib/web/mage/apply/scripts.js 参考 In Magento2 what is<script type=“text/x-magento-init”>?

参考文档

Magento 2 and RequireJS (翻译) Magento 2 Javascript Init Scripts(翻译)