PHP的View层设计思路(一)
一个页面,该怎样组织才最合理? 首先就XHTML页面来说,都是由一个个的框组成的。有些框只在某个特定的页面有,也有些框是在不同的页面间共享的。最后,有一个大框,把所有的小框包围起来,这个大框就是标签。再加上段里的一些声明、CSS链接和JS链接,一个页面就形成了。 每个框在包含它的容器框中都需要定位,如自然定位,相对定位,绝对定位,浮动,等等。同时每个框也需要有自身的修饰,如宽
一个页面,该怎样组织才最合理?
首先就XHTML页面来说,都是由一个个的框组成的。有些框只在某个特定的页面有,
也有些框是在不同的页面间共享的。最后,有一个大框,把所有的小框包围起来,这个
大框就是<body></body>标签。再加上<head></head>段里的一些声明、CSS链接和JS链
接,一个页面就形成了。
每个框在包含它的容器框中都需要定位,如自然定位,相对定位,绝对定位,浮
动,等等。同时每个框也需要有自身的修饰,如宽度、高度、背景、字体等等。在这种
模型中,CSS属性实际上已经被区分成了互相分离的两部分:定位和自身的修饰。这实际
上是组合模式(Composite Pattern)的一种实现,UML图为:
很多View层设计方案都没有结合CSS一起讨论。然而如果采用上述方案,那么CSS就
应该是跟每个Block对象一一对应的。比如下面这个页面Block组织:
<body id="main">
<div id="container_one">
<div id="content_one">hello</div>
</div>
<div id="container_two">
<div id="content_two">world</div>
</div>
</body>
就需要main、container_one、content_one、container_two、content_two共五个CSS
文件(这里暂时先不考虑CSS文件对Web服务器性能的影响)。为什么要分开成五个CSS
文件?这是因为除<body>外的其它Block是需要在不同的<body>间复用的。要复用就必
然要松散耦合,所以每个实现上的Leaf Block(注意这是实现上的,不是UML图中的,
因为实现中一个Container Block也可以被当成一个Leaf Block使用,比如你可以把
container_two和其下的content_two合并起来当成一个整体,所谓的对象组合)都需要
一个单独的模板文件和一个单独的CSS。再举JS里的对象动态绑定做例子,就很容易理
解这种绑定。文件组织看起来大致如下,注意我没有区分各文件的逻辑层次,在现实框
架中肯定需要按照逻辑划分到不同的模块的,我只是给个例子说明下思路:
template文件:
main.container
container_one.container
container_two.container
content_one.leaf
content_two.leaf
css文件:
main.css
container_one.css
container_two.css
content_one.css
content_two.css
如此一来,只需要设计一个View类,让它依此规则渲染对应的模板即可。下一篇
文章就给出该View类的一个样例实现。
<2007.07.25注:>附样例代码:
class view {
public function __construct($layout) {
$this->layout = $layout;
$this->layout_target = dirname(self::$target) . '/' . $this->layout;
}
public function set_title($title) {
$this->title = $title;
}
public function set_keywords($keywords) {
$this->keywords = $keywords;
}
public function set($key, $value) {
$this->vars[$key] = $value;
}
public function render($_block_token, $_block_name = '') {
if ($_block_name === '') {
$_block_name = $_block_token;
}
$_folder = $this->layout_target;
$_go_upper_time = 3;
extract($this->vars, EXTR_SKIP);
ob_start();
for ($_i = 0; $_i < $_go_upper_time; ++$_i) {
$_block_file = self::$block_root . '/' . $_folder . '/' . $_block_name . '.tpl';
if (!is_readable($_block_file)) {
$_folder = dirname($_folder);
} else {
require $_block_file;
$this->csses[$_block_token] = $_folder . '/' . $_block_name . '.css';
break;
}
}
if ($_folder === '.') {
$_block_file = self::$block_root . '/' . $_block_name . '.tpl';
if (!is_readable($_block_file)) {
hc_api_error("Cannot find block file '{$_block_name}' for block token '{$_block_token}'");
}
require $_block_file;
$this->csses[$_block_token] = $_block_name . '.css';
}
$this->blocks[$_block_token] = ob_get_clean();
$this->vars = array();
}
public function show() {
$blocks = $this->blocks;
ob_start();
require self::$layout_root . '/' . $this->layout_target . '.lyt';
ob_end_flush();
}
private function render_head() {
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "/n";
echo '<html xmlns="http://www.w3.org/1999/xhtml">' . "/n";
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . "/n";
if ($this->keywords === '') {
$keywords = config::get('system.keywords');
echo '<meta name="keywords" content="' . $keywords . '" />' . "/n";
} else {
echo '<meta name="keywords" content="' . $this->keywords . '" />' . "/n";
}
echo '<title>' . $this->title . '</title>' . "/n";
echo '<link rel="stylesheet" href="css/css.css" type="text/css" media="all" />' . "/n";
echo '<link rel="stylesheet" href="css/layout/' . $this->layout_target . '.css" type="text/css" media="all" />' . "/n";
foreach ($this->csses as $css) {
echo '<link rel="stylesheet" href="css/block/' . $css . '" type="text/css" media="all" />' . "/n";
}
echo '<script type="text/javascript" src="js/jquery.js"></script>' . "/n";
}
private $layout = '';
private $layout_target = '';
private $title = '';
private $keywords = '';
private $vars = array();
private $blocks = array();
private $csses = array();
public static function set_target($target) {
self::$target = $target;
}
public static function set_layout_root($layout_root) {
self::$layout_root = $layout_root;
}
public static function set_block_root($block_root) {
self::$block_root = $block_root;
}
private static $target = '';
private static $layout_root = '';
private static $block_root = '';
}
一些初始化代码暂略(这部分代码是我目前应用中抽取出来的,所以不能直接使用),简单用例代码为:
$view = new view('index'); // 指定layout为index布局模板
$view->set_title('标题');
$view->set('name', 'diogin'); //指定一个变量
$view->render('header'); // 嵌入header块
$view->render('navigator'); // 嵌入navigator块
$view->render('content'); // 嵌入content块
$view->render('footer'); // 嵌入footer块
$view->show(); // 渲染出整个页面
以上只是一个思路,供大家参考,呵呵。
更多推荐
所有评论(0)