Thymeleaf教程 (八) 模板佈局(thymeleaf的主要技術優勢)

這節主要介紹模板的引入。及如何在不改變前端人員的html顯示結果的情況下設計模板(通過屬性配置動態時不顯示的部分)。

模板模塊導入

首先定義一個/WEBINF/templates/footer.html文件:

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <body>
        <div th:fragment="copy">
            &copy; 2011 The Good Thymes Virtual Grocery
        </div>
    </body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

上面的代碼定義了一個片段稱爲copy,我們可以很容易地使用th:include 或者 th:replace屬性包含在我們的主頁上:

<body>
...
<div th:include="footer :: copy"></div>
</body>
  • 1
  • 2
  • 3
  • 4

include的表達式想當簡潔。這裏有三種寫法:

  • “templatename::domselector” 或者 “templatename::[domselector]”引入模板頁面中的某個模塊。
  • “templatename”引入模板頁面。
  • “::domselector” 或者 “this::domselector” 引入自身模板的模塊 
    上面所有的templatename和domselector的寫法都支持表達式寫法:
<div th:include="footer :: (${user.isAdmin}? #{footer.admin} : #{footer.normaluser})"></div>
  • 1

不使用th:fragment來引用模塊

...
<div id="copy-section">
&copy; 2011 The Good Thymes Virtual Grocery
</div>
...
  • 1
  • 2
  • 3
  • 4
  • 5

我們可以用css的選擇器寫法來引入

<body>
...
<div th:include="footer :: #copy-section"></div>
</body>
  • 1
  • 2
  • 3
  • 4

th:include 和 th:replace的區別

th:include和th:replace都可以引入模塊,兩者的區別在於 
th:include:引入子模塊的children,依然保留父模塊的tag。 
th:replace:引入子模塊的所有,不保留父模塊的tag。 
舉個栗子:

<footer th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</footer>
  • 1
  • 2
  • 3

引入界面:

<body>
...
<div th:include="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
</body>
  • 1
  • 2
  • 3
  • 4
  • 5

結果是:

<body>
...
<div>
&copy; 2011 The Good Thymes Virtual Grocery
</div>
<footer>
&copy; 2011 The Good Thymes Virtual Grocery
</footer>
</body>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

給引入模塊添加參數

我們的模塊當中肯定有需要有參數的需求:

<div th:fragment="frag (onevar,twovar)">
    <p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>
  • 1
  • 2
  • 3

比如在文本中顯示參數可以這樣中:

<div th:include="::frag (${value1},${value2})">...</div>
<div th:include="::frag (onevar=${value1},twovar=${value2})">...</div>
  • 1
  • 2

第二種用法中參數順序並不重要:

<div th:include="::frag (twovar=${value2},onevar=${value1})">...</div>
  • 1

引入沒有被定義的模塊參數

這段模塊沒有定義參數

<div th:fragment="frag">
...
</div>
  • 1
  • 2
  • 3

我們可以並且只能用第二種方式引入:

<div th:include="::frag (onevar=${value1},twovar=${value2})">
  • 1

這個也等同於:

<div th:include="::frag" th:with="onevar=${value1},twovar=${value2}">
  • 1

解析式刪除不需要的內容(這纔是此技術最吸引人的地方,可以讓前端和後端使用同一個模板,並且都能看到自己想要的效果)

一般情況下後端處理後的界面是這樣的:

<table>
    <tr>
        <th>NAME</th>
        <th>PRICE</th>
        <th>IN STOCK</th>
        <th>COMMENTS</th>
    </tr>
    <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
        <td th:text="${prod.name}">Onions</td>
        <td th:text="${prod.price}">2.41</td>
        <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
        <td>
            <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
            <a href="comments.html"
            th:href="@{/product/comments(prodId=${prod.id})}"
            th:unless="${#lists.isEmpty(prod.comments)}">view</a>
        </td>
    </tr>
</table>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

這只是個模板文件,不是前端寫好的預覽文件,那麼要和前端寫好的預覽文件一至,我們一般情況下只能增加虛擬的行.

<table>
    <tr>
        <th>NAME</th>
        <th>PRICE</th>
        <th>IN STOCK</th>
        <th>COMMENTS</th>
    </tr>
    <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
        <td th:text="${prod.name}">Onions</td>
        <td th:text="${prod.price}">2.41</td>
        <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
        <td>
            <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
            <a href="comments.html"
            th:href="@{/product/comments(prodId=${prod.id})}"
            th:unless="${#lists.isEmpty(prod.comments)}">view</a>
        </td>
    </tr>
    <tr class="odd">
        <td>Blue Lettuce</td>
        <td>9.55</td>
        <td>no</td>
        <td>
        <span>0</span> comment/s
    </td>
    </tr>
    <tr>
        <td>Mild Cinnamon</td>
        <td>1.99</td>
        <td>yes</td>
        <td>
        <span>3</span> comment/s
        <a href="comments.html">view</a>
        </td>
    </tr>
</table
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

OK.現在我們有三行了。看起來和前端的預覽文件一致了。那麼我們通過thymeleaf處理後的結果肯定是正確的內容+虛擬的內容,其實我們要的只是正確的內容而已。 
爲了解決這個問題th:remove華麗登場了。

<table>
    <tr>
        <th>NAME</th>
        <th>PRICE</th>
        <th>IN STOCK</th>
        <th>COMMENTS</th>
    </tr>
    <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
        <td th:text="${prod.name}">Onions</td>
        <td th:text="${prod.price}">2.41</td>
        <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
        <td>
        <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
        <a href="comments.html"
        th:href="@{/product/comments(prodId=${prod.id})}"
        th:unless="${#lists.isEmpty(prod.comments)}">view</a>
        </td>
    </tr>
    <tr class="odd" th:remove="all">
        <td>Blue Lettuce</td>
        <td>9.55</td>
        <td>no</td>
        <td>
        <span>0</span> comment/s
        </td>
    </tr>
    <tr th:remove="all">
        <td>Mild Cinnamon</td>
        <td>1.99</td>
        <td>yes</td>
        <td>
        <span>3</span> comment/s
        <a href="comments.html">view</a>
        </td>
    </tr>
</table>
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

這個模板在後端開發通過thymeleaf解析後會移除掉有th:remove的標籤,滿足後端的預期。同時在前端眼中,也是自己預覽的效果。

th:remove總共有五種屬性:

  • all : 移除tag標記和children。
  • body:保留tag標記和移除children。
  • tag :移除tag和保留children.
  • all-but-first :保留tag和移除除了第一個外的所有children。
  • none :什麼都不做。 
    以下是all-but-first的栗子:
<table>
    <thead>
        <tr>
            <th>NAME</th>
            <th>PRICE</th>
            <th>IN STOCK</th>
            <th>COMMENTS</th>
        </tr>
    </thead>
    <tbody th:remove="all-but-first">
        <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
            <td th:text="${prod.name}">Onions</td>
            <td th:text="${prod.price}">2.41</td>
            <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
            <td>
            <span th:text="${#lists.size(prod.comments)}">2</span> comment/s
            <a href="comments.html"
            th:href="@{/product/comments(prodId=${prod.id})}"
            th:unless="${#lists.isEmpty(prod.comments)}">view</a>
            </td>
        </tr>
        <tr class="odd">
            <td>Blue Lettuce</td>
            <td>9.55</td>
            <td>no</td>
            <td>
            <span>0</span> comment/s
            </td>
        </tr>
        <tr>
            <td>Mild Cinnamon</td>
            <td>1.99</td>
            <td>yes</td>
            <td>
            <span>3</span> comment/s
            <a href="comments.html">view</a>
            </td>
        </tr>
    </tbody>
</table>
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

當然屬性也支持表達式:

<a href="/something" th:remove="${condition}? tag : none">Link text not to be removed</a>
  • 1
<a href="/something" th:remove="${condition}? tag">Link text not to be removed</a>
  • 1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章