如何使用包装器将 CSS 文件应用于我的 Catalyst webapp 中的特定模板

How can I apply CSS file to specific template in my Catalyst webapp using a wrapper

我不太明白包装器是如何工作的。我了解催化剂教程的示例,但我不知道如何为特定模板应用特定 CSS 文件。 我是否应该在 wrapper.tt 中使用 [% IF %] 语句以便 select 特定模板?我是否调用带有存储的 CSS 文件,就像我对控制器中的模板所做的那样?

一些示例或提示会很棒,谢谢

您当然可以将 CSS 文件分配给控制器中的存储变量。

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.

一个更灵活但也更复杂的解决方案是在您的视图中编写一个方法,该方法可以作为 TT vmethod 公开给模板工具包,并使用它添加 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 没有 private 或 public 的概念,但这是告诉其他开发人员不要乱用这个的约定。

现在建议向视图添加第二种方法来读取列表并 return 它。这会将文件列表如何存储的实现细节与模板完全分离。您可以完全更改它而无需触摸模板文件。

如果你有公开的方法,那么确保每个文件只包含一次会很聪明,例如使用 List::Util::uniq,或使用散列并访问 key 而不是获取数组。

我最初将此方法用于 javascript 个文件而不是 CSS。对于您应用程序中的 CSS,我实际上认为将所有样式压缩到一个文件中并缩小它会更聪明。你的用户无论如何都会下载其中的大部分,所以为什么要加载多个文件并使每个初始页面加载速度慢一点,并炸毁他们的缓存,如果你可以让第一个页面加载时间稍微长一点的话然后从缓存中读取所有内容?