一个简单的PHP模板引擎

PHP早期开发中通常是PHP代码和HTML代码混写,这也使代码中充斥着数据库操作,逻辑处理等。当项目不大时,这样的代码还可以接受,但是随着项目不断扩大,我们就会发现同一个文件中同时存在前端逻辑和后端处理,当逻辑越来越复杂时,代码的可读性和可维护性都会变得非常差,以至于后来不得不进行大规模的代码重构。所以后来就出现了代码分层的思想,尽量拆分开前端代码和后端代码。

PHP模板引擎能解决这种混乱吗?当然可以。但是呢,即使你不用专门的模板引擎也可以写出逻辑清晰的代码,重点是要有分层的思想,有专门的脚本去进行数据获取,数据处理,逻辑处理等,在展示页面只进行尽可能简单的逻辑处理即可。既然这样,那还有使用PHP模板引擎的必要吗?毫无疑问当然有,因为模板引擎的功能不仅于此。

那接下来就说一下PHP模板引擎的主要作用:

1、它实现了一些自定义标签,用于展示层的简单逻辑处理,相较于不适用引擎的好处是代码看起来不像是PHP代码了,感觉上HTML代码和PHP代码完全分开了,但这只是假象,坏处是效率降低了,因为这样的页面需要专门的脚本解析后才能正确显示,解析的方法就是使用正则表达式替换,这明显降低了效率。到现在来看感觉PHP模板引擎有还不如没有呢,那为什么还要用它呢,重点是他的下一个功能。

2、文件缓存,这是模板引擎在生产环境中提高效率的非常好的手段。可以用在页面加载时所用数据量很大但不经常变或者不需要实时更新,即使延迟一会也无妨的页面。我个人感觉文件缓存是PHP模板引擎的最重要的部分。

接下来我们就写一个简易的模板引擎(最后有完整文件代码)

首先我们先要计划好我们的所需要的基础类,有Template类和Compile类。

在我们具体实现编译功能之前先搭好一个空的骨架,具体如下:

<?php

/**
* 模板引擎基础类
*/
class Template
{
    private $config = array(
        ‘suffix‘ => ‘.m‘,      // 设置模板文件的后缀
        ‘templateDir‘ => ‘template/‘,    // 设置模板所在的文件夹
        ‘compileDir‘ => ‘cache/‘,    // 设置编译后存放的目录
        ‘cache_html‘ => true,    // 是否需要编译成静态的HTML文件
        ‘suffix_cache‘ => ‘.html‘,    // 设置编译文件的后缀
        ‘cache_time‘ => 7200,    //  多长时间自动更新,单位秒
        ‘php_turn‘ => true,   // 是否支持原生PHP代码
        ‘cache_control‘ => ‘control.dat‘,
        ‘debug‘ => false,
    );
    private static $instance = null;
    private $value = array();   // 值栈
    private $compileTool;   // 编译器
    public $file;     // 模板文件名,不带路径
    public $debug = array();   // 调试信息
    private $controlData = array();
    public function __construct($config = array())
    {
        $this->debug[‘begin‘] = microtime(true);
        $this->config = $config + $this->config;
        if (! is_dir($this->config[‘templateDir‘])) {
            exit("模板目录不存在!");
        }
        if (! is_dir($this->config[‘compileDir‘])) {
            mkdir($this->config[‘compileDir‘], 0770);
        }
        $this->getPath();
        include ‘./Compile.php‘;
    }
    /**
    *获取绝对路径
    */
    public function getPath() {
        $this->config[‘templateDir‘] = strtr(realpath($this->config[‘templateDir‘]), ‘\\‘, ‘/‘).‘/‘;
        $this->config[‘compileDir‘] = strtr(realpath($this->config[‘compileDir‘]), ‘\\‘, ‘/‘).‘/‘;
    }
    /**
    *取得模板引擎的实例
    */
    public static function getInstance() {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    /* 设置模板引擎参数 */
    public function setConfig($key, $value = null) {
        if (is_array($key)) {
            $this->config = $key + $this->config;
        }else {
            $this->config[$key] = $value;
        }
    }
    /* 获取当前模板引擎配置,仅供调试使用 */
    public function getConfig($key = null) {
        if ($key) {
            return $this->config[$key];
        }else {
            return $this->config;
        }
    }
    /**
    *注入单个变量
    */
    public function assign($key, $value) {
        $this->value[$key] = $value;
    }
    /**
    *注入数组变量
    */
    public function assignArray($array) {
        if (is_array($array)) {
            foreach($array as $k => $v) {
                $this->value[$k] = $v;
            }
        }
    }
    /**
     * 获取模板文件完整路径
     */
    public function path() {
        return $this->config[‘templateDir‘].$this->file.$this->config[‘suffix‘];
    }
    /**
    *判断是否开启了缓存
    */
    public function needCache() {
        return $this->config[‘cache_html‘];
    }
    /**
    *显示模板
    */
    public function show($file) {

    }
}

?>

从上边的代码中我们能发现对于模板文件不存在和编译文件不存在处理方式不同,这也很容易理解,如果你连模板文件都没有有啥好编译的,但是你有模板文件没编译文件这也很正常,正常进行编译即可。

如上所示,我们首先想好了这个模板引擎需要什么配置,还有一些设置配置的方法和检查配置的方法等,而我们的核心方法show()还没有实现呢,先不着急,我们先去写编译类Compile,如下所示:

<?php

class Compile
{
    private $template;   // 待编译的文件
    private $content;   // 需要替换的文件
    private $comfile;   // 编译后的文件
    private $left = ‘{‘;   // 左定界符
    private $right = ‘}‘;   // 右定界符
    private $value = array();   // 值栈
    private $phpTurn;
    private $T_P = array();   // 匹配正则数组
    private $T_R = array();   // 替换数组
    public function __construct($template, $compileFile, $config) {
        $this->template = $template;
        $this->comfile = $compileFile;
        $this->content = file_get_contents($template);
    }
    public function compile() {
        $this->c_var();
        file_put_contents($this->comfile, $this->content);
    }
    public function c_var() {
        $this->content = preg_replace($this->T_P, $this->T_R, $this->content);
    }
    public function __set($name, $value) {
        $this->$name = $value;
    }
    public function __get($name) {
        return $this->$name;
    }
}

?>

从上面Compile类的构造函数我们可以看出,他需要模板文件路径,编译文件路径,和具体编译时的配置参数,但是在这这个配置参数吗,没有用到。之前说过模板引擎主要使用的正则表达式来进行匹配替换,将模板文件编译成能正确执行的PHP文件,这里使用数组存放正则匹配数组和替换数组来进行整体替换。

接下来我们就简单实现几个常用的标签,先看怎么替换简单变量:

// \x7f-\xff表示ASCII字符从127到255,其中\为转义,作用是匹配汉字
$this->T_P[] = "#\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}#";
$this->T_R[] = "<?php echo \$this->value[‘\\1‘]; ?>";

正如我们看到的,上边的那个是正则匹配,下边的是替换。但是我们没有给编译类的value变量赋值,那这个替换能找到正确的值吗?答案是能,因为他用的不是这个类的value用的是模板类的value,接下来一会会讲到。

然后我们在看看怎么实现foreach标签,这个很常用

$this->T_P[] = "#\{(loop|foreach)\s+\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\}#i";
$this->T_P[] = "#\{\/(loop|foreach)\}#";

$this->T_P[] = "#\{([k|v])\}#";

$this->T_R[] = "<?php foreach ((array)\$this->value[‘\\2‘] as \$k => \$v) { ?>";
$this->T_R[] = "<?php } ?>";

 $this->T_R[] = "<?php echo \$\\1?>";

这里用到的主要正则表达式的知识有:元组、反向引用等,这些只要稍微看一下正则表达式基础就能理解了。

我们再来一个if else标签:

$this->T_P[] = "#\{\/(loop|foreach|if)\}#";
$this->T_P[] = "#\{if (.*?)\}#";
$this->T_P[] = "#\{(else if|elseif) (.*?)\}#";
$this->T_P[] = "#\{else\}#";
$this->T_R[] = "<?php } ?>";
$this->T_R[] = "<?php if(\\1){ ?>";
$this->T_R[] = "<?php }elseif(\\2){ ?>";
$this->T_R[] = "<?php }else{ ?>";

我们将if的闭合标签和foreach的闭合标签放一块了。

现在我们已经能编译一些标签了我们就再转回模板类,现在我们想一想要怎么展示呢,这个才是我们的根本目的。写代码之前先理一下思路:

1、判断是否开启了缓存,如果是进行第二步,否则直接进行编译输出。

2、判断是否需要更新缓存(判断方式主要是缓存时间和编译文件和模板文件的修改时间的关系),如果是就进行第三步,否则直接读取缓存文件输出。

3、重新编译模板文件,并将编译后的PHP文件输出保存到静态缓存文件中。

简单来说就是上边的那三个步骤,具体实现如下:

/**
    *是否需要重新生成静态文件
    */
    public function reCache($file) {
        $flag = true;
        $cacheFile = $this->config[‘compileDir‘].md5($file).$this->config[‘suffix_cache‘];
        if ($this->config[‘cache_html‘] === true) {
            $timeFlag = (time() - @filemtime($cacheFile)) < $this->config[‘cache_time‘] ? true : false;
            if (is_file($cacheFile) && filesize($cacheFile) > 1 && $timeFlag && filemtime($compileFile) >= filemtime($this->path())) {
                $flag = false;
            }else {
                $flag = true;
            }
        }
        return $flag;
    }
    /**
    *显示模板
    */
    public function show($file) {
        $this->file = $file;
        if (! is_file($this->path())) {
            exit(‘找不到对应的模板!‘);
        }
        $compileFile = $this->config[‘compileDir‘].md5($file).‘.php‘;
        $cacheFile = $this->config[‘compileDir‘].md5($file).$this->config[‘suffix_cache‘];
        extract($this->value, EXTR_OVERWRITE);
        if ($this->config[‘cache_html‘] === true) {
            if ($this->reCache($file) === true) {
                $this->debug[‘cached‘] = ‘false‘;
                $this->compileTool = new Compile($this->path(), $compileFile, $this->config);
                if ($this->needCache()) {ob_start();}
                if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) {
                    $this->compileTool->value = $this->value;
                    $this->compileTool->compile();
                    include $compileFile;
                }else {
                    include $compileFile;
                }
                if ($this->needCache()) {
                    $message = ob_get_contents();
                    file_put_contents($cacheFile, $message);
                }
            }else {
                readfile($cacheFile);
                $this->debug[‘cached‘] = ‘true‘;
            }
        }else {
            if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) {
                $this->compileTool = new Compile($this->path(), $compileFile, $this->config);
                $this->compileTool->value = $this->value;
                $this->compileTool->compile();
                include $compileFile;
            }else {
                include $compileFile;
            }
        }
        $this->debug[‘spend‘] = microtime(true) - $this->debug[‘begin‘];
        $this->debug[‘count‘] = count($this->value);
    }

上边的代码基本是按照上述的三个步骤来进行的,好好看一下不难理解。

接下来就是模板文件了:

<html>
{$data},{$person}
<br/>列表一:<br/>
<ul>
{foreach $arr1}
<li>$v</li>
{/foreach}
</ul>
<br/>列表二:<br/>
<ul>
{loop $arr2}
<li>$v</li>
{/loop}
</ul>
{if $a == ‘1‘}a等于1
{elseif $a == ‘2‘}a等于2
{else}a不等于1也不等于2
{/if}
</html>

这个模板文件主要测试了之前我们事先的模板标签。

下面写一个测试文件:

<?php

include_once ‘./Template.php‘;
$tpl = new Template();
$tpl->assign(‘data‘, ‘hello‘);
$tpl->assign(‘person‘, ‘world!‘);
$tpl->assign(‘arr1‘, array(‘123‘,‘456‘,‘789‘));
$tpl->assign(‘arr2‘, array(‘abc‘, ‘def‘, ‘ghi‘));
$tpl->assign(‘a‘, ‘2‘);
$tpl->show(‘member‘);

?>

这就是一个简单的测试我们的模板引擎能不能用的测试用例。

下面我们看看完整代码吧:

<?php

/**
* 模板引擎基础类
*/
class Template
{
    private $config = array(
        ‘suffix‘ => ‘.m‘,      // 设置模板文件的后缀
        ‘templateDir‘ => ‘template/‘,    // 设置模板所在的文件夹
        ‘compileDir‘ => ‘cache/‘,    // 设置编译后存放的目录
        ‘cache_html‘ => true,    // 是否需要编译成静态的HTML文件
        ‘suffix_cache‘ => ‘.html‘,    // 设置编译文件的后缀
        ‘cache_time‘ => 7200,    //  多长时间自动更新,单位秒
        ‘php_turn‘ => true,   // 是否支持原生PHP代码
        ‘cache_control‘ => ‘control.dat‘,
        ‘debug‘ => false,
    );
    private static $instance = null;
    private $value = array();   // 值栈
    private $compileTool;   // 编译器
    public $file;     // 模板文件名,不带路径
    public $debug = array();   // 调试信息
    private $controlData = array();
    public function __construct($config = array())
    {
        $this->debug[‘begin‘] = microtime(true);
        $this->config = $config + $this->config;
        if (! is_dir($this->config[‘templateDir‘])) {
            exit("模板目录不存在!");
        }
        if (! is_dir($this->config[‘compileDir‘])) {
            mkdir($this->config[‘compileDir‘], 0770);
        }
        $this->getPath();
        include ‘./Compile.php‘;
    }
    /**
    *获取绝对路径
    */
    public function getPath() {
        $this->config[‘templateDir‘] = strtr(realpath($this->config[‘templateDir‘]), ‘\\‘, ‘/‘).‘/‘;
        $this->config[‘compileDir‘] = strtr(realpath($this->config[‘compileDir‘]), ‘\\‘, ‘/‘).‘/‘;
    }
    /**
    *取得模板引擎的实例
    */
    public static function getInstance() {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    /* 设置模板引擎参数 */
    public function setConfig($key, $value = null) {
        if (is_array($key)) {
            $this->config = $key + $this->config;
        }else {
            $this->config[$key] = $value;
        }
    }
    /* 获取当前模板引擎配置,仅供调试使用 */
    public function getConfig($key = null) {
        if ($key) {
            return $this->config[$key];
        }else {
            return $this->config;
        }
    }
    /**
    *注入单个变量
    */
    public function assign($key, $value) {
        $this->value[$key] = $value;
    }
    /**
    *注入数组变量
    */
    public function assignArray($array) {
        if (is_array($array)) {
            foreach($array as $k => $v) {
                $this->value[$k] = $v;
            }
        }
    }
    /**
     * 获取模板文件完整路径
     */
    public function path() {
        return $this->config[‘templateDir‘].$this->file.$this->config[‘suffix‘];
    }
    /**
    *判断是否开启了缓存
    */
    public function needCache() {
        return $this->config[‘cache_html‘];
    }
    /**
    *是否需要重新生成静态文件
    */
    public function reCache($file) {
        $flag = true;
        $cacheFile = $this->config[‘compileDir‘].md5($file).$this->config[‘suffix_cache‘];
        if ($this->config[‘cache_html‘] === true) {
            $timeFlag = (time() - @filemtime($cacheFile)) < $this->config[‘cache_time‘] ? true : false;
            if (is_file($cacheFile) && filesize($cacheFile) > 1 && $timeFlag && filemtime($compileFile) >= filemtime($this->path())) {
                $flag = false;
            }else {
                $flag = true;
            }
        }
        return $flag;
    }
    /**
    *显示模板
    */
    public function show($file) {
        $this->file = $file;
        if (! is_file($this->path())) {
            exit(‘找不到对应的模板!‘);
        }
        $compileFile = $this->config[‘compileDir‘].md5($file).‘.php‘;
        $cacheFile = $this->config[‘compileDir‘].md5($file).$this->config[‘suffix_cache‘];
        extract($this->value, EXTR_OVERWRITE);
        if ($this->config[‘cache_html‘] === true) { // 开启缓存的处理逻辑
            if ($this->reCache($file) === true) { // 需要更新缓存的处理逻辑
                $this->debug[‘cached‘] = ‘false‘;
                $this->compileTool = new Compile($this->path(), $compileFile, $this->config);
                if ($this->needCache()) {ob_start();} // 打开输出控制缓冲
                if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) {
                    $this->compileTool->value = $this->value;
                    $this->compileTool->compile();
                    include $compileFile;
                }else {
                    include $compileFile;
                }
                if ($this->needCache()) {
                    $message = ob_get_contents(); // 获取输出缓冲中的内容(在include编译文件的时候就有输出了)
                    file_put_contents($cacheFile, $message);
                }
            }else {
                readfile($cacheFile);
                $this->debug[‘cached‘] = ‘true‘;
            }
        }else {
            if (! is_file($compileFile) || filemtime($compileFile) < filemtime($this->path())) {
                $this->compileTool = new Compile($this->path(), $compileFile, $this->config);
                $this->compileTool->value = $this->value;
                $this->compileTool->compile();
                include $compileFile;
            }else {
                include $compileFile;
            }
        }
        $this->debug[‘spend‘] = microtime(true) - $this->debug[‘begin‘];
        $this->debug[‘count‘] = count($this->value);
        //$this->debug_info();
    }
    public function debug_info() {
        if ($this->config[‘debug‘] === true) {
            echo PHP_EOL, ‘---------debug info---------‘, PHP_EOL;
            echo "程序运行日期:", date("Y-m-d H:i:s"), PHP_EOL;
            echo "模板解析耗时:", $this->debug[‘spend‘], ‘秒‘, PHP_EOL;
            echo ‘模板包含标签数目:‘, $this->debug[‘count‘], PHP_EOL;
            echo ‘是否使用静态缓存:‘, $this->debug[‘cached‘], PHP_EOL;
            echo ‘模板引擎实例参数:‘, var_dump($this->getConfig());
        }
    }
    /**
    *清理缓存的HTML文件
    */
    public function clean($path = null) {
        if ($path === null) {
            $path = $this->config[‘compileDir‘];
            $path = glob($path.‘* ‘.$this->config[‘suffix_cache‘]);
        }else {
            $path = $this->config[‘compileDir‘].md5($path).$this->config[‘suffix_cache‘];
        }
        foreach((array)$path as $v) {
            unlink($v);
        }
    }
}

?>
<?php

class Compile
{
    private $template;   // 待编译的文件
    private $content;   // 需要替换的文件
    private $comfile;   // 编译后的文件
    private $left = ‘{‘;   // 左定界符
    private $right = ‘}‘;   // 右定界符
    private $value = array();   // 值栈
    private $phpTurn;
    private $T_P = array();   // 匹配正则数组
    private $T_R = array();   // 替换数组
    public function __construct($template, $compileFile, $config) {
        $this->template = $template;
        $this->comfile = $compileFile;
        $this->content = file_get_contents($template);
        if ($config[‘php_turn‘] === true) {
            $this->T_P[] = "#<\?(=|php|)(.+?)\?#is";
            $this->T_R[] = "&lt;?\1\2?&gt;";
        }
        // 变量匹配
        // \x7f-\xff表示ASCII字符从127到255,其中\为转义,作用是匹配汉字
        $this->T_P[] = "#\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}#";
        // foreach标签盘匹配
        $this->T_P[] = "#\{(loop|foreach)\s+\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\}#i";
        $this->T_P[] = "#\{\/(loop|foreach|if)\}#";
        $this->T_P[] = "#\{([k|v])\}#";
        // if else标签匹配
        $this->T_P[] = "#\{if (.*?)\}#";
        $this->T_P[] = "#\{(else if|elseif) (.*?)\}#";
        $this->T_P[] = "#\{else\}#";
        $this->T_P[] = "#\{(\#|\*)(.*?)(\#|\*)\}#";

        $this->T_R[] = "<?php echo \$this->value[‘\\1‘]; ?>";
        $this->T_R[] = "<?php foreach ((array)\$this->value[‘\\2‘] as \$k => \$v) { ?>";
        $this->T_R[] = "<?php } ?>";
        $this->T_R[] = "<?php echo \$\\1?>";
        $this->T_R[] = "<?php if(\\1){ ?>";
        $this->T_R[] = "<?php }elseif(\\2){ ?>";
        $this->T_R[] = "<?php }else{ ?>";
        $this->T_R[] = "";
    }
    public function compile() {
        $this->c_var();
        //$this->c_staticFile();
        file_put_contents($this->comfile, $this->content);
    }
    public function c_var() {
        $this->content = preg_replace($this->T_P, $this->T_R, $this->content);
    }
    /* 对引入的静态文件进行解析,应对浏览器缓存 */
    public function c_staticFile() {
        $this->content = preg_replace(‘#\{\!(.*?)\!\}#‘, ‘<script src=\1‘.‘?t=‘.time().‘></script>‘, $this->content);
    }
    public function __set($name, $value) {
        $this->$name = $value;
    }
    public function __get($name) {
        return $this->$name;
    }
}

?>

模板文件member.m代码:

<html>
{$data},{$person}
<br/>列表一:<br/>
<ul>
{foreach $arr1}
<li>$v</li>
{/foreach}
</ul>
<br/>列表二:<br/>
<ul>
{loop $arr2}
<li>$v</li>
{/loop}
</ul>
{if $a == ‘1‘}a等于1
{elseif $a == ‘2‘}a等于2
{else}a不等于1也不等于2
{/if}
</html>

测试用例:

<?php

include_once ‘./Template.php‘;
$tpl = new Template();
$tpl->assign(‘data‘, ‘hello‘);
$tpl->assign(‘person‘, ‘world!‘);
$tpl->assign(‘arr1‘, array(‘123‘,‘456‘,‘789‘));
$tpl->assign(‘arr2‘, array(‘abc‘, ‘def‘, ‘ghi‘));
$tpl->assign(‘a‘, ‘2‘);
$tpl->show(‘member‘);

?>

本文内容大部分来自于《PHP核心技术与最佳实践》的第六章。

原文地址:https://www.cnblogs.com/wp1996/p/9011892.html

时间: 2024-08-05 16:25:01

一个简单的PHP模板引擎的相关文章

一个简单的makefile模板

在Linux下编译工程,makefile是必不可少的工具,下面记录一个简单的makefile模板. 多个文件目录下的makefile写法推荐参考博文:http://www.cnblogs.com/Anker/p/3242207.html DIR_SRC = ./ DIR_BIN = ../bin PROGRAMNAME = program TARGET = ${DIR_BIN}/${PROGRAMNAME} SRC = $(wildcard ${DIR_SRC}/*.cpp) CC = g++

Html+css 一个简单的网页模板

一个简单的网页模板,有导航.子菜单.banner部分 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "http://www.w3.org/TR/html4/loose.dtd"> 3 <html> 4 <head> 5 <title>网页</title> 6 <meta charset="UTF-8&qu

Epii.js 一个极其简单的Js模板引擎

Epii.js 简约而不简单的JavaScript模板引擎 项目地址 https://github.com/epaii/epii.js 极低门槛,拿来即用,别忘记star 特性 一个轻量级模板引擎,可快速实现数据与ui绑定(数据变动,UI自动变动),快速实现事件绑定和处理,不依赖任何第三方库,仅仅8k. 可快速应用于web开发,native+webapp开发,h5微网页开发,不与其它框架冲突. 让开发者更多关注与应用本身,而不用花费大量时间实现数据与ui的,和事件处理.效率大幅度提升. 名字由来

最简单的JavaScript模板引擎

在小公司待久了感觉自己的知识面很小,最近逛博客园和一些技术网站看大家在说JavaScript模版引擎的事儿,完全没有概念,网上一搜这是08年开始流行起来的...本来以为这是很高深的知识,后来在网上看到jQuery作者John Resig,研究了一下,算是明白了最简单的javaScript模版引擎的原理,并没有想象的那么高大上,写篇博客推导一下John Resig写法的过程,写出一个最简单的JavaScript模版引擎. 什么是JavaScript引擎 其实在网站开发中模板还是很常见的一种技术,比

用 php 实现一个视图组件和模板引擎——基础

只要不是做后端接口开发和一些作为守护进程之类的服务器脚本,大多数时候都是在和浏览器打交道,因此合理组织并展现 html 标签是最为常见的工作.一般大家使用框架时,都会自带有一套视图组件和模板引擎. 我们不讨论这些组件和引擎的好坏.因为这些东西已经经过考验,可以在生产环境下使用.我们现在只是为了学习一些东西,这时候了解一些原理上的可能对以后的帮助更大,如果一些人真的很有时间,利用这些基础知识完全可以写一个自己的组件,即可当做练习,也可以拿去自用. 好了,说这么多,我还是希望很多人明白,视图和模板引

编写一个简单的js模板替换工具 rtt----replace templete tool

最近一段时间在修改自己的个人在线简历.  这个在线简历用到了css3来制作3D的旋转效果, 因此会有兼容性问题, 针对于不支持css3的3D透视的浏览器, 比如 IE,  360等等, 我使用的是另一套css文件兼容.  针对于移动端浏览器, 尽管基本都是webkit内核, 但经测试发现3D效果并不流畅, 因此移动端是识别userAgent切换到另一套非3D页面.  因为没用任何数据库, 那么问题就来了, 移动端和pc端两套页面是共用的一套数据, 我想到的方法有两个: 一是页面加载之后用ajax

[bootstrap] 打造一个简单的系统模板(1) 左侧折叠菜单

1. 前言 最近需要做一个后台管理系统,我打算使用bootstrap弄一个好看的后台模板.网上的好多模板我觉的css和js有点重. 于是就打算完全依靠bootstrap搭建一个属于自己的模板. 首先从左侧的折叠菜单开始.看图. 2. CSS 代码 以下是自定义的css代码,由于系统是内部使用,所以优先考虑chrome,firefox 不考虑IE了. #main-nav { margin-left: 1px; } #main-nav.nav-tabs.nav-stacked > li > a {

一个简单的Java模板工具类(二)—简单表达式解析实现

以前写过一个, 用正则比较不高效, 所以用表达式解析方式又实现了一个, 练手. 以前的: http://my.oschina.net/haogrgr/blog/222349 现在的: import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; /**  * 非常非常简单的模板实现  *   * @author desheng.tu  * @date 2015年

中级JavaScript例子, 如何实现一个简单实用的模板套用机制, GXTemplate , 第一章(估计要写9章)

我们是刚刚成立的, 一家传统的软件开发公司(只有几个人的小公司), 主营业务就是传统行业软件项目的外包. 由于这种项目需要的技术不深, 但是对开发效率有很高的要求, 所以我们在慢慢的摸索一下快速开发模式. 同时也愿意把其中不杂乱的部分,分享出来. 这一系列的文章主要是针对GXTemplate, 一个模板套用类库 (谈不上框架) 这并不是一个 "如何使用" 的教程 , 而是一个 "如何创造" 这种类库的教程. 特点是, 我们会把整个创造过程, 由v0.1的原始版本开始