php模板系统 - 为模板加载默认Javascript行为的正确方法

时间:2011-02-15 19:50:04

标签: php javascript template-engine

情况:

  1. 一个PHP模板系统,负责构建HTML页面。
  2. Javascript核心功能都在外部文件中
  3. 每个模板都有一些默认的Javascript函数,需要在每个/模板的基础上调用
  4. 当呈现页面时,我接下来需要调用一组Javascript函数:即

    <script type="text/javascript">
         $(document).ready(function{
             API.loadThis();  // all these Javascript functions are in an external JS file
             API.loadThat();
             API.buildDateSelector("#idForSelector");
             // etc
        });
    </script>
    

    到目前为止,我刚刚将其作为文本添加到每个HTML模板中。但是,如果一个页面由多个较小的模板组成(每个模板可能包含它们自己的初始化Javascript),那么我的网页上会抛出多个内联Javascript。

    我的问题是:

    1. 我应该如何正确组织所有内容,以便我可以轻松“注册”或“触发”在页面加载时调用的默认Javascript?
    2. 或者是将每个Javascript块附加到每个模板(如上所述)适当的吗?

2 个答案:

答案 0 :(得分:1)

我会做的与@Chris非常相似。但是,我建议做一些小改动:

  1. addJS函数中添加一个参数,指示页面上的位置。默认情况下,您应该至少支持headfoothead会将其放在首位,foot会将其放在收盘前</body> )。

    public function addJS($string, $position = 'head') {
        if (!is_array($this->js[$position])) {
            $this->js[$position] = array($string);
        } elseif (!in_array($string, $this->js[$position])) {
            $this->js[$position][] = $string;
        }
    }
    

    然后,在模板中包含标记以指示位置:

        {{js_head}}
    </head>
    <body>
        <!--content here-->
        {{js_foot}}
    </body>
    

    然后,在渲染时,只需执行以下操作:

    $js = $this->js;
    $positions = preg_replace_callback(
        '/{{js_(inline_)?([a-zA-Z0-9]+)}}/', 
        function ($match) use ($js) {
            if (isset($js[$match[2]])) {
                $js = implode("\n", $js[$match[2]]);
                if ($match[1] == 'inline') {
                    return $js;
                } else {
                    return '<script type="text/javascript">'.$js.'</script>';
            }
            return '';
        },
        $templateBody
    );
    

    现在,真正的好处是你的模板可以干净利落地为重复使用和常用的位定义自己的位置:

    $this->addJS('return this.form.submit();', 'submit_form');
    $html = '
        <input type="text" onblur="{{js_inline_submit_form}}" />
        <button name="submit" onclick="{{js_inline_submit_form}}" />
    ';
    

    它非常有用,因为现在你没有在代码中的任何地方复制JS调用。另外,它会减少在<script>标签中包装每个输出的开销(因为它包裹标签中的整个位置,而不是每个内容)...

  2. 这将允许您在运行时获取所有非内联JS并编译一系列文件,以发送到浏览器以处理缓存。它增加了能够让你的JS接近你的视图(为了可维护性)但仍然提供缓存的JS而不必每次都重新发送它的好处......

    public function buildJSCache($position) {
        if (!isset($this->js[$position]) || empty($this->js[$position])) {
            return '';
        }
        $file = implode($this->js[$position]);
        $name = 'js/'.md5($file) .'.js';
        if (!file_exists($name)) {
            file_put_contents($name, $file);
        }
        return $name;
    }
    

    然后,在您的模板代码中,只需执行:

    $replace = $this->buildJSCache('head');
    if ($replace) {        
        $replace = '<script type="text/javascript" src="'.$filename.'"></script>';
    }
    $template = str_replace('{{js_head}}', $replace, $template);
    

    您可以获得用户可维护性和速度的双赢(如果您愿意,甚至可以将其缩小)。

  3. 注意:所有这些代码都只是演示,如果你在生产中使用它,我会清理它并进一步考虑......

    这至少是我0.02美元......

答案 1 :(得分:0)

有很多方法可以做到这一点。我建议您获得一些开源框架,看看他们如何做事并决定您的偏好。有些技术被认为是“最佳实践”,但很多框架的结构都归结为开发人员的偏好。

我有一个框架,我用于我自己的项目,类似于你描述的,每个较小的模板被称为“组件”。每个组件都可以使用addJS()方法为自己添加任意数量的javascript,同样适用于css和html。顶级控制器循环遍历给定页面的内容(就组件而言)。这让我有机会提前加载所有的css,javascript和html。然后,我可以按照我认为合适的顺序输出它们。

所以:

  • 页面控制器处理请求
    • 进入一个或多个组件
      • 组件load方法填充html,javascript和css类属性(文件名数组,html字符串) 为自己
      • 组件有自己的一组模板,js,css
    • 输出网站范围的模板
      • 包含页眉中的所有组件css
    • 遍历组件,输出组件html,布局内容
    • 输出页脚的组件JS

我有一个components文件夹,其中包含每个组件的文件夹。每个组件文件夹中都有一个php文件(该组件的处理程序),可选一个或多个css / js文件。这样可以很好地保持一切井井有条。