EJS渲染时出现function not defined错误求助
问题核心原因
你碰到的问题本质是EJS模板的执行环境和前端JS完全分离:
- EJS的
<%= %>语法是在Node.js服务器端执行的,此时浏览器还没加载页面,你通过<script>引入的getTimeElapsed是前端浏览器环境的函数,服务器端根本访问不到,所以会提示函数不存在。 - 你在控制台能调用这个函数,是因为页面已经加载完成,函数在浏览器环境生效了,但这和EJS模板渲染阶段是完全独立的两个阶段。
另外你的elapsedtime.js里还有个笔误:return currentDate - plantDate;中的plantDate应该是submitteddate,这个不修正的话,就算前端调用也会报错。
解决方案
方案一:服务器端计算时间差(推荐)
把时间计算逻辑移到Node.js服务器端,渲染EJS前就计算好每个数据的时间差,直接传给模板:
- 修改路由文件,添加计算函数并处理数据:
// 路由文件中新增时间计算函数 function getTimeElapsed(submitdate) { const submittedDate = new Date(submitdate); const currentDate = new Date(); return currentDate - submittedDate; } router.get('/main', function(req, res, next) { // 注意:原代码里let res = ...会覆盖路由的res对象,必须改变量名 train.getAll().then(trainsStr => { const trains = JSON.parse(trainsStr); // 给每条数据添加计算好的时间差 const trainsWithElapsed = trains.map(train => ({ ...train, timeElapsed: getTimeElapsed(train.dateSubmit) })); res.render('main', { title: 'View All Plants', data: trainsWithElapsed}); }).catch(err => { // 记得添加错误处理 next(err); }); });
- 修改EJS模板,直接使用计算好的值:
<% data.forEach(item => { %> <div> <div class="card-body"> <p class="card-text"><%= item.something %></p> <span><%= item.timeElapsed %></span> </div> </div> <% }); %>
(原代码里循环变量名data和外层数据源重名,改成item避免作用域混淆)
方案二:前端渲染后动态计算
如果必须在前端计算,可以先渲染占位符,等页面加载完成后用JS遍历DOM替换内容:
- 修改EJS模板,给span添加标识和存储原始日期的属性:
<% data.forEach(item => { %> <div> <div class="card-body"> <p class="card-text"><%= item.something %></p> <!-- 用data-date存储原始日期,留空span等待填充 --> <span class="elapsed-time" data-date="<%= item.dateSubmit %>"></span> </div> </div> <% }); %>
- 修正
elapsedtime.js的笔误,并添加页面初始化逻辑:
function getTimeElapsed(submitdate) { const submitteddate = new Date(submitdate); const currentDate = new Date(); // 修正笔误:plantDate改为submitteddate return currentDate - submitteddate; } // 页面加载完成后执行计算 document.addEventListener('DOMContentLoaded', function() { const elapsedSpans = document.querySelectorAll('.elapsed-time'); elapsedSpans.forEach(span => { const submitDate = span.dataset.date; const elapsed = getTimeElapsed(submitDate); span.textContent = elapsed; }); });
额外注意事项
- 原路由代码里的
let res = train.getAll()是严重错误,会覆盖路由回调的res对象,导致后续res.render失效,必须修改变量名。 - EJS模板里的循环变量名不要和外层数据源重名,否则会导致作用域混乱。
内容的提问来源于stack exchange,提问作者Siddhant Sahni
相关产品推荐
相关产品推荐

