Magento Layout

假设读者朋友们已经会自己创建简单的模块,并且使用过 layout xml 来展示某个页面了。那么本篇将对 magento layout 做一个总结,从概念上理顺 magento layout 是什么,它是为了解决什么问题,并串联与之相关的一些知识。

如果你还不会创建模块,请参阅 创建 Magento 2 Hello World Simple Module
如果还没有使用过 layout ,请参阅 Magento 2 中的 Controller

magento layout 是什么

A Layout is a collection of blocks in a tree structure

Layout 是 block 的集合,这些 block 是树形结构组织的。

那么 magento block 是什么?

A Magento block is an object with a toHtml method defined. When this toHtml method is called, it returns the string which should be output to the screen.

可以认为,Magento block 是对象,这个对象拥有方法 toHtml() ,调用这个方法会返回 html 片段的字符串。

早期的 php 开发是 html 和 php 代码混淆在一起的,但是这样很难维护和分工,所以将 html 分离出来,成为模版层。

我们知道 block 都会对应一个 phtml 模版。当 block 的 toHtml() 被调用时,phtml 文件会被 include (就是 php 内置的 include)进去。(详情请参考 Magento 2 Templates: Use $block or $thisMagento\Framework\View\TemplateEngine\Phprender 方法。)

phtml 是可以 override 的,参考 Theme inheritance

layout 可以 extend 也可以 override 。参考 Extend a layoutOverride a layout

嵌套结构

layout xml 的内容如下:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <referenceContainer name="customer.login.container">
        <block class="ThankIT\SocialLogin\Block\SocialBlock" name="thankit_social_block" ifconfig="thankit_sociallogin/general/enable" template="ThankIT_SocialLogin::login/socialblock.phtml" cacheable="false" after="customer.new">
            <block class="ThankIT\SocialLogin\Block\Buttons" name="thankit_login_buttons" template="ThankIT_SocialLogin::login/buttons.phtml" />
        </block>
    </referenceContainer>
</page>

可以看出我们的 block 中嵌套了一个 block ,那么最外面的 block 对应的 ThankIT_SocialLogin::login/socialblock.phtml 模版内容如下:

$helper = $this->helper('ThankIT\SocialLogin\Helper\Data');
if($helper->hasButtons()) : ?>
    // ... 省略内容
    <?php echo $block->getChildHtml('thankit_login_buttons'); ?>
<?php endif; ?>

注意此处$block->getChildHtml('thankit_login_buttons'); 我们调用了 block 的 getChildHtml 方法,该方法来自 class Magento\Framework\View\Element\AbstractBlock ,他将取他的 child block ,并调用其 toHtml 方法。

所以我们的 block 可以有序组织起来,形成嵌套的结构。

getChildHtml() 如果不给参数,则 render all child blocks 。

controller 中直接创建 block

我们在 ThankIT_HelloWorld 模块的基础上,创建以下 controller

<?php
namespace ThankIT\HelloWorld\Controller\Create;

class Block extends \Magento\Framework\App\Action\Action
{

    protected $resultPageFactory;

    /**
     * Constructor
     *
     * @param \Magento\Framework\App\Action\Context  $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory
    ) {
        $this->resultPageFactory = $resultPageFactory;
        parent::__construct($context);
    }

    /**
     * Execute view action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $resultPage = $this->resultPageFactory->create();
        // var_dump(get_class($resultPage->getConfig()->getTitle()));
        $resultPage->getConfig()->getTitle()->set(__('create block directly and fpc'));

        $block = $resultPage->getLayout()
            ->createBlock('ThankIT\HelloWorld\Block\Index\Index')
            ->setTemplate('ThankIT_HelloWorld::index/index.phtml')
            ->toHtml();
        $this->getResponse()->setBody($block);
    }
}

那么我们会得到一些字符串,连 html 结构都没有。此处仅仅为了说明是如何调用 toHtml 来得到 html 片段的。

关于 Magento 2 Controller and FPC

layout xml 要解决的问题

layout xml 要解决的是让主题开发人员也可以控制 HTML 的输出。其实就是又一层抽象,让主题开发人员不需要去改 php 。

博主个人认为,layout xml 带来的好处是他的分散性,可以很方便的进行扩展、更改、维护。如果我们要在 controller 中控制 block 的输出,那么我们都要去改 controller ,这就很难维护了。

Magento 2 layout 文件类型

参考 Magento 2 layout 文件类型

Magento 2 layout 使用

关于指令:
Layout instruction 之 argument 和 action

后台的使用
Using a Layout Update

获得 layout 的工具

调试工具:如何得到页面的布局文件

可进一步挖掘,获得想要的 layout 文件。

参考文档

《No Frills Magento Layout》 by Alan Storm 2011

发表评论

电子邮件地址不会被公开。 必填项已用*标注