微博類系統,AJAX 提交後回傳 Map/JSON,前端以字串拼接方式生成 HTML 插入列表。拼接點多、維護難、易 XSS。
<!-- 隱藏範本 -->
<div id=\"post-template\" style=\"display:none\">
<div class=\"post\">
<span class=\"author\"></span>
<span class=\"time\"></span>
<p class=\"content\"></p>
</div>
</div>
<!-- 列表容器 -->
<div id=\"post-list\"></div>
<script>
function appendPost(data) {
var $tpl = $('#post-template .post').clone(); // 克隆範本
$tpl.find('.author').text(data.author);
$tpl.find('.time').text(formatTime(data.time));
$tpl.find('.content').text(data.content); // text() 自動轉義,防 XSS
$('#post-list').prepend($tpl.show()); // 顯示並插入頂部
}
</script>
// Controller
@GetMapping(\"/post/fragment\")
public String postFragment(@RequestParam Long id, Model model) {
model.addAttribute(\"post\", postService.get(id));
return \"fragments/post :: postItem\"; // Thymeleaf 片段
}
...
// 前端
$.get('/post/fragment', {id: newId}, function(html) {
$('#post-list').prepend(html);
});
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| jQuery clone 範本 | 零依賴、改動小、利用瀏覽器原生 DOM、text() 防 XSS | 邏輯分散、複雜結構難維護 | 存量 jQuery 專案、快速修復 |
| 後端片段渲染 | 模板集中管理、伺服器直出 SEO 友好、復用性高 | 增加一次請求、耦合後端模板引擎 | 傳統 MVC 專案、需 SEO |
| Vue/React 組件 | 組件化、響應式、生態豐富、類型安全 | 學習成本、建構工具鏈 | 新專案、長期維護 |
**絕不使用 html() 或 innerHTML 直接插入未轉義資料**。
- jQuery: .text() / .val() 自動轉義。
- 原生: textContent / element.innerText。
- 後端模板: Thymeleaf th:text、FreeMarker ${...?html} 預設轉義。
**存量 jQuery 專案首選「範本 clone + text() 賦值」**,最小改動解決拼接地獄與 XSS。長期演進建議引入片段渲染或遷移至組件化框架。