magento的布局文件layout.xml文件详解

解析顺序

布局xml文件一般位于app/design/{area}/{package}/{theme}/layout/目录下。Layout文件一般包含block、reference、action三种标签。

对于Magento系统,首先会将系统中相关相关的layout合并,合并一般是包括app\design\frontend\base \default\layout目录下的xml文件,以及指定的模板下面的对应的layout文件。最终普通网页合并之后的从default下 output=”toHtml”进行最终的输出,那么解析的block或其他元素也是从该节点进行解析。

1.顶层的block一般位于page.xml中,如下所示。Output表示通过toHtml进行输出。默认使用3columns.phtml三列布局。Type对应Mage_Page_Block_Html类。

  1. <block type="page/html" name="root" output="toHtml" template="page/3columns.phtml">

2.在顶层的block中,一般包含以下几个关键部分,分别是Html头部、网页头部、内容左部中部右部、网页底部这么几个基本结构布局。

  1. <block type="page/html_head" name="head" as="head">
  2. <block type="page/html_header" name="header" as="header">
  3. <block type="page/html_breadcrumbs" name="breadcrumbs" as="breadcrumbs"/>
  4. <block type="core/text_list" name="left" as="left" translate="label">
  5. <block type="core/text_list" name="content" as="content" translate="label">
  6. <block type="core/text_list" name="right" as="right" translate="label">
  7. <block type="page/html_footer" name="footer" as="footer" template="page/html/footer.phtml">

3.每个模块一般情况下都会有对应的模块xml文件,如目录布局文件为catalog.xml文件,支付为checkout.xml。不过对于magento系统来说,最终还是合并读取的。

4.如果是目录模块被调用,在catalog.xml中,首先会将default节点中所有元素进行加载和解析,然后根据对应产品模块具体页面加载 对应的节点,如分类文件默认采用catalog_category_default节点下的元素更新,如果分类设置为Is Anchor,则采用catalog_category_layered节点下的元素更新。产品默认采用catalog_product_view节点下 的元素更新。

现在我们详细的分析一下page中的各个布局结构

1.Html头部:Html头部主要包括增加默认的js和css相关文件。

  1. <block type="page/html_head" name="head" as="head">
  2. <action method="addJs"><script>prototype/prototype.js</script></action>
  3. <action method="addCss"><stylesheet>css/styles.css</stylesheet></action>
  4. </block>

2.页面头部:主要包括一些头部链接、语言切换等

  1. <block type="page/html_header" name="header" as="header">
  2. <block type="page/template_links" name="top.links" as="topLinks"/>
  3. <block type="page/switch" name="store_language" as="store_language" template="page/switch/languages.phtml"/>
  4. <block type="core/text_list" name="top.menu" as="topMenu" translate="label">
  5. <label>Navigation Bar</label>
  6. </block>
  7. <block type="page/html_wrapper" name="top.container" as="topContainer" translate="label">
  8. <label>Page Header</label>
  9. <action method="setElementClass"><value>top-container</value></action>
  10. </block>
  11. </block>

3.左右部侧栏,一般有product_compare_sidebar、catalog.leftnav、catalog.product.related等侧边栏,具体需要看对应页面的所对应的侧边栏。

4.content内容一般在具体页面中进行指定,不同模块的内容肯定是不同的,在page.xml文件中只是定义了一个as。

5.footer包括了切换store、常见链接等。

解析内容

布局xml文件一般位于app/design/{area}/{package}/{theme}/layout/目录下。Layout文件一般包含block、reference、action三种标签。

1.Block标签指明对应的Html数据块,在指定是一个Block后,系统首先会根据该Block的配置生成一个html数据块,然后再继续解析它所包含的其他内容。

  1. <block type="checkout/cart_sidebar" name="cart_sidebar" template="checkout/cart/sidebar.phtml" before="-">
  2. <action method="addItemRender"><type>configurable</type><block>checkout/cart_item_renderer_configurable</block><template>checkout/cart/sidebar/default.phtml</template></action>
  3. <block type="core/text_list" name="cart_sidebar.extra_actions" as="extra_actions" translate="label" module="checkout">
  4. <label>Shopping Cart Sidebar Extra Actions</label>
  5. </block>
  6. </block>

如在解析type=”checkout/cart_sidebar”
block的时候,首先在config.xml找到checkout的block所对应的半类名,得到Mage_Checkout_Block,再和
cart_sidebar组成全称类名为Mage_Checkout_Block_Cart_Sidebar,该Block类所对应的模板文件为
checkout/cart/sidebar.phtml,before=”-”表明在同级别上,它是排在最前面的。Name需要唯一,作为解析和引用使
用。

然后在解析子Block时候,如type=”core/text_list”的Block,会告诉他的父节点cart_sidebar该子节点信息,这
样,在父节点所对应的模板文件中,才能使用getChildHtml(“cart_sidebar.extra_actions”)函数调用子节点的
html信息。
如果有as节点,表示该节点可以在其他地方被引用,也就是说可以在其他地方再次解析,比如as=’left’,则可以在其他地方用reference中进行添加相关block操作。

2.Reference标签指明其他Block
Name在该区域的一个引用,Reference所对应的Block一般都有as属性。一般也只有一个name值,表示这一Block会使用该
Reference填充内容,将该Reference下的子Block作为对应Blok的子Block进行解析。

3.Action表明指定的Block执行一些特别的动作,比如添加js,css,给常量赋值,调用Block中对应的函数等。

  1. <block type="core/template" name="right.permanent.callout" template="callouts/right_col.phtml">
  2. <action method="setImgSrc"><src>images/media/col_right_callout.jpg</src></action>
  3. <action method="setImgAlt" translate="alt" module="catalog"><alt>Keep your eyes open for our special Back to School items and save A LOT!</alt></action>
  4. </block>

在Block当中调用Mage_Core_Block_Template类解析callouts/right_col.phtml。在该block
下的action中,没有指定节点,表明该action作用于上级Block即right.permanent.callout。在方法中使用
setImgSrc函数,那么对应的,可以在模板中使用getImgSrc获取到action中所包含的值。

在setImgAlt中,也可以使用getImgAlt获取值,不过其中使用translate属性和module属性,那么会调用Catalog中的Helper,对alt中的内容进行翻译成对应的本地化文字。

附:

  1. * Create layout blocks from configuration
  2. *
  3. * @param Mage_Core_Layout_Element|null $parent
  4. */
  5. public function generateBlocks($parent=null)//Mage_Core_Model_Layout
  6. {
  7. if (emptyempty($parent)) {
  8. $parent = $this->getNode();
  9. }
  10. foreach ($parent as $node) {
  11. $attributes = $node->attributes();
  12. if ((bool)$attributes->ignore) {
  13. continue;
  14. }
  15. switch ($node->getName()) {
  16. case 'block':
  17. $this->_generateBlock($node, $parent);
  18. $this->generateBlocks($node);
  19. break;
  20. case 'reference':
  21. $this->generateBlocks($node);
  22. break;
  23. case 'action':
  24. $this->_generateAction($node, $parent);
  25. break;
  26. }
  27. }
  28. }
  29. protected function _generateBlock($node, $parent)
  30. {
  31. if (!emptyempty($node['class'])) {
  32. $className = (string)$node['class'];
  33. } else {
  34. $className = Mage::getConfig()->getBlockClassName((string)$node['type']);
  35. }
  36. $blockName = (string)$node['name'];
  37. $_profilerKey = 'BLOCK: '.$blockName;
  38. Varien_Profiler::start($_profilerKey);
  39. $block = $this->addBlock($className, $blockName);
  40. if (!$block) {
  41. return $this;
  42. }
  43. if (!emptyempty($node['parent'])) {
  44. $parentBlock = $this->getBlock((string)$node['parent']);
  45. } else {
  46. $parentName = $parent->getBlockName();
  47. if (!emptyempty($parentName)) {
  48. $parentBlock = $this->getBlock($parentName);
  49. }
  50. }
  51. if (!emptyempty($parentBlock)) {
  52. $alias = isset($node['as']) ? (string)$node['as'] : '';
  53. if (isset($node['before'])) {
  54. $sibling = (string)$node['before'];
  55. if ('-'===$sibling) {
  56. $sibling = '';
  57. }
  58. $parentBlock->insert($block, $sibling, false, $alias);
  59. } elseif (isset($node['after'])) {
  60. $sibling = (string)$node['after'];
  61. if ('-'===$sibling) {
  62. $sibling = '';
  63. }
  64. $parentBlock->insert($block, $sibling, true, $alias);
  65. } else {
  66. $parentBlock->append($block, $alias);
  67. }
  68. }
  69. if (!emptyempty($node['template'])) {
  70. $block->setTemplate((string)$node['template']);
  71. }
  72. if (!emptyempty($node['output'])) {
  73. $method = (string)$node['output'];
  74. $this->addOutputBlock($blockName, $method);
  75. }
  76. Varien_Profiler::stop($_profilerKey);
  77. return $this;
  78. }
  79. protected function _generateAction($node, $parent)
  80. {
  81. if (isset($node['ifconfig']) && ($configPath = (string)$node['ifconfig'])) {
  82. if (!Mage::getStoreConfigFlag($configPath)) {
  83. return $this;
  84. }
  85. }
  86. $method = (string)$node['method'];
  87. if (!emptyempty($node['block'])) {
  88. $parentName = (string)$node['block'];
  89. } else {
  90. $parentName = $parent->getBlockName();
  91. }
  92. $_profilerKey = 'BLOCK ACTION: '.$parentName.' -> '.$method;
  93. Varien_Profiler::start($_profilerKey);
  94. if (!emptyempty($parentName)) {
  95. $block = $this->getBlock($parentName);
  96. }
  97. if (!emptyempty($block)) {
  98. $args = (array)$node->children();
  99. unset($args['@attributes']);
  100. foreach ($args as $key => $arg) {
  101. if (($arg instanceof Mage_Core_Model_Layout_Element)) {
  102. if (isset($arg['helper'])) {
  103. $helperName = explode('/', (string)$arg['helper']);
  104. $helperMethod = array_pop($helperName);
  105. $helperName = implode('/', $helperName);
  106. $arg = $arg->asArray();
  107. unset($arg['@']);
  108. $args[$key] = call_user_func_array(array(Mage::helper($helperName), $helperMethod), $arg);
  109. } else {
  110. /**
  111. * if there is no helper we hope that this is assoc array
  112. */
  113. $arr = array();
  114. foreach($arg as $subkey => $value) {
  115. $arr[(string)$subkey] = $value->asArray();
  116. }
  117. if (!emptyempty($arr)) {
  118. $args[$key] = $arr;
  119. }
  120. }
  121. }
  122. }
  123. if (isset($node['json'])) {
  124. $json = explode(' ', (string)$node['json']);
  125. foreach ($json as $arg) {
  126. $args[$arg] = Mage::helper('core')->jsonDecode($args[$arg]);
  127. }
  128. }
  129. $this->_translateLayoutNode($node, $args);
  130. call_user_func_array(array($block, $method), $args);
  131. }
  132. Varien_Profiler::stop($_profilerKey);
  133. return $this;
  134. }

在addJs、addCss的代码一般在page/html_head类型的block当中,Magento首先会将所有文件存储在$_data当中,最终通过getCssJsHtml函数解析成对应的html代码输出。

Head中支持add类型的方法有addCss、addJs、addCssIe、addJsIe、addLinkRel五种。

  1. <reference name="head">
  2. <action method="addCss"><stylesheet>css/local.css</stylesheet></action>
  3. <action method="addJs"><script>scriptaculous/controls.js</script></action>
  4. <action method="addItem"><type>js</type><name>lib/ds-sleight.js</name><params/><if>lt IE 7</if></action>
  5. </reference>

通用的函数是addItem,需要指定type和name,如果有条件判断的话就放在if标签当中

如果需要删除某个js或者css,可以使用removeItem方法

jslib/ds-sleight.js

其他的action函数需要看其type所对应的类中所支持的函数。

  1. /**
  2. * Get HEAD HTML with CSS/JS/RSS definitions
  3. * (actually it also renders other elements, TODO: fix it up or rename this method)
  4. *
  5. * @return string
  6. */
  7. public function getCssJsHtml()//Mage_Page_Block_Html_Head extends Mage_Core_Block_Template
  8. {
  9. // separate items by types
  10. $lines  = array();
  11. foreach ($this->_data['items'] as $item) {
  12. if (!is_null($item['cond']) && !$this->getData($item['cond']) || !isset($item['name'])) {
  13. continue;
  14. }
  15. $if     = !emptyempty($item['if']) ? $item['if'] : '';
  16. $params = !emptyempty($item['params']) ? $item['params'] : '';
  17. switch ($item['type']) {
  18. case 'js':        // js/*.js
  19. case 'skin_js':   // skin/*/*.js
  20. case 'js_css':    // js/*.css
  21. case 'skin_css':  // skin/*/*.css
  22. $lines[$if][$item['type']][$params][$item['name']] = $item['name'];
  23. break;
  24. default:
  25. $this->_separateOtherHtmlHeadElements($lines, $if, $item['type'], $params, $item['name'], $item);
  26. break;
  27. }
  28. }
  29. // prepare HTML
  30. $shouldMergeJs = Mage::getStoreConfigFlag('dev/js/merge_files');
  31. $shouldMergeCss = Mage::getStoreConfigFlag('dev/css/merge_css_files');
  32. $html   = '';
  33. foreach ($lines as $if => $items) {
  34. if (emptyempty($items)) {
  35. continue;
  36. }
  37. if (!emptyempty($if)) {
  38. $html .= '<!--[if '.$if.']>'."\n";
  39. }
  40. // static and skin css
  41. $html .= $this->_prepareStaticAndSkinElements('<link rel="stylesheet" type="text/css" href="%s"%s />' . "\n",
  42. emptyempty($items['js_css']) ? array() : $items['js_css'],
  43. emptyempty($items['skin_css']) ? array() : $items['skin_css'],
  44. $shouldMergeCss ? array(Mage::getDesign(), 'getMergedCssUrl') : null
  45. );
  46. // static and skin javascripts
  47. $html .= $this->_prepareStaticAndSkinElements('<script type="text/javascript" src="%s"%s></script>' . "\n",
  48. emptyempty($items['js']) ? array() : $items['js'],
  49. emptyempty($items['skin_js']) ? array() : $items['skin_js'],
  50. $shouldMergeJs ? array(Mage::getDesign(), 'getMergedJsUrl') : null
  51. );
  52. // other stuff
  53. if (!emptyempty($items['other'])) {
  54. $html .= $this->_prepareOtherHtmlHeadElements($items['other']) . "\n";
  55. }
  56. if (!emptyempty($if)) {
  57. $html .= '<![endif]-->'."\n";
  58. }
  59. }
  60. return $html;
  61. }

来源:http://www.ahuasheng.com/magento-layout-xml-parse-content.html

布局原理解析

Magento中的布局(Layout)包含一小部分的标记集合,作为详细说明关于程序如何建立一个页面,如何建立它的行为和每个构建的区块。最佳 的布局途径是在每个角度正确的划分和使用。为了让您能够做到这一点,下面是一些行为特性的布局XML标记。


句柄(Handle)

Handle (图1)是一个标识符,决定应用程序要如何通过嵌套的更新处理它。

如果句柄的名称是<default>,然后应用程序知道在加载网店的几乎所有页面之前应该加载此特定页面布局的嵌套更新(我们说'几乎 所有的',因为一些特殊的页面像产品图片弹出窗口就没有加载布局中的<default>句柄)。

如果Magento找到<default>以外的句柄,它将按照指定的句柄中的页面嵌套更新对页面进行处理。例
如,<catalog_product_view>包含Product
View页面的布局更新,而<catalog_product_compare_index>包含Compare Product
页面的更新布局。句柄作为设计人员设置在网店中的标识符,他不需要广泛的理解 Magento编程,也不应该需要修改。


<block>

Magento通过<block>标记决定页面中的每个区块的行为和视觉表现。在Magento中我们已经提到了两种类型的区块-结
构区块(structural blocks)和内 容区块(content
blocks)。区分这两种区块最好的方式是通过分配给它的标记属性来区分。结构区块通常包含属性'as',通过这个属
性值程序可以与指定的区域(由getChildHtml
方法指定)中的模板联系。你会发现在默认布局许多地方出现这个'as'属性,因为默认布局的一个性质就是是建立一个实际的布局,在各个不同的页面
中的具体布局上就可以开始增加。例如,在默认布局中,有像‘left’、‘right’、‘content’和‘footer’这些结构区块。并不是说这
些区块不能存在于正常的布局更新中,但我们为什么不首先在默认布局中建立这些结构区块,然后在后面每个具体的页面基础上添加内容呢?让我们进一步挖
掘<block>的现有属性。

  • type
    – 这是模块类的标识符,它定义了区块的功能。此属性不应该被修改。
  • name
    – 这是名称,其他的区块可以通过此名称引用此区块(看图3)。
  • before
    (and) after
    – 这两种方法决定内容区块在结构区块中的位置。before="-" 和 after="-"这样的命令标志此区块的位置是一个结构区块的最上方或最下方。
  • template
    - 这个属性指定的值决定了此区块的功能是使用哪个模板。例如,如果这个属性值指定了'catalog/category/view.phtml
    ', 程序就会载入‘app/design/frontend/template/catalog/category/view.phtml
    ’ 模板文件。要了解布局是如何通过模板执行的,阅读分 步指南建设一个主题。
  • action
    – <action> 是用来控制前台的功能的,如加载或不加载一个JavaScript。一套完整的action方式将很快推出,但此时的最佳的学习途径是了解现有的布局更新 上面的不同Action方法。
  • as
    – 此属性指 定模板文件中会调用那个区块。当您在模板中看到getChildHtml('
    block_name ')的PHP方法,可以肯定它指的是引用属性'as'的值为' block_name '的区块。
    (例如:在骨架模板中的方法<?=$this->getChildHtml('header')?>是调用<block
    as=“header”>)

<reference>

<reference>是用来引用另一个区块。要引用灵位一个区块,在内部的更新将应用于与其关联的<block>(见图 3)。

要使用引用,可以通过区块中的‘name’属性值引用。此属性的指向标签中'name'属性。所以,如果你使用<reference name="right">,响应的区块名称将是<block name="right">。

图3:

来源:
http://www.magentobbs.com/index.php?q=content/%E5%B8%83%E5%B1%80%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90%EF%BC%88anatomy-layout%EF%BC%89

magento的布局文件之谜的更多相关文章

  1. Magento的布局(Layout),块(Block)和模板(Template)

    public function indexAction() { //remove our previous echo //echo 'Hello Index!'; $this->loadLayo ...

  2. Android Studio分类整理res/Layout中的布局文件(创建子目录)

    res/layout中的布局文件太杂,没有层次感,受不了的我治好想办法解决这个问题. 前几天看博客说可以使用插件分组,可惜我没找到.知道看到另一篇博客时,才知道这个方法不能用了. 不能用插件,那就手动 ...

  3. Android 自定义View及其在布局文件中的使用示例

    前言: 尽管Android已经为我们提供了一套丰富的控件,如:Button,ImageView,TextView,EditText等众多控件,但是,有时候在项目开发过程中,还是需要开发者自定义一些需要 ...

  4. 在布局文件中使用Fragment的步骤

    为了在Activity布局文件中使用Fragment我们需要四个步骤. 1.定义一个Activity,他继承android.support.v4.app.FragmentActivity,下面是关键代 ...

  5. Android笔记——在布局文件中插入另一个布局文件

    假如有一个布局文件A.xml想把另外一个布局文件B.xml引进其布局,则可以通过下面的代码 <include layout="@layout/B" />

  6. bug__android studio 出现布局文件不提示,且点击代码不能跟踪代码

    1,点击布局文件,出现  Cannot find declaration to  go to ? 且 点击代码不能跟踪代码? 把 项目的build.gradle 中的  compileSdkVersi ...

  7. android 非activity如何得到布局文件 (java文件中获取布局文件)

    Android中得到布局文件对象有两种方式第一种,在Activity所在类中this.getLayoutInflater().inflater(R.layout.布局文件名,null);第二种,在非A ...

  8. Android学习---ListView和Inflater的使用,将一个布局文件转化为一个对象

    本文将介绍ListView和Inflater的使用,将接上一篇文章内容. 一.什么是ListView? 在android开发中ListView是比较常用的控件,ListView 控件可使用四种不同视图 ...

  9. Android中将布局文件转成bitmap

    在实践中发现,有些需要打印的小票高度小于屏幕的高度,而有些小票内容过多高度高于屏幕高度. 小于屏幕高度的布局文件转成bitmap较为容易,高于屏幕高度的布局文件转成长图bitmap较为复杂. 一.小于 ...

随机推荐

  1. TDD、BDD、DDD

    TDDTest-Driven DevelopmentTest-Driven Development (TDD) is a software development technique where au ...

  2. 【Robot Framework 项目实战 02】SeleniumLibrary Web UI 自动化

    前言 SeleniumLibrary 是针对 Robot Framework 开发的 Selenium 库.它也 Robot Framework 下面最流程的库之一.主要用于编写 Web UI 自动化 ...

  3. Codeforces 918D - MADMAX

    918D - MADMAX 思路: dp+记忆化搜索 状态:dp[i][j][w]表示先手在i节点,后手在j节点,这一轮的字母为w的结果,如果为true,则表示先手必赢,否则后手必赢. 状态转移:如果 ...

  4. UVA - 11853 Paintball(dfs)

    UVA - 11853 思路:dfs,从最上面超过上边界的圆开始搜索,看能不能搜到最下面超过下边界的圆. 代码: #include<bits/stdc++.h> using namespa ...

  5. grub 启动错误 "file not found"

    刚安装ubuntu 14.4 竟然出现这么尴尬的事,ubuntu 行不行? 幸好还是能从u盘启动后,转到硬盘. 然后在网上找到了解决方法. http://askubuntu.com/questions ...

  6. 雷林鹏分享:Ruby 哈希(Hash)

    Ruby 哈希(Hash) 哈希(Hash)是类似 "employee" => "salary" 这样的键值对的集合.哈希的索引是通过任何对象类型的任意键 ...

  7. English trip -- VC(情景课) 8 B job duties 工作职责

    Vocabulary focus  核心词汇 She is a receptionist. She answers the phone. She is a cashier She counts mon ...

  8. win10 WiFi 密码查询 命令

    如果你笔记本有WiFi,正好你系统又是Win10 那么... netsh wlan show profile * key=clear

  9. LeetCode--168--Excel表列名称

    问题描述: 给定一个正整数,返回它在 Excel 表中相对应的列名称. 例如, 1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 ...

  10. Mass Change Queries CodeForces - 911G (线段树合并)

    链接 大意: 给定序列, 每次操作将区间[l,r]中的x全改为y, 最后输出序列 权值范围比较小, 对每个权值开一颗线段树, 每次将x合并到y上即可 #include <iostream> ...