有人问我如何使用headLink()
、headScript()
和其他占位符助手的一些示例,所以我想我应该尝试一下那今天。
首先,让我们看看这些助手的作用。每个都是占位符的具体实例。在ZendFramework中,占位符有多种用途:
- 文档类型感知
- 聚合内容的聚合和格式化
- 捕获内容
- 视图脚本和布局脚本之间的内容持久化
让我们详细看看这些。
文档类型提示
HTML规范鼓励您在HTML文档中使用DocType声明—而XHTML实际上需要一个。简而言之,DocType有助于告诉您的浏览器什么被认为是有效的语法,并提供一些关于它应该如何呈现的提示。
现在,如果您像我一样,回想起来会很痛苦;语法有点神秘,很长,而且我不想经常输入。幸运的是,新的doctype()
帮助程序允许您使用诸如XHTML1_TRANSITIONAL
或HTML4_STRICT
之类的助记符来调用适当的文档类型:
<?= $this->doctype('XHTML1_TRANSITIONAL') ?>
但是,文档类型不仅仅是对浏览器的提示;这是您需要遵守的合同。如果您选择特定的文档类型,则表示您同意编写遵循其规范的标记。
doctype()
助手实际上在许多占位符助手(以及form*()
助手)内部使用,以确保它们生成的标记——如果any—遵循给定的文档类型。但是,要使其工作,您需要尽早指定您的文档类型。我建议在yourbootstrap或在发出任何输出之前运行的插件中执行此操作;通常,我会从ViewRenderer
中拉取视图,以便这样做:
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer'); $viewRenderer->initView(); $viewRenderer->view->doctype('XHTML1_TRANSITIONAL');
由于这设置了文档类型助手的状态,您随后可以在布局脚本中简单地回显文档类型助手的返回值:
<?= $this->doctype() ?>
内容聚合
占位符跨视图实例聚合和存储内容。通过聚合,我的意思是它们将提供的数据存储在ArrayObject
中,允许您收集相关数据以供以后显示。由于占位符实现了__toString()
,并且可以是集合,我们添加了访问器以允许您设置任意文本来为集合中的项目添加前缀、追加和分隔。各种具体的占位符——主要是head*()
助手——利用这个特殊的功能,将每个条目作为一个单独的项目存储在集合中,然后在调用渲染时装饰它们。
此外,每个具体实例都包含一些自定义逻辑。对于headLink()
和headScript
帮助程序,我们执行检查以确保在指定文件时忽略重复条目。为什么这是个好主意?好吧,由于您可以_forward()
执行其他操作,甚至可以调用action()
viewhelper,因此您可能有多个视图脚本加载相同的样式表或javascript;我们帮助防范此类情况。
举个例子:
<? // /foo/bar view script: ?> <? $this->headLink()->appendStylesheet('/css/foo.css'); $this->headScript()->appendFile('/js/foo.js'); echo $this->action('baz', 'foo'); ?> <? // /foo/baz view script; ?> <? $this->headLink()->appendStylesheet('/css/foo.css'); $this->headScript()->appendFile('/js/foo.js'); ?> FOO BAZ!
这当然是一个人为的例子,但它很好地说明了问题:如果在创建相同内容的过程中呈现了两个视图脚本,那么你的占位符中就有可能出现重复的内容。但是,在这种情况下,不会出现重复内容,因为助手会在添加重复条目时检测到它们,并跳过它们。
捕获内容
占位符聚合内容的一种方式是捕获内容。基本占位符类定义了captureStart()
和captureEnd()
方法,允许您在视图脚本中创建内容,然后捕获这些内容供以后使用。
这对headScript()
帮助程序特别有用,因为它允许您直接在视图中创建将在HTMLhead中执行的javascript(或者,如果您使用inlineScript()
)helper,你可以让它在文档的末尾执行,这是Y!Slow推荐的)。headStyle()
助手也是如此;您可以定义自定义样式表以直接包含在您的文档中,直接包含在需要它们的视图中。
例如,Dojo附带了一些自定义样式表以呈现其各种小部件,并且还具有动态加载自定义类和小部件的能力。假设我们想在我们的页面中显示一个DojoComboBox:我们需要几个样式表,以及一些Dojoresources:
首先,让我们来处理样式表:
<? $this->headStyle()->captureStart() ?> @import \"/js/dijit/themes/tundra/tundra.css\"; @import \"/js/dojo/resources/dojo.css\"; <? $this->headStyle()->captureEnd() ?>
这些现在聚合在我们的headStyle()
视图助手中,我们可以稍后渲染它们;它们不会像在viewscript中那样内联显示在页面中。
现在,让我们来处理JavaScript。我们需要将主dojo.js
文件作为脚本加载,然后创建一个内联脚本来加载我们的各种小部件。Dojo经常使用它自己的自定义HTML属性,而head*()
助手通常不喜欢这个(他们喜欢坚持规范中定义的那些属性),所以我们需要告诉助手这没关系,这样Dojo就会在页面加载完成时解析页面(用适当的、请求的功能装饰我们的小部件)。
<? $this->headScript() ->setAllowArbitraryAttributes(true) ->appendFile('/js/dojo/dojo.js', 'text/javascript', array('djConfig' => 'parseOnLoad: true')) ->captureStart() ?> djConfig.usePlainJson=true; dojo.require(\"dojo.parser\"); dojo.require(\"dojox.data.QueryReadStore\"); dojo.require(\"dijit.form.ComboBox\"); <? $this->headScript()->captureEnd() ?>
这样做有什么好处?它允许您将与特定视图脚本相关的JS和CSS功能保留在手头那个视图脚本中—您将所有内容都放在一个地方。如果您需要更改加载的JS或CSS,或者修改您要使用的内联JS,您可以在它适用的其余内容中找到它。
放在一起:布局
我在这个叙述中一直在谈论“当你稍后渲染它时”。“稍后”是指您的布局脚本。我不打算在这里讨论如何初始化或定义布局,因为它已在其他地方介绍过。然而,让我们看看如何将我们的文档类型和head助手引入我们的布局:
<?= $this->doctype() ?> <html> <head> <? // headTitle() is another concrete placeholder ?> <?= $this->headLink() ?> <?= $this->headStyle() ?> <?= $this->headScript() ?> </head> ...
当然,您可能希望在其中放置更多内容—如果您有在每个页面上加载的样式表或脚本,您可能希望在布局中静态定义它们……除了调用占位符助手。但是添加占位符帮助程序会给您带来一些明确的好处:增加代码分离、更易于维护的代码(因为特定于视图的CSS和JS与视图保持)、更简单的布局逻辑以及能力以防止包含重复文件。
所有这些功能现在都是ZendFramework1.5.0的标准;如果您还没有尝试过,请立即下载。
注意:我的同事RalphSchindler—Zend_Layout
的原始提案作者和各种占位符助手的重要贡献者—明天将举办一个关于Zend_Layout和Zend_View的网络研讨会,2008年3月18日;如果您对此主题感兴趣,您应该检查一下。
更新:修复了布局文章的链接。