說到 JavaScript 模板引擎,大家首先想到的肯定是 Angular 和 React 這些時下比較流行的專案,它們讓前端開發模式變的與傳統的 WordPress 主題大不相同。

不同於 WordPress 的使用 PHP 在服務端處理一切,呼叫模板生成好 HTML 再返回給使用者;JavaScript 模板引擎下,伺服器只負責處理和生成資料,然後由 JavaScript 在瀏覽器前端,根據專門為它設計的模板生成出 HTML 程式碼。

這種開發模式對於製作和使用者有大量互動的網站非常有優勢,尤其是在使用 AJAX 上傳和獲取資料時,可以避免很多麻煩。雖然這種技術我很喜歡,也符合未來的發展趨勢,但是因為搜尋引擎相關的問題的不完善,導致 JavaScript 模板引擎只能在 Web APP 和管理後臺之類的網頁被使用。

不過,即使在普通網站中不能全面的應用,在一些特殊的地方,小範圍的使用 JavaScript 模板生成 HTML 程式碼也是非常方便的,比如評論列表、設定選項和 AJAX 載入文章列表之類的,不需要搜尋引擎抓取,又需要 JavaScript 參與的功能。

在 WordPress 核心中,提供了一個基於 Underscore.js 的簡易 JavaScript 模板 「引擎」,被主題定製器大量的使用,今天我們就來一起學一下,相信只要合理利用它,就可以完美解決你拼接大量字串的痛苦。

掛載指令碼

在開始正式之前,首先要把用來支援 JavaScript 模板的 Underscore.js 引入進來,它在指令碼排隊系統中的名稱是 wp-util,可以直接掛載:

functionBing_enqueue_scripts(){

    wp_enqueue_script('wp-util');

}

add_action('wp_enqueue_scripts','Bing_enqueue_scripts');

也可以把它設定成我們的指令碼的依賴:

functionBing_enqueue_scripts(){

    wp_enqueue_script(

        'base',

        get_template_directory_uri().'/js/base.js',

        array('jquery','wp-util'),//依賴 wp-util 指令碼

        '1.0'

    );

}

add_action('wp_enqueue_scripts','Bing_enqueue_scripts');

儲存模板

在大多數情況下,我們會在頁面已經載入完成之後,呼叫模板並傳入資料來生成 HTML,但是這些模板存放在哪是個麻煩的問題。首先,模板不能被使用者看到,但是如果直接使用 CSS 隱藏,又會產生很大的 SEO 問題。

出於這個原因,我們在這裡使用一對 <script> 標籤來容納模板本身,然後把 type 屬性設定成 text/template 。這樣,當瀏覽器和搜尋引擎在看到是 <script> 標籤之後,就不會把裡邊的模板程式碼當成網頁內容,並且,由於無法理解 type 屬性的值,也不會當做 JavaScript 程式碼來執行,是非常完美的解決方案。

<script type="text/template"id="tmpl-article">

    <!--在這裡存放模板程式碼-->

</script>

為了方便呼叫這個模板,還要給 <script> 標籤的 id 引數設定成 tmpl-{id},在以後的使用中,就可以透過 ID 來指定呼叫哪個模板。

製作模板

模板往往是由 HTML 程式碼和一些動態的標籤組成,也可以在裡邊執行 JavaScript 程式碼來完成邏輯上的操作。

最常有的語法有三種:

  • {{ var }} - 輸出進行了 HTML 轉義的變數。
  • {{{ var }}} - 輸出原始變數。
  • <# runCode(); #> - 執行 JavaScript 程式碼,就像 PHP 模板檔案中的 <?php run_code(); ?> 那樣。

<script type="text/template"id="tmpl-article">

    <article id="post-{{ data.id }}"class="entry">

        <#if(data.hasThumbnail){#>

            <div class="entry-thumbnail">

                <img src="{{ data.thumbnail }}"/>

            </div>

        <#}#>

        <h2 class="entry-title">

            <ahref="{{ data.url }}">{{data.title}}</a>

        </h2>

        <div class="entry-summary">{{{data.excerpt}}}</div>

    </article>

</script>

上邊的例子中,大量的使用了 data 變數,這是我們在呼叫模板生成 HTML 時所傳入的引數 (下邊會具體講到),可以透過呼叫它的屬性來動態獲取資料,讓我們的模板可以被複用。

在製作完成之後,我建議把一個模板單獨存放在一個檔案中,然後透過 wp_footer 鉤子插入到頁面底部,這裡我直接使用 include 引入了儲存模板程式碼的檔案,這樣可以保證程式碼的乾淨整潔。

functionBing_load_article_template(){

    include(get_template_directory().'/templates/article-template.php');

}

add_action('wp_footer','Bing_load_article_template');

生成資料

模板準備好了,在生成 HTML 之前,我們首先得有資料,這些資料一般是透過 AJAX 來獲取,也可以直接放在 JavaScript 變數或者元素的 data-* 引數裡,這個根據需求來決定,怎麼方便怎麼來。

在伺服器中,我們要根據需求生成出資料,然後封裝成 JSON,給前端使用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

functionBing_random_posts(){

    $posts=get_posts('orderby=rand&posts_per_page=10');

    $json  =array();

    foreach($postsas$post){

        $json[$post->ID]=array(

            'id'           =>$post->ID,

            'hasThumbnail'=>has_post_thumbnail($post->ID),

            'url'          =>get_permalink($post->ID),

            'title'        =>get_the_title($post),

            'excerpt'      =>get_the_excerpt($post)

        );

        if($json[$post->ID]['hasThumbnail']){

            $thumbnail_id=get_post_thumbnail_id($post->ID);

            $thumbnail    =wp_get_attachment_image_src($thumbnail_id,'full');

            $json[$post->ID]['thumbnail']=$thumbnail[0];

        }

    }

    $json=array_values($json);

    wp_send_json($json);

}

add_action('wp_ajax_random-posts','Bing_random_posts');

add_action('wp_ajax_nopriv_random-posts','Bing_random_posts');

上邊的程式碼中,製作好資料之後,我們討巧的使用了 wp_send_json() 函式直接封裝併傳送 JSON 。如果需要直接把資料放在頁面裡,就得使用 wp_json_encode() 函式來封裝 JSON 並獲取,然後再在放到我們想要的位置。

<script type="text/javascript">

    jQuery(document).on('click','.random',function(){

        varposts='<?php echo wp_json_encode( $json ); ?>';

    });

</script>

使用模板

重頭戲來了,現在有了模板也有了資料,就差把兩者結合到一起,生成出 HTML 程式碼了。

首先,使用標題中提到的 wp.template() 方法,傳入模板的 ID 來初始化它;然後使用返回的方法,傳入 data 引數即可生成 HTML,總共說了一句話,就是這麼簡單。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

jQuery(document).on('click','.random',function(){

    varcontent  =jQuery('#content');

    content.empty();

    jQuery.get(adminAjax,'action=random-posts',function(data){

        vartemplate=wp.template('article');

        for(vari=data.length-1;i>=0;--i){

            varhtml=template(data[i]);

            content.prepend(html);

        }

    });

    returnfalse;

});

上邊的程式碼中,呼叫模板,傳入資料,生成出 HTML 程式碼,再透過 jQuery 的 DOM 操作方法 append()prepend()after() 和 before() 把程式碼插入到想要的位置,或者直接用 html() 方法修改元素的內容。

後記

看到最後,你可能會有點小失望,前邊的準備時間那麼長,到最後只需要兩步走就能完成操作。實際上,這個 JavaScript 模板的功能也就這麼多,只能幫你生成 HTML,減少在 JavaScript 程式碼中大量拼接字串的痛苦。

但是,如果能夠利用好,也能在實際開發中解決大問題。就比如我最近想製作一個點選外掛連結,就能直接彈出外掛資訊的功能,如果把所有外掛的彈窗都在 PHP 中生成好 HTML 程式碼,會導致頁面非常龐大,重複程式碼很多;直接在 JavaScript 中把彈窗程式碼拼接起來吧,更是讓我非常痛苦,所以才盯上了這個模板。

在實際使用過程中,還是在 「製作模板」 這一步驟的可擴充套件性最強,因為你可以嵌入任意 JavaScript 程式碼,各種邏輯都能完成,比如上邊所說的外掛彈窗,就有一個外掛的星級評價顯示,這些都可以在模板中完成,PHP 只需要提供分數即可。