Система шаблонов php - правильный способ загрузки поведения Javascript по умолчанию для шаблона

Ситуация:

  1. Система шаблонов PHP, отвечающая за создание HTML-страниц.
  2. Все основные функции Javascript находятся во внешних файлах.
  3. Каждый шаблон имеет некоторые функции Javascript по умолчанию, которые необходимо вызывать для каждого шаблона.

Когда страница отображается, мне нужно вызвать набор функций 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 к каждому шаблону (как указано выше)?

person Kenny Cason    schedule 15.02.2011    source источник
comment
Кроме того, если не совсем понятно, о чем я спрашиваю, дайте мне знать, и я могу добавить более конкретную информацию. Спасибо   -  person Kenny Cason    schedule 15.02.2011
comment
В нашем продукте у нас есть что-то похожее, и мы делаем это таким образом, имея {tpl_name}_js_bottom.tpl, который загружается, если существует, при рендеринге шаблона.   -  person ludesign    schedule 15.02.2011


Ответы (2)


То, что я сделал бы, очень похоже на @Chris. Тем не менее, я бы предложил несколько незначительных изменений:

  1. Добавьте в функцию addJS параметр, указывающий позицию на странице. По умолчанию у вас должна быть поддержка как минимум head и foot (head поместит его в голову, 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);
    

    Вы получаете двойную выгоду от удобства обслуживания и скорости для пользователя (вы даже можете минимизировать это, если хотите).

Примечание: весь этот код является только демонстрацией, если бы вы использовали его в производстве, я бы очистил его и немного подумал...

Это как минимум 0,02 доллара...

person ircmaxell    schedule 15.02.2011
comment
Мне также нравится идея указывать места для вставки встроенного JS. Довольно интересно. Мне придется сесть и подумать обо всем этом - person Kenny Cason; 15.02.2011

Есть много способов сделать это. Я предлагаю вам получить несколько фреймворков с открытым исходным кодом, посмотреть, как они работают, и определиться со своими предпочтениями. Некоторые методы считаются «наилучшей практикой», но большая часть структуры фреймворка сводится к предпочтениям разработчика.

У меня есть структура, которую я использую для своих собственных проектов, похожая на то, что вы описываете, каждый из меньших шаблонов называется «компонентом». Каждый компонент может добавить к себе любое количество javascript, используя метод addJS(), аналогично для css и html. Контроллер верхнего уровня перебирает содержимое данной страницы (с точки зрения компонентов). Это дает мне возможность заранее загрузить все css, javascript и html. Затем я могу вывести их в любом порядке, который считаю нужным.

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
      • компоненты имеют свой набор шаблонов, js, css
    • outputs site-wide templates
      • includes all component css within page header
    • перебирает компоненты, выводит HTML-код компонента, материал макета
    • выводит компонент JS для нижнего колонтитула страницы

У меня есть папка components, внутри нее папки для каждого компонента. В каждой папке компонента находится файл php (обработчик этого компонента), возможно, один или несколько файлов css/js. Благодаря этому все хорошо организовано.

person Chris Baker    schedule 15.02.2011
comment
Ницца. это было моим размышлением. страница имеет массив функций/кода загрузки JS, и все они отображаются при отображении страницы. Вы также правы, проверяя многие другие шаблонизаторы. Я чувствую, что, возможно, мне следовало сделать это на более низком уровне, прежде чем публиковать: P - person Kenny Cason; 15.02.2011
comment
Примечание. Вам нужен не механизм шаблонов, а структура приложения. Это часть вашего кода, которая использует механизм шаблонов — код, который решает, когда отображать объекты, что делать с выводом и т. д. Механизм шаблонов занимается только созданием HTML. Поэтому, когда вы идете по магазинам, ищите фреймворки и смотрите, какой механизм шаблонов они используют. - person Chris Baker; 15.02.2011
comment
Интересно, спасибо за это. Я действительно не думал об этом так, но вместо этого я просто смешал все вместе как механизм шаблонов, хе-хе - person Kenny Cason; 15.02.2011
comment
Я тоже, я хотел бы, чтобы они хотя бы дали объяснение. :-/ ну +1 от меня. Спасибо! - person Kenny Cason; 16.02.2011