解析順序
布局xml文件一般位于app/design/{area}/{package}/{theme}/layout/目錄下。Layout文件一般包含block、reference、action三種標(biāo)簽。
?
對于Magento系統(tǒng),首先會將系統(tǒng)中相關(guān)相關(guān)的layout合并,合并一般是包括app\design\frontend\base \default\layout目錄下的xml文件,以及指定的模板下面的對應(yīng)的layout文件。最終普通網(wǎng)頁合并之后的從default下 output=”toHtml”進(jìn)行最終的輸出,那么解析的block或其他元素也是從該節(jié)點進(jìn)行解析。
?
1.頂層的block一般位于page.xml中,如下所示。Output表示通過toHtml進(jìn)行輸出。默認(rèn)使用3columns.phtml三列布局。Type對應(yīng)Mage_Page_Block_Html類。
<block type="page/html" name="root" output="toHtml" template="page/3columns.phtml">?
2.在頂層的block中,一般包含以下幾個關(guān)鍵部分,分別是Html頭部、網(wǎng)頁頭部、內(nèi)容左部中部右部、網(wǎng)頁底部這么幾個基本結(jié)構(gòu)布局。
<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.每個模塊一般情況下都會有對應(yīng)的模塊xml文件,如目錄布局文件為catalog.xml文件,支付為checkout.xml。不過對于magento系統(tǒng)來說,最終還是合并讀取的。
?
4.如果是目錄模塊被調(diào)用,在catalog.xml中,首先會將default節(jié)點中所有元素進(jìn)行加載和解析,然后根據(jù)對應(yīng)產(chǎn)品模塊具體頁面加載 對應(yīng)的節(jié)點,如分類文件默認(rèn)采用catalog_category_default節(jié)點下的元素更新,如果分類設(shè)置為Is Anchor,則采用catalog_category_layered節(jié)點下的元素更新。產(chǎn)品默認(rèn)采用catalog_product_view節(jié)點下 的元素更新。
?
現(xiàn)在我們詳細(xì)的分析一下page中的各個布局結(jié)構(gòu)
1.Html頭部:Html頭部主要包括增加默認(rèn)的js和css相關(guān)文件。
<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.左右部側(cè)欄,一般有product_compare_sidebar、catalog.leftnav、catalog.product.related等側(cè)邊欄,具體需要看對應(yīng)頁面的所對應(yīng)的側(cè)邊欄。
?
4.content內(nèi)容一般在具體頁面中進(jìn)行指定,不同模塊的內(nèi)容肯定是不同的,在page.xml文件中只是定義了一個as。
?
5.footer包括了切換store、常見鏈接等。
?
解析內(nèi)容
布局xml文件一般位于app/design/{area}/{package}/{theme}/layout/目錄下。Layout文件一般包含block、reference、action三種標(biāo)簽。
?
1.Block標(biāo)簽指明對應(yīng)的Html數(shù)據(jù)塊,在指定是一個Block后,系統(tǒng)首先會根據(jù)該Block的配置生成一個html數(shù)據(jù)塊,然后再繼續(xù)解析它所包含的其他內(nèi)容。
<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所對應(yīng)的半類名,得到Mage_Checkout_Block,再和 cart_sidebar組成全稱類名為Mage_Checkout_Block_Cart_Sidebar,該Block類所對應(yīng)的模板文件為 checkout/cart/sidebar.phtml,before=”-”表明在同級別上,它是排在最前面的。Name需要唯一,作為解析和引用使 用。
然后在解析子Block時候,如type=”core/text_list”的Block,會告訴他的父節(jié)點cart_sidebar該子節(jié)點信息,這 樣,在父節(jié)點所對應(yīng)的模板文件中,才能使用getChildHtml(“cart_sidebar.extra_actions”)函數(shù)調(diào)用子節(jié)點的 html信息。
如果有as節(jié)點,表示該節(jié)點可以在其他地方被引用,也就是說可以在其他地方再次解析,比如as=’left’,則可以在其他地方用reference中進(jìn)行添加相關(guān)block操作。
?
2.Reference標(biāo)簽指明其他Block Name在該區(qū)域的一個引用,Reference所對應(yīng)的Block一般都有as屬性。一般也只有一個name值,表示這一Block會使用該 Reference填充內(nèi)容,將該Reference下的子Block作為對應(yīng)Blok的子Block進(jìn)行解析。
?
3.Action表明指定的Block執(zhí)行一些特別的動作,比如添加js,css,給常量賦值,調(diào)用Block中對應(yīng)的函數(shù)等。
<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當(dāng)中調(diào)用Mage_Core_Block_Template類解析callouts/right_col.phtml。在該block下的action中,沒有指定節(jié)點,表明該action作用于上級Block即right.permanent.callout。在方法中使用setImgSrc函數(shù),那么對應(yīng)的,可以在模板中使用getImgSrc獲取到action中所包含的值。
在setImgAlt中,也可以使用getImgAlt獲取值,不過其中使用translate屬性和module屬性,那么會調(diào)用Catalog中的Helper,對alt中的內(nèi)容進(jìn)行翻譯成對應(yīng)的本地化文字。
?
附:
* 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當(dāng)中,Magento首先會將所有文件存儲在$_data當(dāng)中,最終通過getCssJsHtml函數(shù)解析成對應(yīng)的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>?
通用的函數(shù)是addItem,需要指定type和name,如果有條件判斷的話就放在if標(biāo)簽當(dāng)中
如果需要刪除某個js或者css,可以使用removeItem方法
jslib/ds-sleight.js
?
其他的action函數(shù)需要看其type所對應(yīng)的類中所支持的函數(shù)。
/** * 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)包含一小部分的標(biāo)記集合,作為詳細(xì)說明關(guān)于程序如何建立一個頁面,如何建立它的行為和每個構(gòu)建的區(qū)塊。最佳 的布局途徑是在每個角度正確的劃分和使用。為了讓您能夠做到這一點,下面是一些行為特性的布局XML標(biāo)記。
句柄(Handle)
Handle (圖1)是一個標(biāo)識符,決定應(yīng)用程序要如何通過嵌套的更新處理它。
如果句柄的名稱是<default>,然后應(yīng)用程序知道在加載網(wǎng)店的幾乎所有頁面之前應(yīng)該加載此特定頁面布局的嵌套更新(我們說'幾乎 所有的',因為一些特殊的頁面像產(chǎn)品圖片彈出窗口就沒有加載布局中的<default>句柄)。
如果Magento找到<default>以外的句柄,它將按照指定的句柄中的頁面嵌套更新對頁面進(jìn)行處理。例 如,<catalog_product_view>包含Product View頁面的布局更新,而<catalog_product_compare_index>包含Compare Product 頁面的更新布局。句柄作為設(shè)計人員設(shè)置在網(wǎng)店中的標(biāo)識符,他不需要廣泛的理解 Magento編程,也不應(yīng)該需要修改。
<block>
Magento通過<block>標(biāo)記決定頁面中的每個區(qū)塊的行為和視覺表現(xiàn)。在Magento中我們已經(jīng)提到了兩種類型的區(qū)塊-結(jié) 構(gòu)區(qū)塊(structural blocks)和內(nèi) 容區(qū)塊(content blocks)。區(qū)分這兩種區(qū)塊最好的方式是通過分配給它的標(biāo)記屬性來區(qū)分。結(jié)構(gòu)區(qū)塊通常包含屬性'as',通過這個屬 性值程序可以與指定的區(qū)域(由getChildHtml 方法指定)中的模板聯(lián)系。你會發(fā)現(xiàn)在默認(rèn)布局許多地方出現(xiàn)這個'as'屬性,因為默認(rèn)布局的一個性質(zhì)就是是建立一個實際的布局,在各個不同的頁面 中的具體布局上就可以開始增加。例如,在默認(rèn)布局中,有像‘left’、‘right’、‘content’和‘footer’這些結(jié)構(gòu)區(qū)塊。并不是說這 些區(qū)塊不能存在于正常的布局更新中,但我們?yōu)槭裁床皇紫仍谀J(rèn)布局中建立這些結(jié)構(gòu)區(qū)塊,然后在后面每個具體的頁面基礎(chǔ)上添加內(nèi)容呢?讓我們進(jìn)一步挖 掘<block>的現(xiàn)有屬性。
- type – 這是模塊類的標(biāo)識符,它定義了區(qū)塊的功能。此屬性不應(yīng)該被修改。
- name – 這是名稱,其他的區(qū)塊可以通過此名稱引用此區(qū)塊(看圖3)。
- before (and) after – 這兩種方法決定內(nèi)容區(qū)塊在結(jié)構(gòu)區(qū)塊中的位置。before="-" 和 after="-"這樣的命令標(biāo)志此區(qū)塊的位置是一個結(jié)構(gòu)區(qū)塊的最上方或最下方。
-
template
- 這個屬性指定的值決定了此區(qū)塊的功能是使用哪個模板。例如,如果這個屬性值指定了'
catalog/category/view.phtml
', 程序就會載入‘app/design/frontend/template/catalog/category/view.phtml
’ 模板文件。要了解布局是如何通過模板執(zhí)行的,閱讀分 步指南建設(shè)一個主題。 - action – <action> 是用來控制前臺的功能的,如加載或不加載一個JavaScript。一套完整的action方式將很快推出,但此時的最佳的學(xué)習(xí)途徑是了解現(xiàn)有的布局更新 上面的不同Action方法。
- as – 此屬性指 定模板文件中會調(diào)用那個區(qū)塊。當(dāng)您在模板中看到getChildHtml(' block_name ')的PHP方法,可以肯定它指的是引用屬性'as'的值為' block_name '的區(qū)塊。 (例如:在骨架模板中的方法<?=$this->getChildHtml('header')?>是調(diào)用<block as=“header”>)
<reference>
<reference>是用來引用另一個區(qū)塊。要引用靈位一個區(qū)塊,在內(nèi)部的更新將應(yīng)用于與其關(guān)聯(lián)的<block>(見圖 3)。
要使用引用,可以通過區(qū)塊中的‘name’屬性值引用。此屬性的指向標(biāo)簽中'name'屬性。所以,如果你使用<reference name="right">,響應(yīng)的區(qū)塊名稱將是<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
?
?
?
?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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