解析順序
布局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類。
<block type="page/html" name="root" output="toHtml" template="page/3columns.phtml">?
2.在頂層的block中,一般包含以下幾個關鍵部分,分別是Html頭部、網頁頭部、內容左部中部右部、網頁底部這么幾個基本結構布局。
<block type="page/html_head" name="head" as="head"> <block type="page/html_header" name="header" as="header"> <block type="page/html_breadcrumbs" name="breadcrumbs" as="breadcrumbs"/> <block type="core/text_list" name="left" as="left" translate="label"> <block type="core/text_list" name="content" as="content" translate="label"> <block type="core/text_list" name="right" as="right" translate="label"> <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相關文件。
<block type="page/html_head" name="head" as="head"> <action method="addJs"><script>prototype/prototype.js</script></action> <action method="addCss"><stylesheet>css/styles.css</stylesheet></action> </block>?
2.頁面頭部:主要包括一些頭部鏈接、語言切換等
<block type="page/html_header" name="header" as="header"> <block type="page/template_links" name="top.links" as="topLinks"/> <block type="page/switch" name="store_language" as="store_language" template="page/switch/languages.phtml"/> <block type="core/text_list" name="top.menu" as="topMenu" translate="label"> <label>Navigation Bar</label> </block> <block type="page/html_wrapper" name="top.container" as="topContainer" translate="label"> <label>Page Header</label> <action method="setElementClass"><value>top-container</value></action> </block> </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數據塊,然后再繼續解析它所包含的其他內容。
<block type="checkout/cart_sidebar" name="cart_sidebar" template="checkout/cart/sidebar.phtml" before="-"> <action method="addItemRender"><type>configurable</type><block>checkout/cart_item_renderer_configurable</block><template>checkout/cart/sidebar/default.phtml</template></action> <block type="core/text_list" name="cart_sidebar.extra_actions" as="extra_actions" translate="label" module="checkout"> <label>Shopping Cart Sidebar Extra Actions</label> </block> </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中對應的函數等。
<block type="core/template" name="right.permanent.callout" template="callouts/right_col.phtml"> <action method="setImgSrc"><src>images/media/col_right_callout.jpg</src></action> <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> </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中的內容進行翻譯成對應的本地化文字。
?
附:
* Create layout blocks from configuration * * @param Mage_Core_Layout_Element|null $parent */ public function generateBlocks($parent=null)//Mage_Core_Model_Layout { if (empty($parent)) { $parent = $this->getNode(); } foreach ($parent as $node) { $attributes = $node->attributes(); if ((bool)$attributes->ignore) { continue; } switch ($node->getName()) { case 'block': $this->_generateBlock($node, $parent); $this->generateBlocks($node); break; case 'reference': $this->generateBlocks($node); break; case 'action': $this->_generateAction($node, $parent); break; } } } protected function _generateBlock($node, $parent) { if (!empty($node['class'])) { $className = (string)$node['class']; } else { $className = Mage::getConfig()->getBlockClassName((string)$node['type']); } $blockName = (string)$node['name']; $_profilerKey = 'BLOCK: '.$blockName; Varien_Profiler::start($_profilerKey); $block = $this->addBlock($className, $blockName); if (!$block) { return $this; } if (!empty($node['parent'])) { $parentBlock = $this->getBlock((string)$node['parent']); } else { $parentName = $parent->getBlockName(); if (!empty($parentName)) { $parentBlock = $this->getBlock($parentName); } } if (!empty($parentBlock)) { $alias = isset($node['as']) ? (string)$node['as'] : ''; if (isset($node['before'])) { $sibling = (string)$node['before']; if ('-'===$sibling) { $sibling = ''; } $parentBlock->insert($block, $sibling, false, $alias); } elseif (isset($node['after'])) { $sibling = (string)$node['after']; if ('-'===$sibling) { $sibling = ''; } $parentBlock->insert($block, $sibling, true, $alias); } else { $parentBlock->append($block, $alias); } } if (!empty($node['template'])) { $block->setTemplate((string)$node['template']); } if (!empty($node['output'])) { $method = (string)$node['output']; $this->addOutputBlock($blockName, $method); } Varien_Profiler::stop($_profilerKey); return $this; } protected function _generateAction($node, $parent) { if (isset($node['ifconfig']) && ($configPath = (string)$node['ifconfig'])) { if (!Mage::getStoreConfigFlag($configPath)) { return $this; } } $method = (string)$node['method']; if (!empty($node['block'])) { $parentName = (string)$node['block']; } else { $parentName = $parent->getBlockName(); } $_profilerKey = 'BLOCK ACTION: '.$parentName.' -> '.$method; Varien_Profiler::start($_profilerKey); if (!empty($parentName)) { $block = $this->getBlock($parentName); } if (!empty($block)) { $args = (array)$node->children(); unset($args['@attributes']); foreach ($args as $key => $arg) { if (($arg instanceof Mage_Core_Model_Layout_Element)) { if (isset($arg['helper'])) { $helperName = explode('/', (string)$arg['helper']); $helperMethod = array_pop($helperName); $helperName = implode('/', $helperName); $arg = $arg->asArray(); unset($arg['@']); $args[$key] = call_user_func_array(array(Mage::helper($helperName), $helperMethod), $arg); } else { /** * if there is no helper we hope that this is assoc array */ $arr = array(); foreach($arg as $subkey => $value) { $arr[(string)$subkey] = $value->asArray(); } if (!empty($arr)) { $args[$key] = $arr; } } } } if (isset($node['json'])) { $json = explode(' ', (string)$node['json']); foreach ($json as $arg) { $args[$arg] = Mage::helper('core')->jsonDecode($args[$arg]); } } $this->_translateLayoutNode($node, $args); call_user_func_array(array($block, $method), $args); } Varien_Profiler::stop($_profilerKey); return $this; }?
在addJs、addCss的代碼一般在page/html_head類型的block當中,Magento首先會將所有文件存儲在$_data當中,最終通過getCssJsHtml函數解析成對應的html代碼輸出。
Head中支持add類型的方法有addCss、addJs、addCssIe、addJsIe、addLinkRel五種。
<reference name="head"> <action method="addCss"><stylesheet>css/local.css</stylesheet></action> <action method="addJs"><script>scriptaculous/controls.js</script></action> <action method="addItem"><type>js</type><name>lib/ds-sleight.js</name><params/><if>lt IE 7</if></action> </reference>?
通用的函數是addItem,需要指定type和name,如果有條件判斷的話就放在if標簽當中
如果需要刪除某個js或者css,可以使用removeItem方法
jslib/ds-sleight.js
?
其他的action函數需要看其type所對應的類中所支持的函數。
/** * Get HEAD HTML with CSS/JS/RSS definitions * (actually it also renders other elements, TODO: fix it up or rename this method) * * @return string */ public function getCssJsHtml()//Mage_Page_Block_Html_Head extends Mage_Core_Block_Template { // separate items by types $lines = array(); foreach ($this->_data['items'] as $item) { if (!is_null($item['cond']) && !$this->getData($item['cond']) || !isset($item['name'])) { continue; } $if = !empty($item['if']) ? $item['if'] : ''; $params = !empty($item['params']) ? $item['params'] : ''; switch ($item['type']) { case 'js': // js/*.js case 'skin_js': // skin/*/*.js case 'js_css': // js/*.css case 'skin_css': // skin/*/*.css $lines[$if][$item['type']][$params][$item['name']] = $item['name']; break; default: $this->_separateOtherHtmlHeadElements($lines, $if, $item['type'], $params, $item['name'], $item); break; } } // prepare HTML $shouldMergeJs = Mage::getStoreConfigFlag('dev/js/merge_files'); $shouldMergeCss = Mage::getStoreConfigFlag('dev/css/merge_css_files'); $html = ''; foreach ($lines as $if => $items) { if (empty($items)) { continue; } if (!empty($if)) { $html .= '<!--[if '.$if.']>'."\n"; } // static and skin css $html .= $this->_prepareStaticAndSkinElements('<link rel="stylesheet" type="text/css" href="%s"%s />' . "\n", empty($items['js_css']) ? array() : $items['js_css'], empty($items['skin_css']) ? array() : $items['skin_css'], $shouldMergeCss ? array(Mage::getDesign(), 'getMergedCssUrl') : null ); // static and skin javascripts $html .= $this->_prepareStaticAndSkinElements('<script type="text/javascript" src="%s"%s></script>' . "\n", empty($items['js']) ? array() : $items['js'], empty($items['skin_js']) ? array() : $items['skin_js'], $shouldMergeJs ? array(Mage::getDesign(), 'getMergedJsUrl') : null ); // other stuff if (!empty($items['other'])) { $html .= $this->_prepareOtherHtmlHeadElements($items['other']) . "\n"; } if (!empty($if)) { $html .= '<![endif]-->'."\n"; } } return $html; }?
來源: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">。
?
來源: 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
?
?
?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
