You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在字符串中引入Handlebars局部模板并添加到DOM元素innerHTML?

解决Express-Handlebars前端动态添加局部模板的问题

核心问题:Express-Handlebars是后端渲染引擎,前端浏览器无法直接解析它的局部模板语法({{> Task}}),必须通过后端预渲染或前端引入Handlebars编译环境实现动态添加。以下是两种可行方案:


方案一:后端预渲染局部模板为字符串,传递给前端使用

通过Express路由预编译task.hbs模板,生成对应HTML字符串后传给前端,前端直接复用该字符串拼接DOM。

1. 后端路由配置

假设task.hbs放在views/partials/目录下,修改路由代码:

const express = require('express');
const exphbs = require('express-handlebars');
const fs = require('fs');
const app = express();

// 初始化Handlebars实例
const hbs = exphbs.create({
  partialsDir: './views/partials'
});
app.engine('hbs', hbs.engine);
app.set('view engine', 'hbs');

app.get('/todo', (req, res) => {
  // 读取并编译task局部模板
  const taskTemplateSource = fs.readFileSync('./views/partials/task.hbs', 'utf8');
  const taskRender = hbs.handlebars.compile(taskTemplateSource);
  
  // 生成带默认标题的HTML字符串(需动态标题可后续通过接口实现)
  const defaultTaskHtml = taskRender({ title: 'A new task' });
  
  // 将HTML字符串传给todo_list模板
  res.render('todo_list', { defaultTaskHtml });
});

2. 前端模板与逻辑修改

修改todo_list.hbs,接收后端传来的模板字符串并复用:

<div id="todo-list">
</div>
<button onclick="addTask()">Add Task</button>

<script>
// 存储后端预渲染的task HTML(三个大括号避免HTML转义)
const baseTaskHtml = `{{{defaultTaskHtml}}}`;

function addTask() {
  const todoList = document.getElementById('todo-list');
  // 追加模板内容到DOM
  todoList.innerHTML += baseTaskHtml;
  
  // 手动绑定删除事件(innerHTML添加的script不会自动执行)
  const lastDeleteBtn = todoList.querySelector('.delete-task:last-of-type');
  lastDeleteBtn.addEventListener('click', deleteTask);
}

function deleteTask() {
  this.parentElement.remove();
}
</script>

注意事项

  • 把task.hbs中的id="delete-task"改为class="delete-task",避免重复ID问题
  • 若需动态生成不同标题的任务,可新增后端接口接收title参数,返回渲染好的HTML字符串,前端通过AJAX请求获取

方案二:前端引入Handlebars,直接在浏览器编译模板

前端引入Handlebars库,把task.hbs内容作为模板字符串,在浏览器端编译并渲染。

修改todo_list.hbs

<div id="todo-list">
</div>
<button onclick="addTask()">Add Task</button>

<!-- 引入Handlebars库 -->
<script src="https://cdn.jsdelivr.net/npm/handlebars@4.7.7/dist/handlebars.min.js"></script>

<!-- 定义Handlebars模板(复用task.hbs内容) -->
<script id="task-template" type="text/x-handlebars-template">
  <h1 class="task-title">The task is: {{title}}</h1>
  <button class="delete-task">Delete task</button>
</script>

<script>
// 编译模板
const taskTemplate = Handlebars.compile(document.getElementById('task-template').innerHTML);

function addTask() {
  const todoList = document.getElementById('todo-list');
  // 动态传入数据,渲染生成HTML
  const taskHtml = taskTemplate({ title: `New task ${Date.now()}` });
  todoList.innerHTML += taskHtml;
}

// 用事件委托处理删除(更高效,无需每次添加都绑定事件)
document.getElementById('todo-list').addEventListener('click', function(e) {
  if (e.target.classList.contains('delete-task')) {
    e.target.parentElement.remove();
  }
});
</script>

注意事项

  • 移除task.hbs中的<script>标签,避免重复绑定事件
  • 事件委托是更优方案,无需为每个新任务单独绑定删除事件

内容的提问来源于stack exchange,提问作者Sharif Velázquez Alzate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 17:35:19