<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>如果您需要将订单导入Magento 2怎么办?平台不支持此过程。但是,您可以在第三方订单导入解决方案的帮助下轻松添加缺少的功能。但是,如果您的导入文件不包含订单增量 ID,该怎么办?由于并非所有第三方模块都知道如何处理此问题,因此情况变得更加复杂。在下面的文章中,您将介绍如何在Magento 2导入期间自动生成订单增量ID。</p><p>缺少订单增量 ID</p><p>假设您需要从直销供应商处导入订单。这意味着您的订单导入文件中没有Magento订单增量或实体ID。但是,您需要在导入时自动生成这些ID,就像从Magento管理面板创建新订单时一样。让我们看看,如何做到这一点。</p><p>如何在Magento 2导入期间自动生成订单增量ID</p><p>您需要使用改进的导入和导出Magento 2扩展在Magento 2导入期间自动生成订单增量ID。首先,它可以从任何外部系统自动导入订单。此外,在以下两种情况下,该模块可以为订单自动生成增量 ID:</p><p>您的订单导入文件包含increment_id列,但它是空的<span style="color: #6a9955;">;</span></p><p>导入文件中缺少increment_id列。</p><p>在increment_id列为空的情况下,改进的导入和导出Magento 2扩展可以自动填充数据,将相应的记录添加到Magento数据库中。如果没有increment_id列,则根本不是问题。该模块可以从头开始创建它,为您填写必要的数据。</p><p>请按照以下步骤在Magento 2导入期间自动生成订单增量ID:</p><p>打开改进的导入和导出扩展<span style="color: #6a9955;">;</span></p><p>打开新的导入作业<span style="color: #6a9955;">;</span></p><p>选择订单作为您的导入实体<span style="color: #6a9955;">;</span></p><p>配置作业的设置<span style="color: #6a9955;">;</span></p><p>在“导入设置”部分,激活“对订单increment_id使用自动增量”特征。</p><p><img src="/uploads/images/20230825/349659d63c137bcf5bf859c7eae272ff.png" title="1.png" alt="" width="927" height="330"/></p><p>完成订单导入作业配置并保存。</p><p>除了能够在Magento 2导入期间自动生成订单增量ID之外,改进的导入和导出Magento 2扩展还允许您根据基于cron的计划,使用不同的文件格式(如CSV,XML,XLSX和JSON)和来源(Google Sheets,Dropbox,Google Drive等)导入和导出数据。您可以将映射应用于第三方数据,运行基于API的导入和导出,以及将任何实体移入和移出Magento 2网站。</p><p><br/><br/></p><p><br/></p>
文章列表
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>很有可能,您知道需要将客户导入Magento 2的情况,但他们没有分配给客户组。在这种情况下,您需要手动重新分配它们。数据文件包含的元素越多,执行此数据输入例程所花费的时间就越多。但是,如果这个过程可以自动化呢?</p><p>下面,我们将说明如何将客户导入Magento 2并将他们分配给客户组,即使该客户组在您的电子商务网站上不存在。您所需要的只是改进的导入和导出。但是,在讨论解决方案之前,让我们更详细地探讨这个问题。</p><p>Magento 2 客户导入不会将客户分配到客户组</p><p>因此,如果您将客户导入Magento 2,并且他们未分配给您网站上存在的客户组,则您的group_id属性(此客户组的ID)可能为空。您可以仔细检查导入文件,应用必要的更改,然后重新导入。但是,这种方法不会节省您的时间。</p><p>在另一种情况下,您的Magento 2客户导入过程可能不会将客户分配到客户组,因为您的网站上不存在该客户组。在这种情况下,您需要在导入任何客户数据之前创建它,并在导入文件中指定组的 ID。</p><p>不幸的是,这两种情况都与大量手动数据输入有关。但是可以平滑边缘并自动将客户导入Magento 2。让我们看看如何。</p><p>如何将客户导入Magento 2并将其分配给客户组</p><p>正如我们上面提到的,您需要改进的导入和导出Magento 2扩展来解决此问题。此模块将三列添加到客户主文件:</p><p>_customer_group_code</p><p>_tax_class_name</p><p>_tax_class_id</p><p>此改进如何帮助将客户导入Magento 2并将其分配给客户组?我看看。</p><p>如果没有group_id属性或相应的列为空,则不再是问题。</p><p>如果您的网站上存在“_customer_group_code”列 中的客户组,则“改进的导入和导出”模块将获取_customer_group_code值并将客户添加到相应的客户组。</p><p>如果“_customer_group_code”列 中的客户组在您的网站上不存在,则该模块将采用_customer_group_code值和_tax_class_name值,并执行以下操作:</p><p>改进的“导入和导出”扩展程序 会动态创建一个新的客户组,如果_tax_class_name列中的税务规则名称来自“_customer_group_code”列 存在于您的网站上。</p><p>但是,如果您的网站上不存在与“_tax_class_name”列中的税务规则同名的税务规则,则不会创建新的客户组。发生这种情况是因为扩展不知道客户组与哪个税种相关。在这种情况下,它显示以下错误:X 行中的_tax_class_name不存在。这意味着您需要在Magento 2网站上创建相应的税收规则来解决此问题。</p><p>或者,改进的导入和导出扩展可以依赖于 _tax_class_id 属性。如果您的网站上存在具有导入表中 ID 的类,则会在导入过程中自动创建一个客户组,并将客户分配给该类。如果您网站上没有税级 ID 与客户导入文件中的税级 ID 匹配,则不会创建新的客户组。</p><p>请注意,_tax_class_id 属性的优先级高于 _tax_class_name 属性。但是,在您的Magento 2网站上至少有一个税收属性(_tax_class_id或_tax_class_name)就足以创建客户组并在导入过程中自动为其分配客户。</p><p>还值得一提的是,group_id属性的优先级高于_customer_group_code属性。如果它们的值不同,则改进的导入和导出扩展将从 group_id 属性中获取该值,以创建新的客户组,并在导入时为其分配客户。</p><p>我们希望这些信息能帮助您将客户导入Magento 2,并将他们比以往更快地分配给客户组!</p><p>除了能够将客户导入Magento 2并将他们分配给客户组(即使您的网站上不存在)之外,改进的导入和导出Magento 2扩展还允许您根据基于cron的时间表,使用不同的文件格式(例如CSV,XML,) XLSX和JSON)和来源(Dropbox,Google Drive等)。此外,可以将映射应用于第三方数据,以将信息从任何来源直接传输到您的电子商务网站。您还可以运行基于 API 的导入和导出流程,并使用 Google 表格将任何实体移入和移出您的 Magento 2 网站。</p><p><br/></p>
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>今天,我们将重点介绍在Magento 2中构建的几乎所有JavaScript功能的基础库 - RequireJS。</p><p>在我们进入Magento的RequireJS实现之前,我们将对RequireJS的功能进行一次旋风式的浏览。</p><p><span style="color: #6a9955;">### RequireJS</span></p><p>RequireJS是一个javascript模块系统。它实现了JavaScript模块的异步模块定义(AMD)标准。在AMD的术语中,javascript模块提供了一种</p><p>运行不默认为全局命名空间的 JavaScript 程序</p><p>首先,下载 RequireJS 源代码并将其保存到名为 的文件夹中。scripts</p><p>然后,创建以下文件。</p><pre class="brush:bash;toolbar:false"><!-- 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></pre><p>如您所见,此页面在主 RequireJS 中加载,如下所示</p><pre class="brush:bash;toolbar:false"><!-- File: require-example.html --> <script data-main="scripts/main" src="scripts/require.js"></script></pre><p>除了标准属性之外,还有自定义属性。这告诉 RequireJS 它应该使用模块作为程序的主入口点。在我们的例子中,它是 ,它对应于 中的文件。srcdata-mainscripts/mainscripts/mainscripts/main.js</p><p>创建以下文件。</p><p></p><pre class="brush:bash;toolbar:false">//File: scripts/main.js requirejs([], function() { alert("Hello World"); });</pre><p>创建上述内容后,在浏览器中加载您的 HTML 页面。您应该会看到警报。祝贺!您刚刚创建了第一个 RequireJS 程序。Hello World</p><p>就其本身而言,RequireJS并没有做很多jQuery的文档就绪函数无法完成的事情。</p><p></p><pre class="brush:bash;toolbar:false">jQuery(function(){ alert("Hello World"); });</pre><p>RequireJS的与众不同之处在于它的模块系统。例如,如果我们想使用一个名为 的假设模块,我们将更改我们的文件以匹配以下内容。helper/worldmain.js</p><p></p><pre class="brush:bash;toolbar:false">requirejs(['helper/world'], function(helper_world) { var message = helper_world.getMessage(); alert(message); });</pre><p>也就是说,我们将要加载的模块指定为数组,并将该数组作为第一个参数传递给函数调用。然后,RequireJS 将模块导出的单个对象作为第一个参数传递给我们的主函数。requirejshelper/worldhelper_world</p><p></p><pre class="brush:bash;toolbar:false">//File: scripts/helper/world.js define([], function(){ var o = {}; o.getMessage = function() { return 'Hello Module World'; } return o; });</pre><p>模块定义与我们的主程序定义非常相似。主要区别在于使用函数而不是函数。的第一个参数是你想在模块中使用的 RequireJS 模块的列表(在我们的例子中,这是一个空数组——在现实世界中,大多数模块将使用其他模块)。第二个参数是 javascript 函数/闭包,它定义了模块将返回的内容。definerequirejsdefine</p><p><span style="color: #6a9955;">### 需要 JS 文件加载</span></p><p>默认情况下,RequireJS 会将模块名称转换为如下所示的路径helper/worldHTTP(S)</p><p>http://example.com/scripts/helper/world.js</p><p>https://example.com/scripts/helper/world.js</p><p>//example.com/helper/scripts/world.js</p><p>也就是说,模块名称转换为文件路径,最后一段是以 结尾的文件名。默认情况下,RequireJS 将使用脚本所在的文件夹作为其基础(在上面的示例中)。jsrequire.js/scripts</p><p>但是,RequireJS 允许您为脚本设置不同的基本路径。在启动 RequireJS 程序之前,请包含以下代码。</p><p></p><pre class="brush:bash;toolbar:false">require.config({ baseUrl: '/my-javascript-code', });</pre><p>有了上述内容,当 RequireJS 需要加载模块时,它将从helper/world</p><p>http://example.com/my-javascript-code/helper/world.js</p><p>https://example.com/my-javascript-code/helper/world.js </p><p>//example.com/my-javascript-code/helper/world.js</p><p>此功能允许您将javascript文件存储在基于RequireJS的系统中的任何位置。</p><p><span style="color: #6a9955;">### RequireJS:模块命名</span></p><p>到目前为止,在我们的示例中,RequireJS 模块名称已绑定到该模块源在磁盘上的位置。换句话说,模块将始终位于 路径 .helper/worldhelper/world.js</p><p>RequireJS允许您通过配置来更改此设置。例如,如果您希望将模块命名为 ,则需要在程序启动前的某个地方运行以下配置代码helper/worldhello</p><p></p><pre class="brush:bash;toolbar:false">require.config({ paths: { "hello": "helper/world" }, });</pre><p>配置键是我们可以重命名/别名模块的地方。对象的 是所需的名称 (),值是模块的实际名称 ()。pathskeypathshellohelper/world</p><p>完成上述配置后,以下程序</p><p></p><pre class="brush:bash;toolbar:false">requirejs(['hello'], function(hello) { alert("Hello World"); });</pre><p>将从路径加载模块。hellohelper/world.js</p><p><span style="color: #6a9955;">### Magento 2 和 RequireJS</span></p><p>这就把我们带到了Magento的RequireJS实现。Magento为您拉入了主要的RequireJS库,包括一些额外的配置,并提供了一种机制,可以让您添加自己的其他RequireJS配置。</p><p>你要注意的第一件事是Magento 2对RequireJS上述功能的使用。如果您查看Magento页面的源代码,您将看到如下所示的内容baseUrl</p><pre class="brush:bash;toolbar:false"><script type="text/javascript"> require.config( {"baseUrl":"http://magento.example.com/static/adminhtml/Magento/backend/en_US"} ); </script></pre><p>通过上述配置,这意味着当Magento 2遇到一个名为的RequireJS模块时,它将从如下所示的URL加载该模块源。helper/world</p><p>http://magento.example.com/static/adminhtml/Magento/backend/en_US/helper/world.js</p><p>如果您已经阅读了本系列的前几篇文章,您可能会将该 URL 识别为“从 Magento 模块加载前端静态资产”URL。这意味着您可以将 RequireJS 模块定义文件放在模块中</p><p>app/code/Package/Module/view/base/web/my_module.js</p><p>它将自动作为名为 RequireJS 模块提供</p><p>Package_Module/my_module</p><p>通过以下网址加载</p><p>http://magento.example.com/static/adminhtml/Magento/backend/en_US/Package_Module/my_module.js</p><p>这也意味着您可以使用如下所示的代码立即开始在模板中编写程序requirejsphtml</p><pre class="brush:bash;toolbar:false"><script type="text/javascript"> requirejs('Package_Module/my_module', function(my_module){ //...program here... }); </script></pre><p>或者通过添加独立的 JavaScript 文件来执行相同的操作。</p><p><span style="color: #6a9955;">### 通过模块配置 RequireJS</span></p><p>在本教程的前面,我们介绍了两个 RequireJS 配置指令 — 和 .还有很多其他的RequireJS配置指令,当你进入框架的高级使用(或者你正在处理进入高级使用的Magento核心代码)时,你会发现你需要使用它们。baseUrlpath</p><p>每个Magento模块都能够通过名为.的特殊视图文件添加RequireJS配置指令。requirejs-config.js</p><pre class="brush:bash;toolbar:false">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</pre><p>这是一个特殊的javascript文件,Magento将使用区域层次结构在每次页面加载时自动加载该文件。我们要试一试。首先,我们需要创建一个名为 .您可以使用以下命令使用 pestle 命令行框架创建基本模块文件Pulsestorm_RequireJsTutorial</p><pre class="brush:bash;toolbar:false">$ pestle.phar generate_module Pulsestorm RequireJsTutorial 0.0.1</pre><p>然后通过运行以下两个命令在 Magento 中启用该模块<br/></p><pre class="brush:bash;toolbar:false">$ php bin/magento module:enable Pulsestorm_RequireJsTutorial $ php bin/magento setup:upgrade</pre><p>如果你有兴趣手动创建一个模块,或者好奇上面的 pestle 命令实际上在做什么,请查看我们的 Magento 2 简介 — 不再有 MVC 文章。</p><p>无论您如何创建它,一旦创建并启用了模块,请添加以下文件</p><p></p><pre class="brush:bash;toolbar:false">//File: app/code/Pulsestorm/RequireJsTutorial/view/base/requirejs-config.js alert("Hello");</pre><p>要了解RequireJS是如何做到这一点的,我们需要看看Magento实际在哪里提取这些文件。如果您查看Magento安装中的任何源页面,您应该会看到如下所示的标记requirejs-config.js</p><pre class="brush:bash;toolbar:false"><script type="text/javascript" src="http://magento.example.com/static/_requirejs/adminhtml/Magento/backend/en_US/requirejs-config.js"></script></pre><p>如果您在浏览器中查看此文件的源代码,您将在如下所示的代码块中看到您的语句alert<br/></p><p></p><pre class="brush:bash;toolbar:false">(function() { alert("Hello World"); require.config(config); })();</pre><p>虽然这不是100%明显,但通过从Magento 2生成这个javascript代码块,我们可以向系统添加额外的RequireJS初始化。requirejs-config.js</p><p>用一个具体的例子来说,这可能更有意义。让我们用以下内容替换我们的requirejs-config.js</p><p></p><pre class="brush:bash;toolbar:false">var config = { paths:{ "my_module":"Package_Module/my_module" } }; alert("Done");</pre><p>我们在这里所做的是定义一个名为 的 JavaScript 变量,并更改了我们的值。如果你回去重新加载,现在可能会更清楚Magento在做什么。configalertrequirejs-config.js</p><p></p><pre class="brush:bash;toolbar:false">(function() { var config = { paths:{ "my_module":"Package_Module/my_module" } }; alert("Done"); require.config(config); })();</pre><p>对于每个人,Magento将创建一个看起来像这样的代码块requirejs-config.js</p><p></p><pre class="brush:bash;toolbar:false">(function() { //CONTENTS HERE require.config(config); })();</pre><p>但替换为 的内容。//CONTENTS HERErequirejs-config.js</p><p></p><pre class="brush:bash;toolbar:false">var config = { paths:{ "my_module":"Package_Module/my_module" } }; alert("Done"); require.config(config);</pre><p>这意味着如果我们在文件中定义一个变量,Magento 最终会将其传递给 .这将允许任何Magento模块开发人员使用RequireJS功能,如,,,或RequireJS配置指令中的许多其他功能之一。configrequirejs-config.jsrequire.configshimpathsbaseUrlmap</p><p><span style="color: #6a9955;">### 了解延迟加载</span></p><p>关于 RequireJS 的另一个重要事情是模块是延迟加载的。RequireJS不会加载任何javascript模块源文件,直到有人将该javascript模块作为依赖项使用。</p><p>换句话说,如果我们使用配置</p><p></p><pre class="brush:bash;toolbar:false">var config = { paths:{ "my_module":"Package_Module/my_module" } };</pre><p>默认情况下,Magento不会加载该文件。Magento只会在你将其用作模块后加载该文件。Package_Module/my_module.js</p><p></p><pre class="brush:bash;toolbar:false">requirejs(['my_module'], function(my_module){ }); requirejs(['Package_Module/my_module'], function(my_module){ }); define(['Package_Module/my_module'], function(my_module){ });</pre><p>请记住,RequireJS的要点是,日常的JavaScript开发人员不需要担心他们的程序如何对其源文件发出HTTP请求。延迟加载是一个实现细节,在理想情况下,它可以为最终用户节省下载特定页面可能不需要的源文件的带宽。</p><p>但是,在不太理想的情况下,这种延迟加载行为可能会使使用较旧的JavaScript框架和库变得棘手。当我们讨论一些jQuery陷阱时,我们将在下面讨论一个例子。</p><p><span style="color: #6a9955;">### 全局 jQuery 对象</span></p><p>即使你决定RequireJS不适合你,并且你想坚持在Magento 2中使用普通的jQuery,你仍然需要了解RequireJS如何与AMD标准之前的库进行交互。</p><p>在Magento 2中,jQuery作为RequireJS模块加载。这意味着如果您尝试使用如下所示的代码</p><pre class="brush:bash;toolbar:false"><script type="text/javascript"> jQuery(function(){ //your code here }); </script></pre><p>您的浏览器会抱怨未定义。这是因为在您将 jQuery 用作 RequireJS 模块之前,全局对象不会被初始化。如果您习惯于编写上述代码,则需要jQueryjQuery</p><p>将其替换为启动 RequireJS 程序执行的代码</p><p>将该程序配置为将模块用作依赖项jquery</p><p>换句话说,像这样的事情</p><p></p><pre class="brush:bash;toolbar:false">requirejs(['jquery'], function(jQuery){ jQuery(function(){ //your code here }); });</pre><p>回顾一下 — 通过调用函数并向其传递模块依赖项列表以及将充当程序主入口点的匿名 JavaScript 函数来开始执行 RequireJS 程序。requirejs</p><p>模块依赖项列表是 的第一个参数 — 即以下代码说“我的程序依赖于模块”requirejsjquery</p><pre class="brush:bash;toolbar:false">requirejs(['jquery'],</pre><p>充当程序主入口点的匿名函数是函数的第二个参数requirejs<br/></p><p></p><pre class="brush:bash;toolbar:false">requirejs(['jquery'], function(jQuery){ //... });</pre><p>RequireJS 将为您调用此函数。对于您配置的每个依赖项,RequireJS 将加载模块并传入其返回的(或者,在 RequireJS 中,导出)模块。</p><p>现代版本的jQuery将检测它们是否包含在RequireJS/AMD环境和返回全局对象的模块中。definejQuery</p><pre class="brush:bash;toolbar:false">if ( typeof define === "function" && define.amd ) { define( "jquery", [], function() { return jQuery; } ); }</pre><p><span style="color: #6a9955;">### RequireJS 和 jQuery 插件</span></p><p>同时使用jQuery和RequireJS还有另一个问题。jQuery库比RequireJS和AMD标准早很多年,开发了自己的插件系统。虽然不是基于模块的,但这个系统在javascript的默认全局环境中玩得相对较好——插件开发人员通过修改单个全局jQuery对象来创建他们的插件。</p><p>这给 RequireJS 带来了一个问题——正如我们上面提到的,在程序中使用模块之前,直到 RequireJS 调用该程序的主入口函数,才会定义全局对象。这意味着包含jQuery插件的长期存在方式jQueryjqueryrequirejs</p><pre class="brush:bash;toolbar:false"><script src="http://magento.example.com/js/path/to/jquery/plugin/jquery.cookie.js"></pre><p>当插件尝试使用全局对象和/或别名时将失败。jQuery$<br/></p><p>//File: http://magento.example.com/js/path/to/jquery/plugin/jquery.cookie.js</p><p>var <span style="color: #569cd6;">config</span> = $.<span style="color: #569cd6;">cookie</span> = function (key, value, options) {</p><p>如果你想包含一个jQuery插件在Magento 2中使用,你需要通过RequireJS来完成。幸运的是,这个过程相对简单。</p><p>首先,您需要使用配置属性为插件路径创建别名。paths</p><p></p><pre class="brush:bash;toolbar:false">var config = { paths:{ "jquery.cookie":"Package_Module/path/to/jquery.cookie.min" } };</pre><p>上面的配置创建了一个名为的模块,该模块指向模块中的 jQuery cookie 插件源文件。jquery.cookiePackage_Module</p><p>在这一点上,你可能会认为通过做这样的事情来开始使用你的插件的jQuery是可以的</p><p></p><pre class="brush:bash;toolbar:false">requirejs(['jquery','jquery.cookie'], function(jQuery, jQueryCookie){ //my code here });</pre><p>毕竟,将两者和依赖项列出应该会触发两个文件的加载。jqueryjquery.cookie</p><p>配置方面,这看起来像</p><p></p><pre class="brush:bash;toolbar:false">var config = { paths:{ "jquery.cookie":"Package_Module/path/to/jquery.cookie.min" }, shim:{ 'jquery.cookie':{ 'deps':['jquery'] } } };</pre><p></p><p><br/></p>
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>许多流行的PHP框架实现了依赖注入系统——尽管说它们实现了自动依赖注入系统会更准确。在我们深入研究Magento的系统之前,我们要解释一下依赖注入要解决的问题。</p><p><span style="color: #6a9955;">### 了解依赖关系注入</span></p><p>理解依赖注入的最简单方法是通过示例。考虑以下PHP方法/伪代码</p><pre class="brush:bash;toolbar:false">//Obviously contrived -- if only getting a price were this simple public function getFormattedPrice($sku) { $db = new DBHandler; $row = $db->query('SELECT price FROM products WHERE sku = ?', $sku); $formatter = new PriceFormatter; return $formatter->asDollars($row['price']); }</pre><p>这是一个简化的示例,说明了获取产品价格的方法可能是什么样子的。从表面上看,这种方法没有错。它实例化数据库处理程序价格查询实例化格式化程序对象</p><p>使用格式化程序对象返回格式化价格</p><p>当其他人想要重用此方法时,问题就出现了。此方法现在依赖于特定类和特定类。即使你认为代码重用是一个不真实的行业神话,这两个依赖关系也使此方法更难在自动化框架中进行测试。您的测试框架现在依赖于与实际应用程序建立相同的数据库连接。DBHandlerPriceFormatter</p><p>此问题的解决方案是不要使用具有这些依赖项的方法。相反,您应该将依赖项注入到方法中。</p><pre class="brush:bash;toolbar:false">public function getFormattedPrice($sku, $db, $formatter) { $row = $db->query('SELECT price FROM products WHERE sku = ?', $sku); return $formatter->asDollars($row['price']); }</pre><p>重写后,此方法有两个新参数。这个想法是客户端程序员应该传入实例化的对象(即注入依赖项)。</p><p>这就是依赖注入的全部内容——维基百科条目有更多关于这个概念的例子,如果你能忍受 java 的例子,值得一读!</p><p><span style="color: #6a9955;">### 现代依赖注入</span></p><p>依赖注入是一个非常简单的概念,但如果你以前从未遇到过它,可能会有一些疑问在你的脑海中挠头。其中之一可能是这个</p><pre class="brush:bash;toolbar:false">public function prepareDataForDisplay() { //... $data = new stdClass; $db = new DBHandler; $formatter = new PriceFormatter; $data['price'] = $this->getFormattedPrice($row['price']); //... } public function getFormattedPrice($sku, $db, $formatter) { $row = $db->query('SELECT price FROM products WHERE sku = ?', $sku); return $formatter->asDollars($row['price']); }</pre><p>虽然我们已经替换了依赖项 - 我们真正所做的只是将它们转移到调用的方法(上面)的级别。因此,从概念上讲,依赖关系注入很简单,但是在哪里注入依赖关系以及在哪里实例化这些对象是悬而未决的。getFormattedPricegetFormattedPriceprepareDataForDisplay</p><p>这是许多PHP框架试图通过某种自动依赖注入来解决的问题。通过创建一个自动注入这些类型的依赖项的系统,框架消除了由谁以及如何注入依赖项的问题。如果这没有意义,请不要担心。在看了Magento的依赖注入的例子之后,它应该开始变得更有意义了。</p><p><span style="color: #6a9955;">### Magento 依赖注入</span></p><p>就像我们上次所做的那样,我们准备了一个包含一些示例代码的模块。该模块位于 GitHub 上,最简单的安装方法是手动下载最新版本。</p><p>如果您需要手动安装Magento扩展的帮助,我们之前的系列文章提供了完整的说明。</p><p>让我们通过运行以下命令来确保正确安装模块</p><p>$ php bin/magento ps:tutorial-object-manager-2</p><p>Hello Again World!</p><p>如果您看到“Hello Again World!”消息,您就可以开始了。</p><p>如果我们看一下实现命令的类,我们会看到以下内容。</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $manager = $this->getObjectManager(); $helper = $this->getObjectManager()->create( '\Pulsestorm\TutorialObjectManager2\Model\Example'); $output->writeln( $helper->sendHelloAgainMessage() ); }</pre><p>我们在该方法中所做的只是实例化一个对象并调用其方法来获取一些输出文本。如果你看看这个类的构造函数executePulsestorm\TutorialObjectManager2\Model\ExamplesendHelloAgainMessagePulsestorm\TutorialObjectManager2\Model\Example</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Model/Example.php public function __construct() { $object = new Message; // $this->messageObject = $object; }</pre><p>我们看到该类实例化一个对象并将其分配给该属性。我们使用短类名,因为此文件位于命名空间中。如果您需要一些帮助来开始使用 PHP 命名空间,我们的入门是一个不错的选择。Pulsestorm\TutorialObjectManager2\Model\MessagemessageObjectMessagePulsestorm\TutorialObjectManager2\Model</p><p>然后,在方法sendHelloAgainMessage</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Model/Example.php public function sendHelloAgainMessage() { return $this->messageObject->getMessage(); }</pre><p>我们使用对象返回文本消息。Message</p><p>我们的(人为的)类对对象具有硬编码的依赖关系。以下是Magento 2如何解决这个问题。打开类定义文件,让我们将构造函数替换为以下代码Pulsestorm\TutorialObjectManager2\Model\ExamplePulsestorm\TutorialObjectManager2\Model\MessageExample.php</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Model/Example.php public function __construct(Message $message) { $this->messageObject = $message; }</pre><p>我们在这里所做的是向构造函数添加一个名为的参数,然后将该参数分配给属性。换句话说,我们已将硬编码依赖项替换为参数。这允许开发人员注入依赖项。您还会注意到我们在参数中包含了一个类型提示。$messagemessageObject</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Model/Example.php __construct(Message $message);</pre><p>此类型提示强制开发人员传入一个对象,该对象要么是对象,要么是其祖先链。同样,我们使用了短类名。以下内容本来是等效的,但要冗长得多。Pulsestorm\TutorialObjectManager2\Model\MessagePulsestorm\TutorialObjectManager2\Model\MessageMessage</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Model/Example.php __construct(\Pulsestorm\TutorialObjectManager2\Model\Message $message);</pre><p>如果您不熟悉类型提示,我们准备了有关它们的入门。</p><p>如果这是一个传统的PHP应用程序,我们会用如下所示的代码注入依赖项</p><p></p><pre class="brush:bash;toolbar:false">$dependency = new \Pulsestorm\TutorialObjectManager2\Model\Message; $helper = new \Pulsestorm\TutorialObjectManager2\Model\Example($dependency);</pre><p>但是,对于Magento 2的对象系统,我们无法提供参数。</p><pre class="brush:bash;toolbar:false">$helper = $this->getObjectManager()->create('Pulsestorm\TutorialObjectManager2\Model\Example');</pre><p>那么我们应该怎么做呢?<br/></p><p>这就是Magento 2的自动依赖注入系统的美妙之处。你不需要做任何事情。只需使用我们的新代码运行命令即可。</p><pre class="brush:bash;toolbar:false">$ php bin/magento ps:tutorial-object-manager-2 Hello Again World!</pre><p>相同的结果 — 即使我们没有做任何事情来传入参数。</p><p>这是自动依赖注入。在幕后,对象管理器将使用 PHP 的反射功能来查看类的类型提示/参数,自动为我们实例化对象,然后将其作为参数传递到构造函数中。__construct</p><p>第一次遇到它时,这似乎有点奇怪,但如果您不相信我们,只需向您的构造函数添加一些调试代码即可</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Model/Example.php public function __construct(Message $message) { var_dump(get_class($message)); exit; $this->messageObject = $message; }</pre><p>重新运行该命令,您将看到打印出的类名。</p><p></p><pre class="brush:bash;toolbar:false">$ php bin/magento ps:tutorial-object-manager-2 string(47) "Pulsestorm\TutorialObjectManager2\Model\Message"</pre><p>一旦你克服了怪异,你可能会想知道为什么这更好。类型提示现在不就是硬编码依赖项吗?</p><p>不同之处在于对象管理器可以控制依赖项的实例化。作为模块开发人员,我们有很大的权力来改变对象管理器实例化注入的依赖项的方式。这是通过模块的文件(代表依赖注入)发生的。虽然Magento 2没有“类重写” - 它确实具有类似的,更强大的功能,所有这些都可以通过文件进行配置。在接下来的几篇文章中,我们将探讨所有这些选项,您将学习如何完全控制这些依赖项。etc/di.xmldidi.xml</p><p>这么长时间的对象管理器,我们几乎不认识你</p><p>在我们结束今天的比赛之前,还有最后一件事要做。如果你浏览Magento 2当前关于Magento 2对象系统的文档(通常标记为依赖注入),你会看到如下神秘的评论。</p><p>对象管理器必须仅在编写代码时存在,编写代码在引导过程的早期执行</p><p>此外,如果您一直密切关注Magento 2的开发,您就会知道曾经有一个静态工厂方法来抓取对象管理器实例,但该方法已被弃用并删除。</p><p>对象管理器类不适用于Magento 2中的日常使用。它(按照惯例)是为处理引导Magento的代码的系统级开发人员保留的。我们在这些教程中提供的方法是一个帮助程序,因此您可以了解对象管理器是什么。getObjectManager</p><p>如果您遵循Magento扩展开发的最佳实践,您将使用依赖注入来实例化几乎所有对象。起初这似乎是不可能的(我在2013年翻了个白眼),但随着Magento 2接近完成,越来越清楚这实际上是可能的。</p><p>我们将在以后的文章中介绍实现这一点的依赖关系注入功能。然而,这里有一些高层的保证,即“没有objet经理”并不像听起来那么疯狂。</p><p>Magento中的所有对象都使用对象管理器进行实例化 - 包括依赖项。换句话说,使用注入注入的对象本身可以具有具有自动注入依赖项的方法。__construct__construct</p><p>数据管理对象(我们过去称之为“ORM模型”)可以通过工厂对象实例化 - 这些工厂对象可以通过依赖注入注入。</p><p>如果它一直向下是依赖注入,您可能想知道堆栈顶部的内容。但请记住,所有有效的代码入口点(控制器操作方法、观察者对象/方法、块对象、Symfony 控制台命令等)都是通过配置创建的。这意味着Magento知道它们,当它需要实例化它们时,它使用对象管理器。这意味着所有这些对象都有注入__construct</p><p>尽管不建议这样做,并且可能会在未来的版本中消失,但到目前为止,有一种方法可以获取对象管理器的实例</p><p>关于最后一项?查看基类Pulsestorm\TutorialObjectManager2\Command\AbstractCommand</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Command/AbstractCommand.php use \Magento\Framework\ObjectManagerInterface; //... public function __construct(ObjectManagerInterface $manager) { $this->objectManager = $manager; parent::__construct(); } protected function getObjectManager() { return $this->objectManager; }</pre><p>这是我们教程模块的 cli 类的基类,也是实现的位置。我们如何获得对象管理器的实例?当然,通过使用依赖注入!getObjectManager</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager2/Command/AbstractCommand.php public function __construct(ObjectManagerInterface $manager)</pre><p>这种模式可能需要一点时间来适应,并且可能看起来有点矫枉过正。但是,在企业环境中,一致性比本垒打更重要。沿着这条道路限制日常开发,并将更多的创造性工作留给深层次的系统开发人员,一个专注于敏捷的团队可以更好地完成最后期限并计算其速度。尽管它们很无聊和企业化,但这些设计模式是确保Magento 2稳步,无情地向发布迈进的重要组成部分。</p><p><br/></p>
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>本文是解释Magento 2的对象管理器/依赖注入系统的系列文章中的第一篇。我们将探讨程序员(你!)如何在Magento 2中创建对象,探索Magento 2的对象系统带来的其他功能,在此过程中,我们将讨论Magento 1的变化,并开始探索Magento 2的约定。</p><p><span style="color: #6a9955;">### Magento 2命令行框架</span></p><p>Magento 2的架构转变带来的重大变化之一是命令行框架。这不是Magento 1中的简单框架(在我的短书No Frills Command Line Magento中讨论过)。相反,Magento 2附带了Symfony控制台组件的完整实现。</p><p>安装 Magento 2 后,您可以通过打开终端应用程序并键入以下命令来查看系统附带的默认命令列表。</p><p>$ php bin/magento</p><p>您应该看到如下所示的输出。</p><pre class="brush:bash;toolbar:false">Magento CLI version 0.74.0-beta16 Usage: command [options] [arguments] Options: --help (-h) Display this help message --quiet (-q) Do not output any message --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug --version (-V) Display this application version --ansi Force ANSI output --no-ansi Disable ANSI output --no-interaction (-n) Do not ask any interactive question Available commands: help Displays help for a command list Lists commands //... full command list snipped ...</pre><p>除了附带许多有用的命令外,第三方开发人员还可以创建Magento模块,向系统添加新命令。</p><p>在本教程中,我们将使用命令行框架来运行代码示例。命令行是一个很好的干净的地方,可以运行示例代码,观察输出,并且无需担心浏览器页面加载和Magento代码运行之间的抽象层和层。</p><p><span style="color: #6a9955;">### 安装教程示例代码</span></p><p>我们准备了一个Magento 2模块,其中包含一个简单的命令行界面(cli)命令。Magento 2模块安装的方法和原因仍在到位,所以现在我们最好的选择是手动安装这个模块。</p><p>我们已将模块源代码放在 GitHub 上。此模块将添加一个名为 的命令,我们将在下面使用它。安装此模块ps:tutorial-object-manager-1</p><p><span style="color: #6a9955;">### 导航到 GitHub 发布页面</span></p><p>找到最新版本(编写本教程时的 0.0.3 现在是 0.0.4),然后单击 或 链接下载版本存档ziptar.gz</p><p>将存档源提取到Magento 2安装中,与文件夹结构匹配app</p><p>您现在应该能够从Magento安装的根目录运行以下命令,并查看模块的顶级文件。lsPulsestorm_TutorialObjectManager1</p><pre class="brush:bash;toolbar:false">$ ls -l app/code/Pulsestorm/TutorialObjectManager1/ total 0 drwxr-xr-x@ 4 alanstorm staff 136 Jul 9 08:49 Command drwxr-xr-x@ 3 alanstorm staff 102 Jul 9 08:49 Model drwxr-xr-x@ 4 alanstorm staff 136 Jul 9 08:49 etc</pre><p>您还可以通过运行以下命令来检查模块是否已正确安装module:status</p><pre class="brush:bash;toolbar:false">$ php bin/magento module:status List of enabled modules: Magento_Store //...</pre><p>如果已将模块正确解压缩到文件夹中,则在运行 时应看到类似于上述的输出。不过,眼尖的读者会注意到一个问题——虽然存在,但它被列为禁用模块。我们需要告诉Magento 2此模块已启用。app/codemodule:statusPulsestorm_TutorialObjectManager1</p><p>为此,我们需要编辑文件。在您喜欢的文本编辑器中打开此文件并查找以下部分app/etc/config.php</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/etc/config.php <?php return array ( 'modules' => array ( 'Magento_Store' => 1, //... full module list snipped ... 'Magento_Wishlist' => 1, ), );</pre><p>该文件是一个简单的 PHP 包含文件,返回已配置模块的数组。您看到的模块是系统附带的核心模块。我们希望将模块添加到此列表的末尾。app/etc/config.php</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/etc/config.php <?php return array ( 'modules' => array ( 'Magento_Store' => 1, //... full module list snipped ... 'Magento_Wishlist' => 1, 'Pulsestorm_TutorialObjectManager1' => 1 ), );</pre><p>现在如果我们运行 ,我们应该看到我们的模块列在启用列表中。module:status</p><pre class="brush:bash;toolbar:false">$ php bin/magento module:status List of enabled modules: Magento_Store //... Pulsestorm_TutorialObjectManager1 List of disabled modules: None</pre><p>与Magento 1相同,模块的全名来自其“命名空间”文件夹和“模块名称”文件夹的组合。但是,这里有一些事情可能会让Magento 1开发人员陷入循环。具体说来</p><p>Magento的模块命名空间现在代替了Magento_Mage_</p><p>和代码池消失了。所有模块都位于corecommunitylocalapp/code</p><p>核心团队已将“模块声明文件”替换为更简单的基于 PHP 的配置app/etc/modules</p><p>在我看来,要更改是中立的,但是删除代码池和模块声明文件对Magento来说是积极的。MagentoMage</p><p>虽然、、和代码池/包含文件夹允许系统所有者通过代码池覆盖对Magento功能进行快速更改,但这些文件在很大程度上导致了商家不愿意升级他们的系统,并且当开发人员更改过多的类文件的隐式契约时,通常会导致微妙的系统问题。corecommunitylocal</p><p>模块声明文件的丢失 - 虽然是一个有趣的想法(整个系统的一个全局配置)的一部分 - 不会被错过。虽然这些文件的初衷可能是配置哪些模块应该或不应该在系统中启用,但早期开发人员的布道和核心团队实践不佳意味着扩展开发人员开始将这些文件与他们的扩展打包在一起,并且任何希望这些文件是用户可配置的文件都消失了。简单的开/关配置阵列的Magento 2方法更有意义。app/etc/modules</p><p><span style="color: #6a9955;">### 运行命令和清除缓存</span></p><p>好的,现在我们已经安装了模块,我们要确保显示新命令。在我们这样做之前,还有一步要做。我们需要清除Magento的缓存。ps:tutorial-object-manager-1</p><p>从概念上讲,Magento 2中的缓存清除与Magento 1相同。有长时间运行的操作将运行一次,然后Magento缓存结果以便下次更快地加载。例如,虽然我们已经将新模块添加到Magento的配置中,但Magento的配置是缓存的,因此正在运行的系统实际上还不知道我们的模块。</p><p>Magento 2提供了一个用于清除缓存的cli命令。只需运行以下内容,您应该就可以开始了。</p><pre class="brush:bash;toolbar:false">$ php bin/magento cache:clean Cleaned cache types: config layout block_html view_files_fallback view_files_preprocessing collections db_ddl eav full_page translate config_integration config_integration_api config_webservice</pre><p>我们说应该,因为尽管这将清除Magento的所有缓存类型,但这并不是100%清楚这是否会清除整个缓存。Magento 1包含许多非类型的缓存条目(例如Zend的模块列名称),Magento 1的缓存清除命令不会删除这些条目。Magento 2对于我们来说还太年轻,无法发现这些边缘情况,但是如果您不确定Magento的缓存是否被清除并且使用的是默认缓存存储,则可以通过手动删除Magento文件夹中的所有文件和文件夹来取消整个缓存。var/cache</p><p>$ rm -rf /path/to/magento/var/cache/*</p><p>此外,虽然它与我们在这里无关,但Magento 2也使用了一些自动代码生成功能,虽然不是严格的缓存,但如果某些系统配置或代码文件被更改/更新,则可能需要重新生成。如果要清除缓存,最好清除这些生成的代码文件。在开发计算机上执行此操作的最快和最简单的方法是删除</p><p>$ rm -rf /path/to/magento/var/generation/*</p><p>对于生产系统,您需要小心执行此操作。Magento 2仍然足够新,以至于代码生成的所有陷阱尚未被发现。</p><p>假设您已经清除了缓存,让我们寻找我们的命令。您可以使用命令查看命令列表list</p><pre class="brush:bash;toolbar:false">$ php bin/magento list //... ps:tutorial-object-manager-1 A cli playground for testing commands //...</pre><p>假设您看到上面的命令,让我们尝试运行它!</p><pre class="brush:bash;toolbar:false">$ php bin/magento ps:tutorial-object-manager-1 You did it!</pre><p>祝贺!您只需手动安装第一个Magento模块。</p><p>更新:Kristof Ringleff指出,实际上有两个命令可以启用/禁用Magento 2模块(和)。在设置新模块时,您肯定希望使用这些命令module:enablemodule:disable</p><pre class="brush:bash;toolbar:false">$ php bin/magento module:enable Pulsestorm_TutorialObjectManager1 - Pulsestorm_TutorialObjectManager1 To make sure that the enabled modules are properly registered, run 'setup:upgrade'. Cache cleared successfully. Generated classes cleared successfully. Alert: Generated static view files were not cleared. You can clear them using the --clear-static-content option. Failure to clear static view files might cause display issues in the Admin and storefront.</pre><p>/ 命令的好处是他们会module:enablemodule:disable</p><p><span style="color: #6a9955;">### 自动为您清除缓存</span></p><p>自动为您删除生成的旧代码</p><p>通知您可能需要执行的其他操作</p><p>允许您启用/禁用模块,即使用于启用/禁用模块的内部方法发生变化</p><p>更改我们的命令</p><p>我们几乎准备好开始讨论对象管理器了。现在我们已经安装了示例模块,让我们尝试更改 的实现。ps:tutorial-object-manager-1</p><p>Magento 2中的每个cli命令都是用PHP类实现的。要更改命令的实现,您需要做的就是在您喜欢的文本编辑器中打开此类文件。尝试打开以下文件,并找到执行方法</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("You did it!"); }</pre><p>然后,编辑命令定义文件,使其如下所示</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("Hello World!"); }</pre><p>如果我们现在尝试运行该命令,我们应该看到以下输出。</p><pre class="brush:bash;toolbar:false">$ php bin/magento ps:tutorial-object-manager-1 Hello World!</pre><p>我们上面所做的只是将一条消息传递给命令行框架的方法——这是框架的等价物 or 。writelnechoprint</p><p>完成此操作后,我们终于可以开始讨论Magento的对象管理器了。</p><p>首先,让我们回顾一些 PHP 101。当您想在 PHP 中实例化对象时,请使用关键字。让我们在我们的方法中尝试一下newexecute</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $object = new \Pulsestorm\TutorialObjectManager1\Model\Example; $message = $object->getHelloMessage(); $output->writeln( $message ); }</pre><p>尝试运行上面的代码,你应该看到这样的内容</p><pre class="brush:bash;toolbar:false">$ php bin/magento ps:tutorial-object-manager-1 Hello Magento!</pre><p>我们上面所做的只是</p><p>从类实例化对象Pulsestorm\TutorialObjectManager1\Model\Example</p><p>调用结果对象的方法以获取消息字符串,getHelloWorld</p><p>使用命令行框架的方法输出消息。writeln</p><p>到目前为止,这是普通的旧 PHP — 如果您不熟悉 PHP 命名空间或那些反斜杠字符,您可能会发现这个命名空间入门很有用。</p><p>没有什么能阻止你在Magento 2中使用普通的旧PHP类。但是,如果你想利用Magento 2的高级对象功能(自动构造函数依赖注入,对象代理等),你需要使用Magento的对象管理器。尝试以下代码</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $manager = $this->getObjectManager(); $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example'); $message = $object->getHelloMessage(); $output->writeln( $message ); }</pre><p>运行上面的代码,你应该看到相同的输出</p><pre class="brush:bash;toolbar:false">$ php bin/magento ps:tutorial-object-manager-1 Hello Magento!</pre><p>这个新代码和我们的旧代码之间的最大区别在于这两行</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $manager = $this->getObjectManager(); $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example');</pre><p>第一个,,为我们获取对象管理器。这不是您在编写Magento 2扩展时通常会做的事情 - 这是我们为本教程添加的帮助程序方法。我们稍后会回到这个概念,但现在接受 将返回 Magento 对象管理器的实例。$<span style="color: #569cd6;">manager</span> = $this->getObjectManager()<span style="color: #6a9955;">;getObjectManagergetObjectManager</span></p><p>对象管理器是一个特殊的对象,Magento用它来实例化几乎所有的对象。这就是我们在第二行所做的</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example');</pre><p>我们调用了对象管理器的方法,并以字符串形式传入 PHP 类名。在后台,对象管理器为我们实例化了一个。createPulsestorm\TutorialObjectManager1\Model\Example</p><p>最简单的形式就是Magento 2的对象管理器。这似乎是一个微不足道的差异,但是通过这个单一点路由所有对象实例化,Magento系统工程师能够赋予他们的对象许多“超能力”。</p><p>在我们讨论超能力之前,虽然完全介绍它超出了本文的范围,但Magento对象管理器的源代码在下面的类文件中。</p><pre class="brush:bash;toolbar:false">#File: lib/internal/Magento/Framework/ObjectManager/ObjectManager.php namespace Magento\Framework\ObjectManager; class ObjectManager implements \Magento\Framework\ObjectManagerInterface { //... }</pre><p>如果您是Magento 1开发人员,则对象管理器可以替代这三种方法。</p><p></p><pre class="brush:bash;toolbar:false">Mage::getModel(...); Mage::helper(...); Mage::getSingleton('core/layout')->createBlock(...);</pre><p>虽然Magento 2仍然具有模型,帮助程序和块的概念,但您不再需要知道这些对象的类别名(,等)。对象管理器可以实例化任何PHP类,而不仅仅是模型,帮助程序或块对象。core/templatemodel/product</p><p><span style="color: #6a9955;">### 自动单例对象</span></p><p>我们今天将通过讨论Magento的对象管理器赋予对象的超能力之一来结束 - 自动单例。不过,在我们这样做之前,我们可能应该描述一下我们所说的单例是什么意思!</p><p>尝试运行以下代码</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $manager = $this->getObjectManager(); $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example'); $object->message = 'Hello PHP!'; $output->writeln( $object->getHelloMessage() ); $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example'); $output->writeln( $object->getHelloMessage() ); }</pre><p>你应该看到这样的输出</p><pre class="brush:bash;toolbar:false">$ php bin/magento ps:tutorial-object-manager-1 Hello PHP! Hello Magento!</pre><p>此代码类似于我们之前的示例,但增加了一些内容。首先,我们使用对象管理器从类中实例化一个对象。Pulsestorm\TutorialObjectManager1\Model\Example</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example');</pre><p>然后我们为对象设置一个自定义消息字符串</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $object->message = 'Hello PHP';</pre><p>然后我们使用 cli 框架的方法输出新消息。writeln</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $output->writeln( $object->getHelloMessage() );</pre><p>这是第一段代码。在第二个代码块中</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example'); $output->writeln( $object->getHelloMessage() );</pre><p>我们实例化了一个新对象,然后输出其默认消息。这意味着我们的程序输出Pulsestorm\TutorialObjectManager1\Model\Example</p><pre class="brush:bash;toolbar:false">Hello PHP! Hello Magento!</pre><p>是自定义消息,后跟默认消息。</p><p>非常简单的东西。</p><p>现在,让我们尝试完全相同的代码,只是我们将使用对象管理器的方法,而不是使用对象管理器的方法createget</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $manager = $this->getObjectManager(); $object = $manager->get('Pulsestorm\TutorialObjectManager1\Model\Example'); $object->message = 'Hello PHP!'; $output->writeln( $object->getHelloMessage() ); $object = $manager->get('Pulsestorm\TutorialObjectManager1\Model\Example'); $output->writeln( $object->getHelloMessage() ); } Run this code, and your output will be a little different. $ php bin/magento ps:tutorial-object-manager-1 Hello PHP Hello PHP</pre><p>我们的程序没有第二次打印默认消息,而是打印了我们在第一个对象上设置的相同自定义消息。为什么会这样?因为第二个对象是第一个对象。</p><p>这是Magento对象管理器的“自动单例”功能。如果您不熟悉这个概念,单例是一个只能实例化一次的对象。使用单例,将来实例化同一对象的尝试将返回原始实例。传统上,这是通过向类的构造函数添加特殊代码来实现的,但是使用Magento 2的对象管理器,任何类都可以转换为单例对象。</p><p>将返回上面的代码示例,第二次调用Magento时,我们返回了带有自定义消息集的原始对象。get</p><p>如果你来自Magento 1,/差异类似于createget</p><p></p><pre class="brush:bash;toolbar:false">Mage::getModel(...); Mage::getSingleton(...);</pre><p>差异。同样,这适用于Magento 2中的所有类和对象,而不仅仅是模型对象。</p><p>自动单例只是Magento 2的对象管理器赋予其对象的超能力之一。下次我们将讨论巨大的超能力 - 自动构造函数参数依赖注入 - 我们还将揭示为什么Magento的文档(看似矛盾)告诉你不要使用对象管理器。</p><p><br/></p>
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>虽然KnockoutJS将自己标榜为MVVM(模型,视图,视图模型)框架,但PHP开发人员会发现模型部分有点薄。KnockoutJS本身没有数据存储的原生概念,并且像许多现代JavaScript框架一样,它被设计为与仅服务后端配合使用的最佳效果。即 KnockoutJS 的“模型”是其他一些框架,发出 AJAX 请求以填充视图模型值。</p><p>KnockoutJS可能会让你措手不及的另一件事是,它不是一个“全栈”的javascript应用程序框架(值得称赞的是,它不会这样标榜自己)。KnockoutJS对你如何把它包含在你的项目中,或者你如何组织你的代码没有意见(尽管文档清楚地表明KnockoutJS团队成员是RequireJS的粉丝)。</p><p>这给像Magento这样的服务器端PHP框架带来了一个有趣的挑战。不仅有一定程度的JavaScript脚手架需要围绕KnockoutJS,而且Magento 2不是一个纯服务的框架。虽然Magento 2的新API功能正在朝着这个方向大踏步前进,但Magento 2并不是一个纯服务的框架。即后端框架开发人员还需要构建脚手架以将业务对象数据放入 KnockoutJS。</p><p>今天我们将深入探讨Magento 2的KnockoutJS集成。在本教程结束时,您将了解Magento 2如何应用KnockoutJS绑定以及Magento 2如何初始化自己的自定义绑定。您还将了解Magento如何修改一些核心的KnockoutJS行为,为什么他们这样做,以及这些更改为您自己的应用程序和模块打开的其他可能性。</p><p>本文是介绍Magento 2中高级JavaScript概念的较长系列的一部分。虽然阅读之前的文章不是100%强制性的,但如果您在下面的概念上苦苦挣扎,您可能需要在下面的评论中指出您的Magento Stack Exchange问题之前查看以前的文章。</p><p><span style="color: #6a9955;">### 创建Magento模块</span></p><p>虽然这篇文章是javascript的重,但我们希望我们的示例代码在具有Magento基线HTML的页面上运行。这意味着添加一个新模块。我们将按照本系列第一篇文章中相同的方式执行此操作,并使用 pestle 创建一个具有 URL 端点的模块</p><pre class="brush:bash;toolbar:false">$ pestle.phar generate_module Pulsestorm KnockoutTutorial 0.0.1 $ pestle.phar generate_route Pulsestorm_KnockoutTutorial frontend pulsestorm_knockouttutorial $ pestle.phar generate_view Pulsestorm_KnockoutTutorial frontend pulsestorm_knockouttutorial_index_index Main content.phtml 1column $ php bin/magento module:enable Pulsestorm_KnockoutTutorial $ php bin/magento setup:upgrade</pre><p>任何通过Magento 2 for PHP MVC开发人员系列工作的人都应该熟悉这些命令。运行上述操作后,您应该能够在系统中访问以下URL</p><p>http://magento.example.com/pulsestorm_knockouttutorial/</p><p>并查看呈现的模板。Pestle在这里不是强制性的 - 如果您有使用Magento页面的首选方式,请随意使用它。app/code/Pulsestorm/KnockoutTutorial/view/frontend/templates/content.phtml</p><p><span style="color: #6a9955;">### 需要JS初始化</span></p><p>在我们上一篇文章和官方的 KnockoutJS 教程中,KnockoutJS 初始化是一件简单的事情。</p><p><span style="color: #569cd6;"></span></p><pre class="brush:bash;toolbar:false">object = SomeViewModelConstructor(); ko.applyBindings(object);</pre><p>对于教程应用程序,这是有道理的。但是,如果您要将所有视图模型逻辑,自定义绑定,组件等保留在单个代码块中,则KnockoutJS将很快变得难以管理。</p><p>相反,Magento的核心团队创建了RequireJS模块,当它被列为依赖项时,将执行任何和所有KnockoutJS初始化。你可以像这样使用这个模块Magento_Ui/js/lib/ko/initialize</p><p></p><pre class="brush:bash;toolbar:false">requirejs(['Magento_Ui/js/lib/ko/initialize'], function(){ //your program here });</pre><p>关于这个 RequireJS 模块需要注意的一件有趣的事情是它不返回任何值。相反,将RequireJS模块列为依赖项的唯一目的是启动Magento的KnockoutJS集成。当您在野外看到它时,这可能会让您感到困惑。例如,考虑来自不同Magento RequireJS模块的这段代码。</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/core/app.js define([ './renderer/types', './renderer/layout', 'Magento_Ui/js/lib/ko/initialize' ], function (types, layout) { 'use strict'; return function (data) { types.set(data.types); layout(data.components); }; });</pre><p>声明了三个 RequireJS 依赖项,</p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/core/app.js [ './renderer/types', './renderer/layout', 'Magento_Ui/js/lib/ko/initialize' ]</pre><p>但在生成的函数中仅使用两个参数</p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/core/app.js function (types, layout) { //... }</pre><p>我不清楚这是否是一种聪明的编程,或者它是否违反了 RequireJS 的精神。也许两者兼而有之。</p><p>无论如何,当你第一次在你自己的基于RequireJS的程序中使用这个库时,Magento将初始化KnockoutJS。后续包含实际上不会执行任何操作,因为 RequireJS 会在您第一次加载模块时缓存它们。</p><p><span style="color: #6a9955;">### KnockoutJS 初始化</span></p><p>如果我们看一下模块的来源Magento_Ui/js/lib/ko/initialize</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/lib/ko/initialize.js define([ 'ko', './template/engine', 'knockoutjs/knockout-repeat', 'knockoutjs/knockout-fast-foreach', 'knockoutjs/knockout-es5', './bind/scope', './bind/staticChecked', './bind/datepicker', './bind/outer_click', './bind/keyboard', './bind/optgroup', './bind/fadeVisible', './bind/mage-init', './bind/after-render', './bind/i18n', './bind/collapsible', './bind/autoselect', './extender/observable_array', './extender/bound-nodes' ], function (ko, templateEngine) { 'use strict'; ko.setTemplateEngine(templateEngine); ko.applyBindings(); });</pre><p>我们看到一个相对简单的程序,但它还包括其他十九个模块。介绍每个模块的功能超出了本文的范围。考虑以下精彩片段。</p><p>模块是模块的别名。koknockoutjs/knockout</p><p></p><pre class="brush:bash;toolbar:false">vendor/magento/module-theme/view/base/requirejs-config.js 11: "ko": "knockoutjs/knockout", 12: "knockout": "knockoutjs/knockout"</pre><p>该模块是实际的挖空库文件。,和</p><p>模块是KnockoutJS社区的额外功能。这些都不是正式的 RequireJS 模块。knockoutjs/knockoutknockoutjs/knockout-repeatknockoutjs/knockout-fast-foreachknockoutjs/knockout-es5</p><p>以 开头的模块是 Magento 对 KnockoutJS 的自定义绑定。这些是正式的 RequireJS 模块,但实际上并不返回模块。相反,每个脚本操作全局对象以向 KnockoutJS 添加绑定。我们将在下面讨论绑定,但如果您是好奇的类型,请尝试调查其他绑定的实现细节。这是一个有用的练习。希望Magento尽快获得我们的官方文档。./bind/*koscope</p><p>这两个模块是KnockoutJS功能的Magento核心扩展。extender</p><p>该模块返回 KnockoutJS 模板引擎的自定义版本,是我们将深入研究的第一个自定义版本。./template/engine</p><p><span style="color: #6a9955;">### Magento KnockoutJS 模板</span></p><p>回顾一下,在股票 KnockoutJS 系统中,模板是预先编写的 DOM/KnockoutJS 代码块,您可以通过引用它们的 .这些块通过脚本标记添加到页面的 HTML 中,其类型idtext/html</p><pre class="brush:bash;toolbar:false"><script type="text/html" id="my_template"> <h1 data-bind="text:title"></h1> </script></pre><p>这是一个强大的功能,但给服务器端框架带来了一个问题——如何在页面上呈现正确的模板?您如何确定模板将在那里而不每次都重新创建它?KnockoutJS的解决方案是将组件绑定与RequireJS等库一起使用,但这意味着您的模板绑定到特定的视图模型对象。</p><p>Magento的核心工程师需要一种更好的方法来加载KnockoutJS模板 - 他们通过将本机KnockoutJS模板引擎替换为从RequireJS模块加载的引擎来实现这一点。Magento_Ui/js/lib/ko/template/engine</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/lib/ko/initialize.js define([ 'ko', './template/engine', //... ], function (ko, templateEngine) { 'use strict'; //... ko.setTemplateEngine(templateEngine); //... });</pre><p>如果我们看一下 RequireJS 模块Magento_Ui/js/lib/ko/template/engine</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/lib/ko/template/engine.js /** * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ define([ 'ko', './observable_source', './renderer' ], function (ko, Source, Renderer) { 'use strict'; var RemoteTemplateEngine, NativeTemplateEngine = ko.nativeTemplateEngine, sources = {}; //... RemoteTemplateEngine.prototype = new NativeTemplateEngine; //... RemoteTemplateEngine.prototype.makeTemplateSource = function (template) { //... } //... return new RemoteTemplateEngine; });</pre><p>我们看到Magento制作了一个新对象,该对象原型继承自本机KnockoutJS渲染引擎,然后修改了一些方法来添加自定义行为。如果你不了解你的javascript内部,这意味着Magento复制了股票KnockoutJS模板系统,对其进行了一些更改,然后将其新模板引擎换成库存模板引擎。</p><p>这些修改的实现细节超出了本文的范围,但最终结果是一个 KnockoutJS 引擎,它可以通过 Magento 模块的 URL 加载模板。</p><p>如果这没有意义,一个例子应该澄清问题。将以下内容添加到我们的文件中。content.phtml</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/KnockoutTutorial/view/frontend/templates/content.phtml <div data-bind="template:'Pulsestorm_KnockoutTutorial/hello'"></div></pre><p>在这里,我们添加了一个 KnockoutJS 绑定并传递给它字符串。如果我们在上述情况下重新加载页面,您将在 javascript 控制台中看到如下错误templatePulsestorm_KnockoutTutorial/hello</p><p>> GET http://magento-2-0-4.dev/static/frontend/Magento/luma/en\_US/Pulsestorm\_KnockoutTutorial/template/hello.html 404 (Not Found)</p><p>Magento采用了我们的字符串()并使用第一部分()来创建视图资源的基本URL,并使用第二部分()和附加的前缀来完成URL。如果我们向以下文件添加 KnockoutJS 视图Pulsestorm_KnockoutTutorial/helloPulsestorm_KnockoutTutorialhellotemplate.html</p><pre class="brush:bash;toolbar:false">#File: app/code/Pulsestorm/KnockoutTutorial/view/frontend/web/template/hello.html <p data-bind="style:{fontSize:'24px'}">Hello World</p></pre><p>并重新加载页面,我们将看到Magento从上面的URL加载了我们的模板,并应用了其KnockoutJS绑定。</p><p>此功能使我们能够避免在需要新模板时用标签乱扔 HTML 页面,并鼓励在 UI 和 UX 功能之间重用模板。<script <span style="color: #569cd6;">type</span>=<span style="color: #ce9178;">"text/html"</span>></p><p><span style="color: #6a9955;">### 无视图模型</span></p><p>回到模块,在Magento设置自定义模板引擎之后,Magento调用KnockoutJS的方法。这将启动将当前 HTML 页面呈现为视图。如果我们看一下该代码,就会立即弹出一些内容。initialize.jsapplyBindings</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/lib/ko/initialize.js ko.setTemplateEngine(templateEngine); ko.applyBindings();</pre><p>Magento在没有视图模型的情况下调用。虽然这是一个合法的 KnockoutJS 调用——告诉 KnockoutJS 在没有数据或视图模型逻辑的情况下应用绑定似乎毫无用处。没有数据的视图有什么用?applyBindings</p><p>在股票KnockoutJS系统中,这将是毫无用处的。理解Magento在这里做什么的关键是在我们的KnockoutJS初始化中备份</p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/lib/ko/initialize.js define([ //... './bind/scope', //... ],</pre><p>Magento的KnockoutJS团队创建了一个名为的自定义KnockoutJS绑定。下面是一个使用范围的示例 - 从Magento 2主页提升。scope</p><pre class="brush:bash;toolbar:false"><li class="greet welcome" data-bind="scope: 'customer'"> <span data-bind="text: customer().fullname ? $t('Welcome, %1!').replace('%1', customer().fullname) : 'Default welcome msg!'"></span> </li></pre><p>当你像这样调用 scope 元素时</p><p><span style="color: #569cd6;">data-bind</span>=<span style="color: #ce9178;">"scope: 'customer'"</span></p><p>Magento将客户视图模型应用于此标签及其后代。</p><p>您可能想知道 - 客户视图模型到底是什么?!如果您在主页的源代码中再往下看一点,您应该会看到以下脚本标记</p><pre class="brush:bash;toolbar:false"><script type="text/x-magento-init"> { "*": { "Magento_Ui/js/core/app": { "components": { "customer": { "component": "Magento_Customer/js/view/customer" } } } } } </script></pre><p>正如我们从本系列的第一篇文章中知道的那样,当Magento遇到带有属性的脚本标签时,它将text/x-magento-init*</p><p>初始化指定的 RequireJS 模块 (Magento_Ui/js/core/app)</p><p>调用该模块返回的函数,传入数据对象</p><p>RequireJS 模块是一个实例化 KnockoutJS 视图模型以与属性一起使用的模块。它的完整实现超出了本文的“范围”,但在高层次上,Magento将为每个配置为的RequireJS模块实例化一个新的javascript对象,并且该新对象成为视图模型。Magento_Ui/js/core/appscopecomponent</p><p>如果这没有意义,让我们通过上面的示例。Magento查看密钥,并看到一个密钥/对象对。x-magento-initcomponents</p><pre class="brush:bash;toolbar:false">"customer": { "component": "Magento_Customer/js/view/customer" }</pre><p>因此,对于密钥,Magento将运行等效于以下内容的代码。customer</p><p></p><pre class="brush:bash;toolbar:false">//gross over simplification var ViewModelConstructor = requirejs('Magento_Customer/js/view/customer'); var viewModel = new ViewModelConstructor; viewModelRegistry.save('customer', viewModel);</pre><p>如果特定组件对象中有额外的数据</p><pre class="brush:bash;toolbar:false">"customer": { "component": "Magento_Customer/js/view/customer", "extra_data":"something" }</pre><p>Magento也会将该数据添加到视图模型中。</p><p>完成上述操作后,视图模型注册表将具有一个名为 的视图模型。这是Magento将应用于绑定的视图模型。<span style="color: #569cd6;">customerdata-bind</span>=<span style="color: #ce9178;">"scope: 'customer'"</span></p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/lib/ko/bind/scope.js define([ 'ko', 'uiRegistry', 'jquery', 'mage/translate' ], function (ko, registry, $) { 'use strict'; //... update: function (el, valueAccessor, allBindings, viewModel, bindingContext) { var component = valueAccessor(), apply = applyComponents.bind(this, el, bindingContext); if (typeof component === 'string') { registry.get(component, apply); } else if (typeof component === 'function') { component(apply); } } //... });</pre><p>它是从视图模型注册表中获取命名视图模型的行,然后以下代码实际上是在 KnockoutJS 中将对象作为视图模型应用的代码registry.get(component, apply)<span style="color: #6a9955;">;</span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/lib/ko/bind/scope.js //the component variable is our viewModel function applyComponents(el, bindingContext, component) { component = bindingContext.createChildContext(component); ko.utils.extend(component, { $t: i18n }); ko.utils.arrayForEach(el.childNodes, ko.cleanNode); ko.applyBindingsToDescendants(component, el); }</pre><p>该变量来自模块,该模块是 RequireJS 模块的别名。registryuiRegistryMagento_Ui/js/lib/registry/registry</p><pre class="brush:bash;toolbar:false">vendor/magento/module-ui/view/base/requirejs-config.js 17: uiRegistry: 'Magento_Ui/js/lib/registry/registry',</pre><p>如果很多东西飞过你的头,别担心。如果要查看特定范围的绑定中可用的数据,以下调试代码应指导您。</p><pre class="brush:bash;toolbar:false"><li class="greet welcome" data-bind="scope: 'customer'"> <pre data-bind="text: ko.toJSON($data, null, 2)"></pre> <!-- ... --> </li></pre><p>如果您是有兴趣深入了解创建视图模型的真实代码(而不是我们上面的简化伪代码)的人之一,则可以从该模块开始。Magento_Ui/js/core/app</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/core/app.js define([ './renderer/types', './renderer/layout', 'Magento_Ui/js/lib/ko/initialize' ], function (types, layout) { 'use strict'; return function (data) { types.set(data.types); layout(data.components); }; });</pre><p>此模块具有名为 的依赖项。正是在这个依赖模块中,Magento初始化视图模型,并将它们添加到视图模型注册表中。Magento_Ui/js/core/renderer/layout</p><p><span style="color: #6a9955;">#File: vendor/magento/module-ui/view/base/web/js/core/renderer/layout.js</span></p><p>代码在那里有点粗糙,但如果你需要知道这些视图模型是如何实例化的,那就是你可以找到它们的地方。</p><p><span style="color: #6a9955;">### 具有任何其他名称的组件</span></p><p>所有这一切中的一个粘性检票口是单词组件。这个绑定+系统基本上是对原生KnockoutJS组件系统的不同看法。scopex-magento-init</p><p>通过使用与KnockoutJS相同的组件术语,Magento开辟了一个混乱的新世界。甚至官方文档似乎对组件是什么或不是什么有点困惑。这就是一个大型软件团队的生活,左手不知道右手在做什么——身体的其他部分对第三只手从背部长出来感到害怕。</p><p>当与同事讨论这些功能或在Magento论坛上提问时,区分KnockoutJS组件和Magento组件非常重要。</p><p><span style="color: #6a9955;">### 2.1 候选版本中的更改</span></p><p>为了结束今天的比赛,我们将讨论Magento 2.1候选版本中对上述内容的一些更改。从概念上讲,系统仍然相同,但细节有一些变化。</p><p>首先,KnockoutJS的初始化现在发生在RequireJS模块中。Magento_Ui/js/lib/knockout/bootstrap</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/lib/knockout/bootstrap.js define([ 'ko', './template/engine', 'knockoutjs/knockout-es5', './bindings/bootstrap', './extender/observable_array', './extender/bound-nodes', 'domReady!' ], function (ko, templateEngine) { 'use strict'; ko.uid = 0; ko.setTemplateEngine(templateEngine); ko.applyBindings(); });</pre><p>请注意,Magento的核心开发人员将所有绑定加载移动到一个单独的模块,定义在Magento_Ui/js/lib/knockout/bindings/bootstrap</p><p><span style="color: #6a9955;">#File: vendor/magento/module-ui/view/base/web/js/lib/knockout/bindings/bootstrap.js</span></p><p>最后,返回的“Magento Javascript组件”有一个包含参数的更改方法签名,并且函数的参数清楚地表明它的签名也发生了变化。Magento_Ui/js/core/appmergelayoutlayout</p><p><span style="color: #6a9955;"></span></p><pre class="brush:bash;toolbar:false">#File: vendor/magento/module-ui/view/base/web/js/core/app.js define([ './renderer/types', './renderer/layout', '../lib/knockout/bootstrap' ], function (types, layout) { 'use strict'; return function (data, merge) { types.set(data.types); layout(data.components, undefined, true, merge); }; });</pre><p>除了对实现细节感兴趣的人感兴趣之外,这些变化还指出了Magento的javascript模块和框架正在迅速变化的事实,与PHP代码不同,Magento的RequireJS模块没有标记来表示稳定性。@api</p><p>除非你绝对需要,否则最好避免动态更改这些核心模块的行为,并尽可能保持你自己的JavaScript独立。</p><p><br/></p>
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>你好模型, 视图, 查看模型</p><p>了解KnockoutJS的最快方法是一个基本的例子。首先,让我们创建以下 HTML 页面</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <!DOCTYPE html> <html lang="en"> <head> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script> <script src="https://code.jquery.com/jquery-3.0.0.min.js" integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0=" crossorigin="anonymous"></script> </head> <body> <div id="main"> <h1></h1> <p></p> </div> </body> </html></pre><p>从 cloudflare CDN 加载 KnockoutJS 库</p><p>从 jQuery 代码 CDN 加载 jQuery 库</p><p>设置一个空的 DOM 节点结构</p><p>您不需要从 CDN 加载 jQuery 和 KnockoutJS,但如果您这样做,则在本教程中它是最简单的。</p><p>如果在浏览器中加载此页面,它将完全空白。那是因为我们需要</p><p>添加创建视图模型并应用 KnockoutJS 绑定的 JavaScript 代码</p><p>将视图代码添加到从视图模型读取的 HTML 页面</p><p>解决其中的第一个问题,让我们将第三个javascript文件添加到我们的页面。我们将创建一个以以下内容命名的文件ko-init.js</p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ viewModel = { title:"Hello World", content:"So many years of hello world" }; ko.applyBindings(viewModel); });</pre><p><span style="color: #6a9955;"></span><br/></p><p>然后使用第三个脚本标签添加到我们的页面。ko-init.js</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script> <script src="https://code.jquery.com/jquery-3.0.0.min.js" integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0=" crossorigin="anonymous"></script> <script type="text/javascript" src="ko-init.js"></script> 最后,更改 and 标记,使其包含以下属性。h1pdata-bind <!-- File: page.html --> <div id="main"> <h1 data-bind="text:title"></h1> <p data-bind="text:content"></p> </div></pre><p>完成上述操作后,重新加载页面,您应该会看到标题和内容已呈现。</p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ viewModel = { title:"Hello World", content:"So many years of hello world" }; ko.applyBindings(viewModel); }); //File: ko-init.js viewModel = { title:"Hello World", content:"So many years of hello world" }; <!-- File: page.html --> <div id="main"> <h1 data-bind="text:title"></h1> <p data-bind="text:content"></p> </div> value = viewModel['title']; textNode = document.createTextNode(value); h1.appendChild(textNode);</pre><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ var viewModelConstructor = function() { this.getTitle = function() { return "Hello Method World"; } this.content = "So many years of hello world"; } viewModel = new viewModelConstructor; ko.applyBindings(viewModel); });</pre><p><span style="color: #6a9955;"></span><br/></p><p>在这里,我们使用了一个javascript构造函数来创建一个简单的对象,并带有一个方法。如果我们更改视图以调用该方法,您将看到它按预期工作getTitlegetTitle</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <div id="main"> <h1 data-bind="text:getTitle()"></h1> <p data-bind="text:content"></p> </div></pre><p>考虑绑定参数的另一种方法是,它们是访问视图模型的值和方法的临时、有限的 JavaScript 范围。</p><p><span style="color: #6a9955;">### 其他绑定</span></p><p>虽然此示例很简单,但您可以开始了解这个基本构建块如何实现更复杂的视图逻辑。更新 DOM 的业务留给了 ings,更新模型的业务留给了纯非 DOM JavaScript 代码。data-bind</p><p>你可以开始看到它与其他绑定的价值。例如,让我们在我们的theValueviewModelConstructor</p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ var viewModelConstructor = function() { this.getTitle = function() { return "Hello World"; } this.content = "So many years of hello world"; this.theValue = "2"; } viewModel = new viewModelConstructor; ko.applyBindings(viewModel); });</pre><p>,然后添加具有新绑定的输入标记。</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <div id="main"> <h1 data-bind="text:getTitle()"></h1> <p data-bind="text:content"></p> <input type="text" data-bind="value:theValue"/> </div></pre><p>重新加载页面,您将看到值为 .2</p><pre class="brush:bash;toolbar:false">data-bind="value:theValue" <!-- File: page.html --> <div id="main"> <h1 data-bind="text:getTitle()"></h1> <p data-bind="text:content"></p> <select data-bind="value:theValue"> <option value="">-- Choose --</option> <option value="1">First</option> <option value="2">Second</option> <option value="3">Third</option> </select> </div></pre><p>虽然这个例子很简单,但它背后的概念却不是。无需更改任何 javascript 应用程序代码,绑定允许我们更改 UI。value</p><p><span style="color: #6a9955;">### 可观察量</span></p><p>到目前为止,我们看到的是一个强大的客厅技巧。整洁,也许有用,但它只为KnockoutJS真正的“淘汰”功能——可观察量奠定了基础。</p><p>同样,我们将通过一个例子进行深入研究。更改视图,使其与以下内容匹配</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <div id="main"> <p data-bind="text:theValue"></p> <select data-bind="value:theValue"> <option value="">-- Choose --</option> <option value="1">First</option> <option value="2">Second</option> <option value="3">Third</option> </select> <input type="text" data-bind="value:theValue"/> <div> <br/><br/> <button id="button">Do It</button> </div> </div></pre><p>并更改视图模型和绑定,使其与以下内容匹配。</p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ var viewModelConstructor = function() { this.theValue = ko.observable("1"); } window.viewModel = new viewModelConstructor; ko.applyBindings(window.viewModel); });</pre><p>如果您重新加载页面,您将看到我们已将 的值绑定到 our and 标记。到目前为止,我们的观点没有什么新东西——这与我们以前所做的那种绑定相同。但是,您会注意到我们在视图模型中做了一些不同的事情。1<input/><p/></p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js this.theValue = ko.observable("1");</pre><p>我们没有设置为硬编码值或自定义函数,而是将值设置为 KnockoutJS 称之为可观察量的值。可观察量是一种特殊的吸气者和二传手。theValue</p><p>如果你打开你的javascript控制台,并键入以下内容,你会看到我们可以通过将其作为函数调用来获取可观察量的值(可以通过控制台获得,因为我们将其定义为对象的全局对象)</p><pre class="brush:bash;toolbar:false">viewModelwindow > viewModel.theValue() > "1"</pre><p>我们可以通过传入参数在可观察量上设置一个值。下面介绍了如何设置可观察量,然后获取可观察量的值。</p><p></p><pre class="brush:bash;toolbar:false">> viewModel.theValue("3") //... > viewModel.theValue() > "3"</pre><p>然而,可观察量的真正力量在于我们将可观察量绑定到的 DOM 节点会发生什么。尝试通过控制台更改观察器的值并观察浏览器窗口</p><p></p><pre class="brush:bash;toolbar:false">> viewModel.theValue("3"); > viewModel.theValue("2"); > viewModel.theValue("1"); > viewModel.theValue("10");</pre><p>更新可观察量的值时,绑定节点的值会实时更改。同样,作为开发人员,我们不必担心 DOM 节点如何更新——一旦我们在模型上设置了值,这个值就会自动反映在用户界面中。</p><p>虽然它超出了本文的范围,但当我们的视图模型包含方法时,您可以看到它如何组合在一起形成复杂的 JavaScript 应用程序。</p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ var viewModelConstructor = function() { this.theValue = ko.observable("1"); var that = this; this.pickRandomValue = function(){ var val = Math.floor(Math.random() * (3)); that.theValue(val); }; } window.viewModel = new viewModelConstructor; ko.applyBindings(window.viewModel); });</pre><p>并且您使用 KnockoutJS 的事件绑定,例如click</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <button data-bind="click:pickRandomValue">Do It</button></pre><p>我们将把解析作为读者的练习</p><p><span style="color: #6a9955;">### 模板绑定</span></p><p>另一个需要理解的重要绑定是 KnockoutJS 的模板绑定。考虑这样的视图模型</p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ var viewModelConstructor = function() { this.first = { theTitle:ko.observable("Hello World"), theContent:ko.observable("Back to Hello World") }; this.second = { theTitle:ko.observable("Goodbye World"), theContent:ko.observable("We're sailing west now") }; } viewModel = new viewModelConstructor; ko.applyBindings(viewModel); });</pre><p>在这里,我们创建了一个标准视图模型,但具有嵌套的数据对象。如果将其与这样的视图相结合</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <div id="main"> <div id="one" data-bind="template:{'name':'hello-world','data':first}"></div> <div id="two" data-bind="template:{'name':'hello-world','data':second}"> </div> <script type="text/html" id="hello-world"> <h1 data-bind="text:theTitle"></h1> <p data-bind="text:theContent"></p> </script> </div></pre><p>模板绑定接受 javascript 对象作为参数</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <div id="one" data-bind="template:{'name':'hello-world','data':first}"></div></pre><p>data 参数是我们想要用来渲染模板的视图模型的属性。模板的名称就是这样 — 要查找和呈现的模板名称。</p><p>向系统添加命名模板的最基本方法是添加带有 of 的标记。<script/>typetext/html</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <script type="text/html" id="hello-world"> <h1 data-bind="text:theTitle"></h1> <p data-bind="text:theContent"></p> </script></pre><p>如果你以前从未见过这个,它可能看起来很奇怪/陌生,但许多现代JavaScript框架使用非标签作为将非渲染(但DOM可访问)内容添加到页面的一种方式。模板只是一组带有 KnockoutJS 绑定的标准 HTML 节点。text/javascript<script/></p><p><span style="color: #6a9955;">### 组件</span></p><p>我们将要进行的最后一个绑定是组件绑定。组件是一种将 KnockoutJS 模板和 KnockoutJS 视图文件打包在一起的方法。这意味着您可以有一个相对简单的视图</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <div data-bind="component:'component-hello-world'"></div></pre><p>这隐藏了已注册组件的复杂性。</p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ var viewModelConstructor = function() { this.message = "Hello World"; } var theTemplate = "<h1 data-bind=\"text:message\"></h1>"; ko.components.register('component-hello-world', { viewModel:viewModelConstructor, template:theTemplate }); ko.applyBindings(); });</pre><p><span style="color: #6a9955;"></span><br/></p><p>组件对象的函数需要组件的名称,然后是 KnockoutJS 组件对象。组件对象是具有两个属性的 JavaScript 脚本对象。该属性需要一个视图模型构造函数,并且该属性应该是带有 KnockoutJS 模板的字符串。注册后,可以通过将组件的名称(作为字符串)传递到绑定中使用组件。registerviewModeltemplate</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <div data-bind="component:'component-hello-world'"></div></pre><p>如果您不想使用语法 — KnockoutJS 使您能够根据组件名称插入具有自定义标记名称的组件。在您的视图/HTML 文件中尝试此操作data-bind</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <component-hello-world></component-hello-world></pre><p>这只触及了KnockoutJS可能的表面。官方文档对组件绑定有一个很好的概述。</p><p><span style="color: #6a9955;">### 自定义绑定</span></p><p>我们今天要讨论的最后一个 KnockoutJS 功能是自定义绑定功能。KnockoutJS使javascript开发人员能够创建自己的绑定。例如,这里我们调用一个名为 的自定义绑定,并向其传递 viewModel 的属性值。pulseStormHelloWorldmessage</p><pre class="brush:bash;toolbar:false"><!-- File: page.html --> <div data-bind="pulseStormHelloWorld:message"></div></pre><p>如果没有实现,KnockoutJS将忽略我们的绑定。相反,请尝试以下ko-init.js</p><p></p><pre class="brush:bash;toolbar:false">//File: ko-init.js jQuery(function(){ var viewModelConstructor = function() { this.message = "Hello World"; } ko.bindingHandlers.pulseStormHelloWorld = { update: function(element, valueAccessor){ jQuery(element).html('<h1>' + valueAccessor() + '</h1>'); } }; ko.applyBindings(new viewModelConstructor); });</pre><p><span style="color: #6a9955;"></span><br/></p><p>要将自定义绑定添加到 KnockoutJS,我们需要做的就是向对象的对象添加一个属性。此属性的名称是我们绑定的名称。处理程序是带有方法的 JS 对象。每当调用绑定时,KnockoutJS 都会调用该方法 — 无论是在 期间还是通过可观察量。kobinidngHandlersupdateupdateapplyBindings</p><p>完成上述操作后,重新加载 HTML 页面,您将看到调用的自定义绑定。当然,这是一个微不足道的例子,但是使用自定义绑定,您可以让KnockoutJS做任何您的编程思维想到的事情。</p><p><br/></p>
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>Javascript 初始化方法</p><p>我们将要讨论的Magento javascript init方法解决了几个不同的问题。</p><p>首先,它们提供了一种标准机制来阻止将javascript直接嵌入到页面中。</p><p>其次,它们提供了一种调用独立 RequireJS 模块(定义为 )作为程序的方法。define</p><p>第三,它们提供了一种向该程序传递服务器端生成的JSON对象的方法。</p><p>第四,它们提供了一种方法来告诉该程序应该在哪些(如果有的话)DOM节点上运行。</p><p>牢记这四个目标。如果您正在努力解决这些自定义框架功能背后的心智模型,它们可能会为您提供帮助。</p><p><span style="color: #6a9955;">### 设置模块</span></p><p>我们将使用 pestle 通过运行以下三个命令来创建以单个 URL 端点命名的模块Pulsestorm_JavascriptInitTutorial</p><pre class="brush:bash;toolbar:false">$ pestle.phar generate_module Pulsestorm JavascriptInitTutorial 0.0.1 $ pestle.phar generate_route Pulsestorm_JavascriptInitTutorial frontend pulsestorm_javascriptinittutorial $ pestle.phar generate_view Pulsestorm_JavascriptInitTutorial frontend pulsestorm_javascriptinittutorial_index_index Main content.phtml 1column $ php bin/magento module:enable Pulsestorm_JavascriptInitTutorial $ php bin/magento setup:upgrade</pre><p>任何通过Magento 2 for PHP MVC开发人员系列工作的人都应该熟悉这些命令。运行上述操作后,您应该能够在系统中访问以下URL</p><p>http://magento.example.com/pulsestorm_javascriptinittutorial/</p><p>并查看呈现的模板。app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</p><p><span style="color: #6a9955;">### 设置一个 RequireJS 模块</span></p><p>现在我们已经设置了一个Magento模块,让我们做一个快速回顾并创建一个RequireJS模块。首先,创建以下文件</p><p>//File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/web/example.js</p><p><br/></p><pre class="brush:bash;toolbar:false">define([], function(){ alert("A simple RequireJS module"); return {}; });</pre><p>这是一个非常简单的 RequireJS 模块。由于模块在文件系统上的位置,以及Magento加载javascript文件的方式,该模块的名称/标识符是Pulsestorm_JavascriptInitTutorial/example</p><p>接下来,更改 的内容,使其与以下内容匹配。content.phtml</p><p><span style="color: #6a9955;">#File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</span></p><pre class="brush:bash;toolbar:false"><script type="text/javascript"> requirejs(['Pulsestorm_JavascriptInitTutorial/example'],function(example){ alert("Loaded"); console.log(example); }); </script></pre><p>在这里,我们将创建一个具有单个模块依赖项的 RequireJS 程序。依赖项是我们刚刚创建的模块 ()。加载Pulsestorm_JavascriptInitTutorial/example</p><p>http://magento.example.com/pulsestorm_javascriptinittutorial/</p><p>系统中的 URL,您应该会看到警报。</p><p>如果以上任何内容对您来说是陌生的,您可能需要查看我们的Magento 2和RequireJS文章。</p><p><span style="color: #6a9955;">### X-Magento-Init</span></p><p>我们要讨论的第一个初始化技术是方法。此初始化方法的最基本版本允许您将 RequireJS 模块作为程序运行。更改模板的内容,使其与以下内容匹配<script <span style="color: #569cd6;">type</span>=<span style="color: #ce9178;">"text/x-magento-init"</span>>content.phtml</p><p><span style="color: #6a9955;">#File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</span></p><pre class="brush:bash;toolbar:false"><div id="one" class="foo"> Hello World </div> <div id="two" class="foo"> Goodbye World </div> <script type="text/x-magento-init"> { "*": { "Pulsestorm_JavascriptInitTutorial/example":{} } } </script></pre><p>使用上述内容重新加载您的页面,您应该会看到我们文件中的声明。alertexample.js</p><p>如果您以前从未见过此语法,它看起来可能有点奇怪。让我们把它一块一块地拆开。</p><p>首先是标签<script/></p><p><span style="color: #6a9955;">#File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</span></p><pre class="brush:bash;toolbar:false"><script type="text/x-magento-init"> //... </script></pre><p>此标签不是 javascript 标签。请注意该属性。当浏览器无法识别脚本类型标记中的值时,它将忽略该标记的内容。Magento(类似于其他现代JavaScript框架)利用这种行为来发挥其优势。虽然这超出了本教程的范围,但正在运行Magento javascript代码,它将扫描脚本标签。如果您想自己探索这个问题,这个堆栈交换问题和答案是一个很好的起点。<span style="color: #569cd6;">type</span>=<span style="color: #ce9178;">"text/x-magento-init"</span>text/x-magento-init</p><p>我们可以立即讨论的代码块的另一部分是以下对象x-magento-init</p><p><span style="color: #6a9955;">#File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</span></p><pre class="brush:bash;toolbar:false">{ "Pulsestorm_JavascriptInitTutorial/example":{} }</pre><p>Magento将查看此对象的键,并将其(键)作为RequireJS模块包含在内。这就是加载脚本的内容。example.js</p><p>您可能想知道为什么这是一个没有值的对象。您可能还想知道为什么整个事物是另一个对象的一部分,带有 a 作为键。*</p><p><span style="color: #6a9955;">#File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</span></p><pre class="brush:bash;toolbar:false">{ "*": {/*...*/} }</pre><p>在我们讨论这个问题之前,我们需要谈谈javascript组件。</p><p><span style="color: #6a9955;">### Magento Javascript Components</span></p><p>上面的例子将我们的 RequireJS 模块作为一个程序运行。这是有效的,Magento本身经常使用该方法将RequireJS模块作为程序调用。然而,真正的力量是能够创建一个Magento Javascript组件。x-magento-initx-magento-init</p><p>Magento Javascript 组件是返回函数的 RequireJS 模块。Magento的系统代码将以特定的方式调用此函数,以公开额外的功能。</p><p>如果这没有意义,请尝试更改 RequireJS 模块,使其与以下内容匹配。</p><p>//File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/web/example.js</p><p><br/></p><pre class="brush:bash;toolbar:false">define([], function () { var mageJsComponent = function() { alert("A simple magento component."); }; return mageJsComponent; });</pre><p>在这里,我们定义了一个函数并将其分配给一个名为 .然后,我们将其退回。mageJsComponent</p><p>如果您在上述情况下重新加载页面,您应该会在警告框中看到一个简单的 Magento 组件。</p><p>这可能看起来很愚蠢——如果Magento所做的只是调用它,那么返回一个函数有什么意义呢?你是对的,但那是因为我们遗漏了一些东西。尝试更改我们的模板,使其与以下内容匹配phtml</p><p><span style="color: #6a9955;">#File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</span></p><pre class="brush:bash;toolbar:false"><div id="one" class="foo"> Hello World </div> <div id="two" class="foo"> Goodbye World </div> <script type="text/x-magento-init"> { "*": { "Pulsestorm_JavascriptInitTutorial/example":{"config":"value"} } } </script></pre><p>并更改我们的 RequireJS 模块,使其看起来像这样</p><p>//File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/web/example.js</p><p><br/></p><pre class="brush:bash;toolbar:false">define([], function () { var mageJsComponent = function(config) { alert("Look in your browser's console"); console.log(config); //alert(config); }; return mageJsComponent; });</pre><p>如果重新加载页面,应会看到更改的警告消息。如果您查看浏览器的 javascript 控制台,您还应该看到以下内容</p><p>> Object {config:<span style="color: #ce9178;">"value"</span>}</p><p>当我们创建一个 Magento Javascript 组件时,Magento 调用返回的函数并包含来自 .text/x-magento-init</p><p><span style="color: #ce9178;">"Pulsestorm_JavascriptInitTutorial/example"</span>:{<span style="color: #ce9178;">"config"</span>:<span style="color: #ce9178;">"value"</span>} </p><p>这就是为什么 RequireJS 模块名称是一个键 — 这个对象的值是我们想要传递给组件的对象。</p><p>在这些示例中,这似乎是一个愚蠢的抽象。但是,在实际模块中,我们将使用 PHP 生成该 JSON。这个系统允许我们在模板中渲染JSON,然后将其传递给Javascript代码。这有助于避免直接使用 PHP 生成 Javascript 的问题,这可能导致代码非常混乱,并且很容易意外地滑入错误或安全问题。phtml</p><p>在我们结束之前,还有最后一个功能要讨论。你会记得我们说过x-magento-initx-magento-init</p><p>提供了一种向该程序传递服务器端生成的 JSON 对象的方法。</p><p>提供了一种为该程序提供它应该在其上运行的 DOM 节点的方法。</p><p>我们已经介绍了如何传入服务器端生成的 JSON — 但是 DOM 节点呢?</p><p>更改您的 RequireJS 模块,使其如下所示</p><p>//File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/web/example.js</p><p><br/></p><pre class="brush:bash;toolbar:false">define([], function () { var mageJsComponent = function(config, node) { console.log(config); console.log(node); //alert(config); }; return mageJsComponent; });</pre><p>我们在这里所做的是向函数添加第二个参数。第二个参数将是我们希望程序运行的 DOM 节点。但是,如果您在上述情况下重新加载页面,您将在控制台中看到以下内容。mageJsComponent</p><p>> Object {config:<span style="color: #ce9178;">"value"</span>}</p><p>> false</p><p>Magento确实传递了一个值 - 但该值是。什么给?nodefalse</p><p>好吧,Magento无法神奇地知道我们要在哪些DOM节点上运行。我们需要告诉它!更改模板,使其与以下内容匹配。phtml</p><p><span style="color: #6a9955;">#File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</span></p><pre class="brush:bash;toolbar:false"><div id="one" class="foo">Hello World</div> <div id="two" class="foo"> Goodbye World </div> <script type="text/x-magento-init"> { "#one": { "Pulsestorm_JavascriptInitTutorial/example":{"config":"value"} } } </script></pre><p>在这里,我们已将 更改为 .我们之前使用的实际上是一个特例,用于不需要在 DOM 节点上运行的程序。这个对象的键实际上是一个CSS / jQuery样式选择器,它告诉Magento程序应该在哪些DOM节点上运行。如果我们在上述情况下重新加载页面,我们将在您的控制台中看到以下内容*<span style="color: #6a9955;">#one*Pulsestorm_JavascriptInitTutorial/example</span></p><pre class="brush:bash;toolbar:false">> Object {config: "value"} > <div id="one" class="foo">Hello World</div></pre><p>您不仅限于 ID,还可以在此处使用 CSS 类标识符。将其更改为</p><p><span style="color: #6a9955;">#File: app/code/Pulsestorm/JavascriptInitTutorial/view/frontend/templates/content.phtml</span></p><pre class="brush:bash;toolbar:false">".foo": { "Pulsestorm_JavascriptInitTutorial/example":{"config":"value"} }</pre><p>您将在控制台中看到以下内容。</p><pre class="brush:bash;toolbar:false">> Object {"config":"value"} > <div id="one" class="foo">Hello World</div> > Object {"config":"value"} > <div id="two" class="foo">Goodbye World</div></pre><p>通过构建这种系统,Magento鼓励开发人员避免将他们的DOM节点硬编码到他们的RequireJS模块中。这意味着有一个系统级的路径来构建依赖于服务器端渲染的JSON的Javascript模块,并在任何任意DOM节点上运行。Magento模块开发人员总是有可能实现自己的系统来实现这种功能,但是Magento 2提供了一个标准,内置的方式来实现这一目标。x-magento-init</p><p><span style="color: #6a9955;">### 数据法师初始化属性</span></p><p>除了 之外,还有另一种方法可以在特定的 DOM 节点上调用类似的功能,那就是属性。尝试将现有模板替换为以下内容<script <span style="color: #569cd6;">type</span>=<span style="color: #ce9178;">"text/x-magento-init"</span>>data-mage-initphtml</p><pre class="brush:bash;toolbar:false"><div data-mage-init='{"Pulsestorm_JavascriptInitTutorial/example": {"another":"example"}}'>A single div</div></pre><p>在上述操作到位的情况下重新加载页面,您应该会在 JavaScript 控制台中看到以下内容。<br/></p><pre class="brush:as3;toolbar:false">> Object {another: "example"} > <div>A single div</div></pre><p>在这里,我们向特定的 div 添加了一个属性。此属性的值是一个 JSON 对象。与类似,这个对象的键是我们想要作为程序或Magento Javascript组件调用的RequireJS模块,该值是一个嵌套的JSON对象,作为参数传递到我们的Magento Javascript组件函数中。data-mage-initx-magento-initconfig</p><pre class="brush:bash;toolbar:false"><div data-mage-init='...'>A single div</div></pre><p>不幸的是,这是必需的。属性的值由严格的 JSON 解析器解析,这意味着 JSON 对象的引号必须是双引号——这意味着我们不能对属性使用双引号。虽然这在HTML5中技术上是可以的,但对于一定年龄的Web程序员来说,它带来了一些不好Microsoft首页记忆。data-mage-init<br/></p><p>无论您最终在特定节点中使用组件还是属性,这两种技术都提供了一种标准的、系统统一的方式来将 Javascript 入口点引入您的页面。Magento的许多前端和后端UI功能都依赖于这种语法,因此即使您个人避开它们,了解这些系统的工作原理也是成为Magento 2开发人员的重要组成部分。<script <span style="color: #569cd6;">type</span>=<span style="color: #ce9178;">"text/x-magento-init"</span>>data-mage-init</p><p><br/></p>
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>在处理项目时,我必须在每个CMS页面上CMS页面的标题和主要内容之间添加一个唯一的静态块。元素必须可以通过Magento管理面板完全自定义,并且必须易于在新的CMS页面上创建,易于修改和删除。由于该元素需要放置在主要内容之外,因此无法在Magento管理中使用CMS添加它。它必须使用Magento布局添加。这是我如何实现这一目标的。</p><p>如您所知,Magento仅为CMS页面提供以下句柄:</p><p><span style="color: #6a9955;">### 主页句柄和 404 页句柄</span></p><p>所有 CMS 页面的句柄</p><p>如果必须在主页上显示 CMS 块,我们将在本地.xml文件中使用主页句柄。同样,如果必须在所有CMS页面上显示相同的静态块,我们将对所有CMS页面使用句柄。</p><p>但是,单个用户创建的CMS页面呢?</p><p><span style="color: #6a9955;">### 前端开发人员的解决方案</span></p><p>幸运的是,Magento使我们能够通过从Magento管理面板上的CMS编辑器编辑每个CMS页面来定义自定义布局。这样,CMS 页面的布局就可以使用存储在数据库中的特定页面的已定义值进行修改。</p><p>首先,我们将创建一个静态块,我们要将其添加到特定的CMS页面中,我们将将其命名为static-block-1并对其应用一些简单的样式。</p><pre class="brush:bash;toolbar:false"><div class=”element-blue”> <h3>Static Block 1</h3> <p>This is blue static element 1 </p> </div></pre><p>接下来,我们将创建一个新的 CMS 页面,其中包含创建的静态块,该块将通过“设计”选项卡上的“布局更新 XML”添加,以及一个标题和一个段落。在本例中,我们将对所有 CMS 页面使用 1 列布局。</p><pre class="brush:bash;toolbar:false"><reference name="root"> <block type="cms/block" name="myelement"> <action method="setBlockId"><block_id>static-block-1</block_id></action> </block> </reference></pre><p>最后,我们必须更新我们的模板文件并添加一行调用我们的元素的代码。 由于我们对所有 CMS 页面都使用了 1 列布局,因此我们将修改 1column.phtml 模板文件。如果要将元素添加到使用其他模板(如 2 列左)的 CMS 页面,则需要修改这些文件。</p><pre class="brush:bash;toolbar:false">… <div class="page"> <?php echo $this->getChildHtml('header') ?> <?php echo $this->getChildHtml('myelement') ?> …</pre><p>对于此示例,我创建了一个与第一个不同的附加静态块和两个额外的 CMS 页面 - 一个用于我创建的新元素,另一个用于没有任何布局更新,因此,它不会包含我们创建的任何元素。</p><p>结果</p><p>带有蓝色静态块的 CMS 页面 1:</p><p>CMS page 1</p><p>CMS 第 1 页的 HTML 代码:</p><p>01-code-1</p><p>带有绿色静态块的 CMS 页面 2:</p><p>02-cms-2</p><p>CMS 第 2 页的 HTML 代码:</p><p>02-code-2</p><p>CMS 第 3 页,我们没有在其 XML 中设置任何布局更新,因此它不显示任何创建的静态块。</p><p>03-cms-3</p><p>CMS 第 3 页的 HTML 代码:</p><p>03-code-3</p><p>好的、坏的和另一种选择</p><p>尽管这是一个非常快速简单的解决方案,效果很好,但当您必须为要添加的每个元素执行这些相同的步骤时,即使在具有 6 或 7 个 CMS 页面的项目中也是如此,它也会变得乏味。</p><p><br/></p>
<h5 style="color:red;">系统学习magento二次开发,推荐小册:<a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank">《Magento中文全栈二次开发 》</a></h5> <div class="image-container"> <p> <a style="color:blue;" href="https://www.maxiaoke.com/manual/magento_cn_dev.html" target="_blank"> <img src="https://www.maxiaoke.com/uploads/images/20230218/bb9c82995c24d1105676e02f373755f5.jpg" alt="Magento中文全栈二次开发"> </a> </p> </div> <div class="text-container" style="font-size:14px; color:#888"> <p>本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。</p> </div> <hr><p>我们可以说Magento中的路由是最重要的部分之一。完整的应用程序(Magento 2)流程取决于处理URL请求和负责匹配和处理该请求的路由器类。本文介绍了Magento 2中的路由器流,并分析了默认安装附带的一些路由器。还将展示如何创建一个自定义路由器。将提到路由器如何匹配操作(控制器类),有关控制器的详细信息将在单独的文章中介绍。</p><p><span style="color: #6a9955;">### 路由流</span></p><p>首先,我们需要分析完整的路由流程,以便稍后可以更详细地了解每个部分。正如我们已经知道的,Magento 2创建了HTTP应用程序,其中类(启动方法)请求流将在其中启动。我们的流程从创建前端控制器开始:</p><pre class="brush:bash;toolbar:false">$frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface');</pre><p>前端控制器负责遍历所有可用的路由器,并为当前请求匹配负责的路由器。稍后我们将详细介绍前端控制器。现在,要了解完整的流程,了解应用程序如何匹配路由器非常重要。路由器列表是在位于Magento\Framework\App的RouterList类中创建的(在Front Controller中调用用于在路由器上循环),该类负责路由器列表的排序和迭代。如果路由器负责当前请求,则路由器类负责匹配。让我们来看看Magento 2流程:<br/></p><p>index.php(运行引导程序并创建HTTP应用程序)→HTTP应用程序→FrontController →路由→控制器处理→等</p><p>现在,我们将分析路由流的每个部分,以便更好地了解Magento 2中的路由。</p><p><span style="color: #6a9955;">### 前端控制器</span></p><p>与Magento 1相同,这是在HTTP应用程序启动(启动方法)时调用的入口路由点。它负责匹配负责当前请求的路由器。它位于lib/internal/Magento/Framework/App/FrontController.php下。你可以看到在HTTP启动方法中使用了FrontControllerInterface。让我们在代码中看一下:</p><p></p><pre class="brush:bash;toolbar:false">class Http implements \Magento\Framework\AppInterface { public function launch() { ... //Here Application is calling front controller and it's dispatch method $frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface'); $result = $frontController->dispatch($this->_request); ... } }</pre><p><span style="color: #ce9178;">现在,当我们知道如何以及何时调用前端控制器时,让我们看一下前端控制器类和调度方法本身:</span></p><p><span style="color: #ce9178;">lib/internal/Magento/Framework/App/FrontController.php</span></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false">class FrontController implements FrontControllerInterface { public function dispatch(RequestInterface $request) { \Magento\Framework\Profiler::start('routers_match'); $routingCycleCounter = 0; $result = null; while (!$request->isDispatched() && $routingCycleCounter++ < 100) { /** @var \Magento\Framework\App\RouterInterface $router */ foreach ($this->_routerList as $router) { try { $actionInstance = $router->match($request); if ($actionInstance) { $request->setDispatched(true); $actionInstance->getResponse()->setNoCacheHeaders(); $result = $actionInstance->dispatch($request); break; } } catch (\Magento\Framework\Exception\NotFoundException $e) { $request->initForward(); $request->setActionName('noroute'); $request->setDispatched(false); break; } } } \Magento\Framework\Profiler::stop('routers_match'); if ($routingCycleCounter > 100) { throw new \LogicException('Front controller reached 100 router match iterations'); } return $result; } }</pre><p><span style="color: #ce9178;">正如我们所看到的,调度方法将遍历所有路由器(启用,我们稍后将在路由器配置中介绍这一点),直到一个路由器匹配并调度请求($request→setDispatched(true);)或工艺路线周期计数器超过 100。路由器可以匹配,但是如果没有调度,它将重复环路槽路由器(向前操作)。此外,路由器可以重定向和调度,也可以匹配和处理。路由器列表类在请求流中解释。现在,我们可以继续查看路由器匹配(匹配方法)的工作原理以及路由器到底是什么。</span></p><p><span style="color: #ce9178;">### 路由器</span></p><p><span style="color: #ce9178;">简而言之,路由器是负责匹配和处理URL请求的PHP类。默认情况下,Magento框架和Magento核心中有一些路由器;Base、DefaultRouter、CMS 和 UrlRewrite。我们将涵盖所有这些内容,解释它们的目的以及它们的工作原理。路由器正在实现路由器接口。现在,让我们看一下默认路由器的流程:</span></p><p><span style="color: #ce9178;">基本路由器→ CMS 路由器→ url重写路由器→默认路由器</span></p><p><span style="color: #ce9178;">(这是路由器循环 – FrontController::d ispatch())</span></p><p><span style="color: #ce9178;">### 基础路由器</span></p><p><span style="color: #ce9178;">它位于lib/internal/Magento/Framework/App/Router/Base.php,它是循环中的第一个,如果你是Magento 1开发人员,你知道它是标准路由器。匹配方法将解析请求和匹配操作,在第二种方法中,它将设置模块前端名称、控制器路径名、操作名称、控制器模块和路由名称。在基本路由器上,标准Magento URL(前端名称/操作路径/操作/参数1/等参数/)匹配。</span></p><p><span style="color: #ce9178;">### 内容管理系统路由器</span></p><p><span style="color: #ce9178;">CMS路由器位于app/code/Magento/Cms/Controller/Router.php中,用于处理CMS页面,它将模块名称(模块前端名称)设置为“cms”,控制器名称(控制器路径名称)设置为“页面”,操作名称设置为“view” – app/code/Magento/Cms/Controller/Page/View.php控制器。设置基本控制器的格式后,它将设置页面 ID 并转发它,但不会调度它。转发意味着它将中断当前的路由器环路并再次启动环路(它最多可以这样做 100 次)。该路由器环路将匹配基本路由器,该路由器将在 Cms/控制器/页面中激活视图控制器并显示保存的页面 ID(根据 url 找到的页面 ID)。</span></p><p><span style="color: #ce9178;">### 网址重写路由器</span></p><p><span style="color: #ce9178;">在Magento 2中,UrlRewrite有自己的路由器,如果你熟悉Magento 1,那么你就会知道Url Rewrite是标准路由器的一部分。它位于:app/code/Magento/UrlRewrite/Controller/Router.php它使用Url Finder来获取与数据库中的URL匹配的url重写:</span></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false">$rewrite = $this->urlFinder->findOneByData( [ UrlRewrite::ENTITY_TYPE => $oldRewrite->getEntityType(), UrlRewrite::ENTITY_ID => $oldRewrite->getEntityId(), UrlRewrite::STORE_ID => $this->storeManager->getStore()->getId(), UrlRewrite::IS_AUTOGENERATED => 1, ] );</pre><p><span style="color: #ce9178;">它将像 CMS 路由器一样转发动作。</span></p><p><span style="color: #ce9178;">### 默认路由器</span></p><p><span style="color: #ce9178;">它位于lib/internal/Magento/Framework/App/Router/DefaultRouter中.php它是路由器循环中的最后一个。当所有其他路由器不匹配时,使用它。在Magento 2中,我们可以为“未找到”页面创建自定义句柄以显示自定义内容。以下是 DefaultRouter 中没有路由处理程序列表的循环:</span></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false">foreach ($this->noRouteHandlerList->getHandlers() as $noRouteHandler) { if ($noRouteHandler->process($request)) { break; } }</pre><p><span style="color: #ce9178;">### 自定义路由器(带示例)</span></p><p><span style="color: #ce9178;">前端控制器将遍历 routersList 中的所有路由器(从 routes.xml 中的配置创建),因此我们需要通过在 di.xml 模块中添加我们对新路由器的配置,在 lib/internal/Magento/Framework/App/RouterList 中添加自定义路由器.php。我们将创建一个新模块(我们称之为Inchoo/CustomRouter),然后我们将在routersList中添加新的路由器,最后,创建路由器类。</span></p><p><span style="color: #ce9178;">自定义路由器只是一个示例,您可以在其中了解如何匹配和转发要匹配的基本路由器的请求。首先,我们需要为位于app/code/Inchoo/CustomRouter中的模块创建文件夹结构,然后我们将在etc文件夹中创建模块.xml并在模块根目录中创建composer.json,其中包含模块信息。现在,我们可以通过在 etc/前端文件夹中向 di.xml 添加配置来创建自定义路由器,因为我们只想为前端提供自定义路由器。最后,我们将在控制器文件夹中创建路由器.php,其中包含用于匹配路由器的逻辑。我们将搜索 URL 并检查 URL 中是否有特定单词,然后,根据该单词,我们将设置模块前端名称、控制器路径名称、操作名称,然后转发基本控制器的请求。我们将搜索两个词:“examplerouter”和“exampletocms”。在“examplerouter”匹配中,我们将转发到基本路由器匹配格式(通过将模块前端名称设置为“inchootest”,控制器路径名称设置为“test”,操作名称设置为“test”),在“exampletocms”上,我们将转发到基本路由器以显示“关于我们”页面。</span></p><p><span style="color: #ce9178;">di.xml(位于 etc/前端)</span></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false"><?xml version="1.0"?> <!-- /** * Copyright © 2015 Inchoo d.o.o. * created by Zoran Salamun(zoran.salamun@inchoo.net) * Module is created for Custom Router demonstration */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd"> <type name="Magento\Framework\App\RouterList"> <arguments> <argument name="routerList" xsi:type="array"> <item name="inchoocustomrouter" xsi:type="array"> <item name="class" xsi:type="string">Inchoo\CustomRouter\Controller\Router</item> <item name="disable" xsi:type="boolean">false</item> <item name="sortOrder" xsi:type="string">22</item> </item> </argument> </arguments> </type> </config> <?php namespace Inchoo\CustomRouter\Controller; /** * Inchoo Custom router Controller Router * * @author Zoran Salamun <zoran.salamun@inchoo.net> */ class Router implements \Magento\Framework\App\RouterInterface { /** * @var \Magento\Framework\App\ActionFactory */ protected $actionFactory; /** * Response * * @var \Magento\Framework\App\ResponseInterface */ protected $_response; /** * @param \Magento\Framework\App\ActionFactory $actionFactory * @param \Magento\Framework\App\ResponseInterface $response */ public function __construct( \Magento\Framework\App\ActionFactory $actionFactory, \Magento\Framework\App\ResponseInterface $response ) { $this->actionFactory = $actionFactory; $this->_response = $response; } /** * Validate and Match * * @param \Magento\Framework\App\RequestInterface $request * @return bool */ public function match(\Magento\Framework\App\RequestInterface $request) { /* * We will search “examplerouter” and “exampletocms” words and make forward depend on word * -examplerouter will forward to base router to match inchootest front name, test controller path and test controller class * -exampletocms will set front name to cms, controller path to page and action to view */ $identifier = trim($request->getPathInfo(), '/'); if(strpos($identifier, 'exampletocms') !== false) { /* * We must set module, controller path and action name + we will set page id 5 witch is about us page on * default magento 2 installation with sample data. */ $request->setModuleName('cms')->setControllerName('page')->setActionName('view')->setParam('page_id', 5); } else if(strpos($identifier, 'examplerouter') !== false) { /* * We must set module, controller path and action name for our controller class(Controller/Test/Test.php) */ $request->setModuleName('inchootest')->setControllerName('test')->setActionName('test'); } else { //There is no match return; } /* * We have match and now we will forward action */ return $this->actionFactory->create( 'Magento\Framework\App\Action\Forward', ['request' => $request] ); } }</pre><p><span style="color: #ce9178;">routes.xml (located in etc/frontend)</span></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false"><?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd"> <router id="standard"> <route id="inchootest" frontName="inchootest"> <module name="Inchoo_CustomRouter" /> </route> </router> </config></pre><p><span style="color: #ce9178;"></span><br/></p><p><span style="color: #ce9178;">Test.php (test controller action class)</span></p><p><br/></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false"><?php /** * Copyright © 2015 Inchoo d.o.o. * created by Zoran Salamun(zoran.salamun@inchoo.net) */ namespace Inchoo\CustomRouter\Controller\Test; class Test extends \Magento\Framework\App\Action\Action { /** * Listing all images in gallery * -@param gallery id */ public function execute() { die("Inchoo\\CustomRouter\\Controller\\Test\\Test controller execute()"); } }</pre><p><span style="color: #ce9178;"></span><br/></p><p><span style="color: #ce9178;">您可以在以下位置查看示例模块:</span></p><p><span style="color: #ce9178;">https://github.com/zoransalamun/magento2-custom-router</span></p><p><span style="color: #ce9178;">安装:</span></p><p><span style="color: #ce9178;">首先将存储库添加到作曲家配置:</span></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false">composer config repositories.inchoocustomrouter vcs git@github.com:zoransalamun/magento2-custom-router.git</pre><p><span style="color: #ce9178;">需要带有作曲家的新包:</span><br/></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false">composer require inchoo/custom-router:dev-master</pre><p><span style="color: #ce9178;">启用 Inchoo 自定义路由器模块</span><br/></p><p><span style="color: #ce9178;"></span></p><pre class="brush:bash;toolbar:false">php bin/magento module:enable Inchoo_CustomRouter</pre><p><span style="color: #ce9178;">刷新所有内容:</span><br/></p><pre class="brush:bash;toolbar:false">php bin/magento setup:upgrade</pre><p><br/></p>