我不太了解包装器的工作原理。我了解了催化剂教程的示例,但是我不知道如何为特定模板应用特定的CSS文件。 我应该在wrapper.tt中使用[%IF%]语句来选择特定模板吗?是否像存储控制器中的模板一样,使用隐藏方式调用CSS文件?
一些示例或提示会很好,谢谢
答案 0 :(得分:3)
您当然可以将CSS文件分配给控制器中的stash变量。
sub frobnicate :Local {
my ($self, $c) = @_;
# ...
# this would probably be implied, i.e. in a properly configured Catalyst
# you don't have to actually set this, it will just load the right thing
$c->stash->{template} = 'frobnicate';
# this one is for loading the right CSS
$c->stash->{css_file} = 'frobnication.css';
}
然后在您的TT包装器中(可能用[% IF css_file %]...[% END %]
包装):
<head>
<link rel="stylesheet" href="[% css_file %]">
</head>
这会起作用,但这不是一个好习惯,因为您要破坏separation of concerns。页面外观与应用程序控制器无关。
您也可以在需要时仅加载每个CSS文件,但这也是一个坏习惯,因为这会影响页面加载时间和加载顺序。通常,将CSS放在<head>
的顶部,将大多数javascript文件放在页面的末尾,</body>
的前面,以便在浏览器关闭并获取并运行之前已经呈现了内容。 javascript。
一种更灵活但也更复杂的解决方案是在您的View中编写一个可以作为TT方法公开给Template Toolkit的方法,并在需要时使用它将CSS文件添加到存储中。您可以使用expose_methods
来做到这一点。
package MyApp::View::TT; # or whatever you have called this
# ...
expose_methods => [qw/add_css_file/],
# ...
sub add_css_file {
my ( $c, $self, $css_file ) = @_;
push @{ $c->stash->{_css_files} }, $css_file;
return;
}
现在,您可以在模板文件中使用它。您可以在每个文件的顶部或底部都有一个块,以将CSS文件添加到应该在逻辑上所属的位置加载的文件列表中。
<h1>Order Confirmation</h1>
[% add_css_file('confirmation.css') %]
在包装器中,您可以迭代该文件列表并加载每个文件。如您所见,这种方法具有允许您拥有多个文件的优点。
<head>
[% FOREACH file IN _css_files %]
<link rel="stylesheet" href="[% file %]">
[% END %]
</head>
它们将在存储区中可用,因为包装器是在页面内部之后渲染的,但是您不能直接从模板中进行处理,因为您不能在Template Toolkit中更改存储区。如果没有文件,则不会执行任何操作,因为循环没有任何要迭代的地方。
请注意我如何调用隐藏密钥_css_file
。下划线_
表示它是一个私有变量。 Perl没有私有或公共的概念,但这是一个约定,告诉其他开发者不要对此感到困惑。
现在建议将另一个方法添加到View中以读取列表并返回它。这将使模板完全存储文件列表的实现细节脱钩。您可以完全更改它,而无需完全触摸模板文件。
如果您有该公开的方法,例如确保每个文件仅被包含一次,例如List::Util::uniq
,或使用散列并访问key
而不是使用数组。
我最初将这种方法用于javascript文件而不是CSS。对于您的应用程序中的CSS,我实际上认为将所有样式压缩到一个文件中并将其最小化会更明智。您的用户无论如何都会下载其中的大多数文件,因此,如果您只可以将第一页的加载时间稍长一点,那么为什么要花一些时间来加载多个文件并使每个初始页面的加载速度变慢,并消耗其缓存呢?然后从缓存中读取所有内容?