一个页面,该怎样组织才最合理?
    首先就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(); // 渲染出整个页面

以上只是一个思路,供大家参考,呵呵。
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐