开发者

php templating system - Proper way to load default Javascript behavior for a template

Situat开发者_运维技巧ion:

  1. A PHP Templating system that is responsible for building a pages HTML.
  2. Javascript core functions are all in external files
  3. Each Template has some default Javascript Functions that need to be called on a per/template basis

When A page is rendered, I next need to call a set of Javascript functions: i.e.

<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>

Up until now I have just appended that as text to each of the HTML templates. However, in the case of a Page that consists of multiple smaller Templates (each possibly containing their own initialization Javascript), then I have multiple bits of inline Javascript thrown all over my webpage.

My question is:

  1. how should I properly organize everything so that I can easily "register" or "trigger" some default Javascript to be called upon page load?
  2. Or is appending each block of Javascript to each template (like above) appropriate?


What I would do is quite similar to @Chris. However, I'd suggest a few minor changes:

  1. Add a parameter to the addJS function which indicates the position on the page. By default you should have support for at least head and foot (head would place it in the head, foot would place it right before the closing </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;
        }
    }
    

    Then, include tokens in the template to indicate the positions:

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

    Then, when rendering, just do something like:

    $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
    );
    

    Now, the real benefit is that your templates can cleanly and trivially define their own positions for re-used and commonly used bits:

    $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}}" />
    ';
    

    It can be quite useful since now you're not duplicating the JS calls everywhere in your code. Plus, it'll reduce the overhead of wrapping each output in <script> tags (since it wraps the entire position in the tags, rather than each piece of content)...

  2. This would allow you to then take all of the non-inline JS and compile a series of files at run-time to send to the browser to take care of caching. It adds the benefit of being able to keep your JS close to your views (for maintainability) yet still serve cached JS and not have to re-send it every time...

    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;
    }
    

    Then, in your template code, just do:

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

    You get the double-win of maintainability and speed to the user (you could even minify it if you wanted).

Note: all of this code is demonstration only, if you were to use it in production, I'd clean it up and think it out a bit further...

That's my $0.02 at least...


There are a lot of ways to do this. I suggest that you get some open source frameworks, look at how they do things and decide on your preferences. Some techniques are considered "best practice", but a lot of a framework's structure boils down to developer preference.

I have a framework I use for my own projects that is similar to what you describe, each of the smaller templates is termed as a "component". Each component is able to add any amount of javascript to itself using an addJS() method, likewise for css and html. A top-level controller loops through a given page's content (in terms of components). This give me a chance to have all the css, javascript, and html loaded ahead of time. Then, I can output them in whatever order I see fit.

So:

  • page controller handles request
    • inits one or more components
      • component load method populates html, javascript, and css class properties (arrays of file names, string for html) for itself
      • components has its own set of templates, js, css
    • outputs site-wide templates
      • includes all component css within page header
    • iterates through components, outputs component html, layout stuff
    • outputs component JS for page footer

I have a components folder, within it are folders for each component. Within each component folder is a php file (that component's handler), optionally one or more css/js files. This keeps everything organized nicely.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜