我正在使用 CakePHP 3.9
我正在尝试在我的视图单元格内设置 css / 脚本依赖块。
我希望将其提取到布局的头部内,但它不起作用。如果我想让它工作,我必须在调用单元格之前/之后在视图内设置 css 依赖项。
有什么方法可以在 View Cell 内设置 css 依赖关系吗?
我的看法:
<?= $this->cell('Post::post_input'); ?>
....
我的查看单元格:
<?php echo $this->Html->css(['element/post-input'], ['block' => true]); ?>
<div class="post-input">...</div>
我的布局:
<html>
<head>
...
<?php
echo $this->fetch('css');
echo $this->fetch('script');
?>
...
</head>
<body>
<?php echo $this->fetch('content'); ?>
</body>
</html>
它不起作用,因为单元格是一个使用单独视图实例的封闭环境,因此您在其模板中定义的所有块都将驻留在其内部视图中。
来自文档:
单元格模板具有独立的范围,它不与用于呈现当前控制器操作或其他单元格的模板和布局的视图实例共享相同的视图实例。因此,他们不知道在操作的模板/布局中进行的任何帮助程序调用或设置的块,反之亦然。
如果您不想在使用单元格时手动添加 CSS 块,那么我建议您构建一个自定义助手,它可以生成(甚至直接回显)单元格并添加块,以及其他内容这行:
<?php
// in src/View/Helper/PostHelper.php
namespace App\View\Helper;
use Cake\View\Helper;
/**
* @property \Cake\View\Helper\HtmlHelper $Html
*/
class PostHelper extends Helper
{
protected $helpers = [
'Html'
];
protected $wasPostInputCssAdded = false;
public function postInput()
{
if (!$this->wasPostInputCssAdded) {
$this->wasPostInputCssAdded = true;
$this->Html->css(['element/post-input'], ['block' => true]);
}
return $this->_View->cell('Post::post_input');
}
}
然后,以下内容将添加块并回显单元格:
<?= $this->Post->postInput() ?>
不需要重写模板的另一个选项是创建一个使用
Cell
类的自定义 CellView
类。然后,视图类将单元格内容包装在布局中,该布局可以像您通常在 Cake 视图/布局模板中期望的那样显示块。
<?php
declare(strict_types=1);
namespace App\View;
use Cake\View\Cell as BaseCell;
use Cake\View\View;
class Cell extends BaseCell
{
/**
* @inheritDoc
*/
public function createView(?string $viewClass = null): View
{
// use custom CellView to for Cells
return parent::createView(CellView::class);
}
}
然后是CellView:
<?php
declare(strict_types=1);
namespace App\View;
class CellView extends AppView
{
/**
* @inheritDoc
*/
public function render(?string $template = null, $layout = null): string
{
$cellContents = parent::render($template, $layout);
// wrap cell contents in "cell" layout
return $this->renderLayout($cellContents, 'cell');
}
}
既然所有单元格都使用布局,剩下的就是创建一个单元格专用的基本布局:
/templates/layout/cell.php(CakePHP 3:/src/Template/Layout/cell.ctp)
<?php
/**
* @var CellView $this
*/
use App\View\CellView;
echo $this->fetch('styles');
echo $this->fetch('content');
echo $this->fetch('scripts');
完成此初始工作后,所有
App\View\Cell
将使用“单元格”布局。我发现从长远来看,如果您使用不同的块或带有块的 postLink
,这会更直观。
注意:此处的代码适用于 CakePHP 4,但要使其兼容 CakePHP 3,您需要做的就是匹配方法签名
我刚刚遇到了同样的问题,但我试图将内容添加到主布局的 scriptBottom 块中,有时是从单元格内添加内容。
因为每个 Cell 都有自己的 View 和 Helper 实例,所以我们无法访问所需块所在的主 View,但是我们确实可以访问主 View,因为它是第一个实例化的,因此是第一个
before.render
我们的助手收到的事件是针对主视图的。因此,我们可以将其存储在静态变量中,然后根据需要在从单元格内调用的帮助程序中将内容附加到该静态变量中。
<?php
declare(strict_types=1);
namespace App\View\Helper;
use App\View\AppView;
use Cake\Core\Exception\Exception;
use Cake\Event\Event;
use Cake\Routing\Router;
use Cake\View\Helper;
use Cake\View\Helper\FormHelper;
use Cake\View\Helper\HtmlHelper;
use function assert;
use function func_get_args;
use function uniqid;
/**
* @property HtmlHelper $Html
* @property FormHelper $Form
*/
final class SecureDeleteHelper extends Helper
{
private static AppView $mainView;
public function beforeRender(Event $event): void
{
// Each cell has its own view, but the first one created is the main
// one that we want to add scripts to, so we'll store it here…
if (isset(self::$mainView)) {
return;
}
$view = $event->getSubject();
assert($view instanceof AppView);
self::$mainView = $view;
}
/**
* @throws Exception if $url is not valid.
*/
public function doSomethingThatRequiresScriptTBeIncluded(): void
{
// …
self::$mainView->helpers()->Html->script('my-script', ['block' => 'scrptBottom']);
}
}
希望此信息对某人有用。