我们在 magento 2 的 phtml 中经常会看到 <script type="text/x-magento-init">
和 data-mage-init
,那么这两个标签是用来做什么的?本篇将给出解释,并说明这样设计的用意。
Magento 2 的自定义设计
首先 <script type="text/x-magento-init">
是 Magento 2 的自定义设计。
我们新建一个 html 文件:
<!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
<?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
<?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
<?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
中填入以下内容
<script type="text/javascript">
console.log('hello');
jQuery(function($){
alert("Hello World");
});
</script>
然后我们刷新页面,查看控制台,会发现:
这是因为 Magento 2 使用 RequireJS 做基础,对 JS 进行模块化,默认不会使用全局命名空间,jQuery
也不再暴露到全局空间。我们应该使用 RequireJS
的方式来访问 js 模块。
Magento 2 本身就是集成了 jQuery
的,所以我们可以这样访问:
<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
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
<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 为以下内容:
<script type="text/x-magento-init">
{
"*": {
"ThankIT_HelloWorld/example":{}
}
}
</script>
example
的内容不变:
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 改成:
<div id="text"></div>
<script type="text/x-magento-init">
{
"#text": {
"ThankIT_HelloWorld/example":{"config":{"text":"Hello Magento 2, Hello ThankIT ..."}}
}
}
</script>
example
改成:
define(['jquery'], function($){
var setText = function(config, node) {
console.log(config);
console.log(node);
$(node).html(config.config.text);
}
return setText;
});
清空浏览器缓存,刷新页面,这时候,我们的页面会是这样的:
不过这里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 改成下面这样:
<div data-mage-init='{"ThankIT_HelloWorld/example": {"config":{"text":"Hello Magento 2, Hello ThankIT ... use data-mage-init ..."}}}'>A single div</div>
刷新页面,是不是先看到 A single div
,随后被替换成了 Hello Magento 2, Hello ThankIT ... use data-mage-init ...
注意,我们的属性中使用的是单引号
<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(翻译)
Allen
可以,很实用