Yii2添加到头()和尾体()中

Yii2添加到头()和尾体()中,yii2,Yii2,在开发一个可以有多个前端主题的站点时,我正在寻找一种方法,允许后端用户手动将代码注入头部和身体。两个用例如下所示: <?php $this->endBody() ?> <?= $this->params['theme_include_body_end'] ?> 案例1-风格 在后端,用户选择一个主题 用户喜欢的主题,但想使链接不同的颜色 用户可以将自定义代码设置为在标记末尾执行,而不是复制和修改主题 案例2-脚本 用户希望将自定义JavaScript添加到文

在开发一个可以有多个前端主题的站点时,我正在寻找一种方法,允许后端用户手动将代码注入头部和身体。两个用例如下所示:

<?php $this->endBody() ?>
<?= $this->params['theme_include_body_end'] ?>
案例1-风格

  • 在后端,用户选择一个主题
  • 用户喜欢的主题,但想使链接不同的颜色
  • 用户可以将自定义代码设置为在
    标记末尾执行,而不是复制和修改主题
  • 案例2-脚本

  • 用户希望将自定义JavaScript添加到文档末尾,但还需要一个额外的JavaScript库
  • 用户不必复制和修改主题,而是可以设置自定义代码,以便在标签处执行
  • 我知道这两种特定情况都可以(部分)通过使用
    registerCss
    registerJs
    来完成,但它们会自动将传递给它们的任何内容包装在
    标记中。我希望有一种方法可以直接将指示的内容直接注入
    head()
    endBody()
    方法。这背后的原因是,我不希望限制用户可以注入的内容(可能头部需要一个脚本标记)

    目前,我只是将要添加的代码存储在params中,然后手动将其包含在每个主题中,如下所示:

    <?php $this->endBody() ?>
    <?= $this->params['theme_include_body_end'] ?>
    
    
    

    这是不可取的,因为在创建主题时很容易忘记。我想找到一种方法,将我的param值自动附加到endBody()调用中,这样无论何时调用endBody(),都会包含我的代码(与head()调用相同)。

    您可以使用自己的视图组件来覆盖方法
    renderhadtml()
    renderBodyEndHtml()
    。在这些方法中,可以根据需要注入必要的代码:

    namespace common/components;
    
    class View extends \yii\web\View {
    
        /**
         * @var string Content that should be injected to end of `<head>` tag
         */
        public $injectToHead    = '';
    
        /**
         * @var string Content that should be injected to end of `<body>` tag
         */
        public $injectToBodyEnd = '';
    
        /**
         * @inheritdoc
         */
        protected function renderHeadHtml()
        {
            return parent::renderHeadHtml() . $this->injectToHead;
        }
    
        /**
         * @inheritdoc
         */
        protected function renderBodyEndHtml($ajaxMode)
        {
            return parent::renderBodyEndHtml(ajaxMode) . $this->injectToBodyEnd;
        }
    
    }
    
    控制器代码中的某个地方:

    \Yii::$app->view->injectToHead = '...';
    \Yii::$app->view->injectToBodyEnd = '...';
    

    Yii2已经通过使用在视图类中提供了此功能

    您需要两个简单的步骤:

    1-(在所需视图文件中):在任何给定视图中

    <?php $this->beginBlock('block1'); ?>
    
    ...content of block1...
    
    <?php $this->endBlock(); ?>
    
    ...
    
    <?php $this->beginBlock('block3'); ?>
    
    ...content of block3...
    
    <?php $this->endBlock(); ?>
    
    
    …block1的内容。。。
    ...
    …block3的内容。。。
    
    2-(在布局中):定义块名及其在布局页面中的位置

    ...
    
    <?php if (isset($this->blocks['block1'])): ?>
        <?= $this->blocks['block1'] ?>
    <?php else: ?>
        ... default content for block1 ...
    <?php endif; ?>
    
    ...
    
    <?php if (isset($this->blocks['block2'])): ?>
        <?= $this->blocks['block2'] ?>
    <?php else: ?>
        ... default content for block2 ...
    <?php endif; ?>
    
    ...
    
    <?php if (isset($this->blocks['block3'])): ?>
        <?= $this->blocks['block3'] ?>
    <?php else: ?>
        ... default content for block3 ...
    <?php endif; ?>
    ...
    
    。。。
    ... block1的默认内容。。。
    ...
    ... block2的默认内容。。。
    ...
    ... block3的默认内容。。。
    ...
    
    参考:Yii2指南


    我希望这能帮助别人。谢谢。

    根据您的用例,另一个可能更简单的选择是使用查看事件。您可以在页面的不同部分插入不同的项目。例如:

    Yii::$app->view->on(View::EVENT_END_BODY, function () {
        echo date('Y-m-d');
    });
    

    您可以在这里阅读更多内容:

    这是一个很好的开始,但当我尝试用我的模块实现它时,它崩溃了。因为有一个后端和前端模块,我不能在组件级别设置视图,否则它将应用于这两个模块。我需要在模块内设置视图类。如果这样做,则无法从控制器设置injectToHeadEnd属性。有没有想过在使用多个模块时调整此设置?我不理解您的问题:为什么不能设置?)您的控制器不在模块中?控制器在模块中,但配置文件适用于整个应用程序。我想我成功了。我必须在模块init()中设置视图类,如下所示:
    Yii::$app->components=['view'=>['class'=>'\common\components\view']
    然后,我可以按照您的指示设置注入的代码,但是,因为我在重写模块中的视图,我的IDE抱怨它是一个未定义的字段。虽然IDE认为它是未定义的,但它仍然有效。如果您不想全局设置组件,您可以使用
    \yii\base\controller::setView
    为必要的控制器定义自己的
    视图。此外,您可以创建自己的父控制器类并重写
    \yii\base\controller::getView
    方法(此方法默认返回
    yii::$app->view;
    )。非常好,谢谢!正是我需要的。感谢我喜欢此解决方案,因为endBody()引发此事件,因此它直接绑定到其中,不需要扩展任何类,也不需要布局是否实现某些参数或块解决方案。请注意,如果您在从视图调用的某个对象上使用它,则需要将调用放在事件注册器函数endBody()之前或者beginBody()等等,因为如果您将事件放置在此调用之后,它将已经触发