如何在字符串中引入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
相关产品推荐
相关产品推荐

