系统学习magento二次开发,推荐小册:《Magento中文全栈二次开发 》
本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。
今天,我们将重点介绍在Magento 2中构建的几乎所有JavaScript功能的基础库 - RequireJS。
在我们进入Magento的RequireJS实现之前,我们将对RequireJS的功能进行一次旋风式的浏览。
### RequireJS
RequireJS是一个javascript模块系统。它实现了JavaScript模块的异步模块定义(AMD)标准。在AMD的术语中,javascript模块提供了一种
运行不默认为全局命名空间的 JavaScript 程序
首先,下载 RequireJS 源代码并将其保存到名为 的文件夹中。scripts
然后,创建以下文件。
<!-- File: require-example.html --> <!DOCTYPE html> <html> <head> <title>My Sample Project</title> <!-- data-main attribute tells require.js to load scripts/main.js after require.js loads. --> <script data-main="scripts/main" src="scripts/require.js"></script> </head> <body> <h1>My Sample Project</h1> </body> </html>
如您所见,此页面在主 RequireJS 中加载,如下所示
<!-- File: require-example.html --> <script data-main="scripts/main" src="scripts/require.js"></script>
除了标准属性之外,还有自定义属性。这告诉 RequireJS 它应该使用模块作为程序的主入口点。在我们的例子中,它是 ,它对应于 中的文件。srcdata-mainscripts/mainscripts/mainscripts/main.js
创建以下文件。
//File: scripts/main.js requirejs([], function() { alert("Hello World"); });
创建上述内容后,在浏览器中加载您的 HTML 页面。您应该会看到警报。祝贺!您刚刚创建了第一个 RequireJS 程序。Hello World
就其本身而言,RequireJS并没有做很多jQuery的文档就绪函数无法完成的事情。
jQuery(function(){ alert("Hello World"); });
RequireJS的与众不同之处在于它的模块系统。例如,如果我们想使用一个名为 的假设模块,我们将更改我们的文件以匹配以下内容。helper/worldmain.js
requirejs(['helper/world'], function(helper_world) { var message = helper_world.getMessage(); alert(message); });
也就是说,我们将要加载的模块指定为数组,并将该数组作为第一个参数传递给函数调用。然后,RequireJS 将模块导出的单个对象作为第一个参数传递给我们的主函数。requirejshelper/worldhelper_world
//File: scripts/helper/world.js define([], function(){ var o = {}; o.getMessage = function() { return 'Hello Module World'; } return o; });
模块定义与我们的主程序定义非常相似。主要区别在于使用函数而不是函数。的第一个参数是你想在模块中使用的 RequireJS 模块的列表(在我们的例子中,这是一个空数组——在现实世界中,大多数模块将使用其他模块)。第二个参数是 javascript 函数/闭包,它定义了模块将返回的内容。definerequirejsdefine
### 需要 JS 文件加载
默认情况下,RequireJS 会将模块名称转换为如下所示的路径helper/worldHTTP(S)
http://example.com/scripts/helper/world.js
https://example.com/scripts/helper/world.js
//example.com/helper/scripts/world.js
也就是说,模块名称转换为文件路径,最后一段是以 结尾的文件名。默认情况下,RequireJS 将使用脚本所在的文件夹作为其基础(在上面的示例中)。jsrequire.js/scripts
但是,RequireJS 允许您为脚本设置不同的基本路径。在启动 RequireJS 程序之前,请包含以下代码。
require.config({ baseUrl: '/my-javascript-code', });
有了上述内容,当 RequireJS 需要加载模块时,它将从helper/world
http://example.com/my-javascript-code/helper/world.js
https://example.com/my-javascript-code/helper/world.js
//example.com/my-javascript-code/helper/world.js
此功能允许您将javascript文件存储在基于RequireJS的系统中的任何位置。
### RequireJS:模块命名
到目前为止,在我们的示例中,RequireJS 模块名称已绑定到该模块源在磁盘上的位置。换句话说,模块将始终位于 路径 .helper/worldhelper/world.js
RequireJS允许您通过配置来更改此设置。例如,如果您希望将模块命名为 ,则需要在程序启动前的某个地方运行以下配置代码helper/worldhello
require.config({ paths: { "hello": "helper/world" }, });
配置键是我们可以重命名/别名模块的地方。对象的 是所需的名称 (),值是模块的实际名称 ()。pathskeypathshellohelper/world
完成上述配置后,以下程序
requirejs(['hello'], function(hello) { alert("Hello World"); });
将从路径加载模块。hellohelper/world.js
### Magento 2 和 RequireJS
这就把我们带到了Magento的RequireJS实现。Magento为您拉入了主要的RequireJS库,包括一些额外的配置,并提供了一种机制,可以让您添加自己的其他RequireJS配置。
你要注意的第一件事是Magento 2对RequireJS上述功能的使用。如果您查看Magento页面的源代码,您将看到如下所示的内容baseUrl
<script type="text/javascript"> require.config( {"baseUrl":"http://magento.example.com/static/adminhtml/Magento/backend/en_US"} ); </script>
通过上述配置,这意味着当Magento 2遇到一个名为的RequireJS模块时,它将从如下所示的URL加载该模块源。helper/world
http://magento.example.com/static/adminhtml/Magento/backend/en_US/helper/world.js
如果您已经阅读了本系列的前几篇文章,您可能会将该 URL 识别为“从 Magento 模块加载前端静态资产”URL。这意味着您可以将 RequireJS 模块定义文件放在模块中
app/code/Package/Module/view/base/web/my_module.js
它将自动作为名为 RequireJS 模块提供
Package_Module/my_module
通过以下网址加载
http://magento.example.com/static/adminhtml/Magento/backend/en_US/Package_Module/my_module.js
这也意味着您可以使用如下所示的代码立即开始在模板中编写程序requirejsphtml
<script type="text/javascript"> requirejs('Package_Module/my_module', function(my_module){ //...program here... }); </script>
或者通过添加独立的 JavaScript 文件来执行相同的操作。
### 通过模块配置 RequireJS
在本教程的前面,我们介绍了两个 RequireJS 配置指令 — 和 .还有很多其他的RequireJS配置指令,当你进入框架的高级使用(或者你正在处理进入高级使用的Magento核心代码)时,你会发现你需要使用它们。baseUrlpath
每个Magento模块都能够通过名为.的特殊视图文件添加RequireJS配置指令。requirejs-config.js
app/code/Package/Module/view/base/requirejs-config.js app/code/Package/Module/view/frontend/requirejs-config.js app/code/Package/Module/view/adminhtml/requirejs-config.js
这是一个特殊的javascript文件,Magento将使用区域层次结构在每次页面加载时自动加载该文件。我们要试一试。首先,我们需要创建一个名为 .您可以使用以下命令使用 pestle 命令行框架创建基本模块文件Pulsestorm_RequireJsTutorial
$ pestle.phar generate_module Pulsestorm RequireJsTutorial 0.0.1
然后通过运行以下两个命令在 Magento 中启用该模块
$ php bin/magento module:enable Pulsestorm_RequireJsTutorial $ php bin/magento setup:upgrade
如果你有兴趣手动创建一个模块,或者好奇上面的 pestle 命令实际上在做什么,请查看我们的 Magento 2 简介 — 不再有 MVC 文章。
无论您如何创建它,一旦创建并启用了模块,请添加以下文件
//File: app/code/Pulsestorm/RequireJsTutorial/view/base/requirejs-config.js alert("Hello");
要了解RequireJS是如何做到这一点的,我们需要看看Magento实际在哪里提取这些文件。如果您查看Magento安装中的任何源页面,您应该会看到如下所示的标记requirejs-config.js
<script type="text/javascript" src="http://magento.example.com/static/_requirejs/adminhtml/Magento/backend/en_US/requirejs-config.js"></script>
如果您在浏览器中查看此文件的源代码,您将在如下所示的代码块中看到您的语句alert
(function() { alert("Hello World"); require.config(config); })();
虽然这不是100%明显,但通过从Magento 2生成这个javascript代码块,我们可以向系统添加额外的RequireJS初始化。requirejs-config.js
用一个具体的例子来说,这可能更有意义。让我们用以下内容替换我们的requirejs-config.js
var config = { paths:{ "my_module":"Package_Module/my_module" } }; alert("Done");
我们在这里所做的是定义一个名为 的 JavaScript 变量,并更改了我们的值。如果你回去重新加载,现在可能会更清楚Magento在做什么。configalertrequirejs-config.js
(function() { var config = { paths:{ "my_module":"Package_Module/my_module" } }; alert("Done"); require.config(config); })();
对于每个人,Magento将创建一个看起来像这样的代码块requirejs-config.js
(function() { //CONTENTS HERE require.config(config); })();
但替换为 的内容。//CONTENTS HERErequirejs-config.js
var config = { paths:{ "my_module":"Package_Module/my_module" } }; alert("Done"); require.config(config);
这意味着如果我们在文件中定义一个变量,Magento 最终会将其传递给 .这将允许任何Magento模块开发人员使用RequireJS功能,如,,,或RequireJS配置指令中的许多其他功能之一。configrequirejs-config.jsrequire.configshimpathsbaseUrlmap
### 了解延迟加载
关于 RequireJS 的另一个重要事情是模块是延迟加载的。RequireJS不会加载任何javascript模块源文件,直到有人将该javascript模块作为依赖项使用。
换句话说,如果我们使用配置
var config = { paths:{ "my_module":"Package_Module/my_module" } };
默认情况下,Magento不会加载该文件。Magento只会在你将其用作模块后加载该文件。Package_Module/my_module.js
requirejs(['my_module'], function(my_module){ }); requirejs(['Package_Module/my_module'], function(my_module){ }); define(['Package_Module/my_module'], function(my_module){ });
请记住,RequireJS的要点是,日常的JavaScript开发人员不需要担心他们的程序如何对其源文件发出HTTP请求。延迟加载是一个实现细节,在理想情况下,它可以为最终用户节省下载特定页面可能不需要的源文件的带宽。
但是,在不太理想的情况下,这种延迟加载行为可能会使使用较旧的JavaScript框架和库变得棘手。当我们讨论一些jQuery陷阱时,我们将在下面讨论一个例子。
### 全局 jQuery 对象
即使你决定RequireJS不适合你,并且你想坚持在Magento 2中使用普通的jQuery,你仍然需要了解RequireJS如何与AMD标准之前的库进行交互。
在Magento 2中,jQuery作为RequireJS模块加载。这意味着如果您尝试使用如下所示的代码
<script type="text/javascript"> jQuery(function(){ //your code here }); </script>
您的浏览器会抱怨未定义。这是因为在您将 jQuery 用作 RequireJS 模块之前,全局对象不会被初始化。如果您习惯于编写上述代码,则需要jQueryjQuery
将其替换为启动 RequireJS 程序执行的代码
将该程序配置为将模块用作依赖项jquery
换句话说,像这样的事情
requirejs(['jquery'], function(jQuery){ jQuery(function(){ //your code here }); });
回顾一下 — 通过调用函数并向其传递模块依赖项列表以及将充当程序主入口点的匿名 JavaScript 函数来开始执行 RequireJS 程序。requirejs
模块依赖项列表是 的第一个参数 — 即以下代码说“我的程序依赖于模块”requirejsjquery
requirejs(['jquery'],
充当程序主入口点的匿名函数是函数的第二个参数requirejs
requirejs(['jquery'], function(jQuery){ //... });
RequireJS 将为您调用此函数。对于您配置的每个依赖项,RequireJS 将加载模块并传入其返回的(或者,在 RequireJS 中,导出)模块。
现代版本的jQuery将检测它们是否包含在RequireJS/AMD环境和返回全局对象的模块中。definejQuery
if ( typeof define === "function" && define.amd ) { define( "jquery", [], function() { return jQuery; } ); }
### RequireJS 和 jQuery 插件
同时使用jQuery和RequireJS还有另一个问题。jQuery库比RequireJS和AMD标准早很多年,开发了自己的插件系统。虽然不是基于模块的,但这个系统在javascript的默认全局环境中玩得相对较好——插件开发人员通过修改单个全局jQuery对象来创建他们的插件。
这给 RequireJS 带来了一个问题——正如我们上面提到的,在程序中使用模块之前,直到 RequireJS 调用该程序的主入口函数,才会定义全局对象。这意味着包含jQuery插件的长期存在方式jQueryjqueryrequirejs
<script src="http://magento.example.com/js/path/to/jquery/plugin/jquery.cookie.js">
当插件尝试使用全局对象和/或别名时将失败。jQuery$
//File: http://magento.example.com/js/path/to/jquery/plugin/jquery.cookie.js
var config = $.cookie = function (key, value, options) {
如果你想包含一个jQuery插件在Magento 2中使用,你需要通过RequireJS来完成。幸运的是,这个过程相对简单。
首先,您需要使用配置属性为插件路径创建别名。paths
var config = { paths:{ "jquery.cookie":"Package_Module/path/to/jquery.cookie.min" } };
上面的配置创建了一个名为的模块,该模块指向模块中的 jQuery cookie 插件源文件。jquery.cookiePackage_Module
在这一点上,你可能会认为通过做这样的事情来开始使用你的插件的jQuery是可以的
requirejs(['jquery','jquery.cookie'], function(jQuery, jQueryCookie){ //my code here });
毕竟,将两者和依赖项列出应该会触发两个文件的加载。jqueryjquery.cookie
配置方面,这看起来像
var config = { paths:{ "jquery.cookie":"Package_Module/path/to/jquery.cookie.min" }, shim:{ 'jquery.cookie':{ 'deps':['jquery'] } } };