如何在Express中传递变量至Handlebars模板实现表单反馈
解决表单提交后邮件状态提示问题
问题背景
我正在开发网站的报价请求联系表单,需要在表单提交后,在表单下方弹出邮件发送成功/失败的提示。目前卡在:Express端如何根据transporter.sendMail的执行结果设置状态变量,让Handlebars模板能渲染对应提示,尝试用helper实现但没成功。
解决方案
核心逻辑:后端在邮件发送完成后,向前端返回包含状态的JSON响应;前端根据响应结果动态生成提示(因为是AJAX提交,页面不刷新,直接操作DOM比重新渲染模板更高效)。
1. 修改后端app.js
重点是在邮件发送回调里返回状态,同时处理表单解析错误:
// ==== Contact Form ==== //Create Mailer options const options = { viewEngine: { extname: '.hbs', layoutsDir: __dirname + '/views/email/', defaultLayout: 'template', partialsDir: 'views/partials/' }, viewPath: 'views/email/', extName: '.hbs' }; // Create Transporter const transporter = nodemailer.createTransport({ host: 'smtp-mail.outlook.com', port: 587, auth: { user: process.env.USER, pass: process.env.PASS } }); // verify connection configuration transporter.verify(function(error, success) { if (error) { console.log('Error with transporter verification:' + `\n${error}`); } }); //attach the plugin to the nodemailer transporter transporter.use('compile', hbs(options)); app.post('/send', (req, res) => { // Accepts the form data submitted and parse it let form = new multiparty.Form(); let data = {}; form.parse(req, function(err, fields) { // 处理表单解析错误 if (err) { console.log('表单解析错误:', err); return res.json({ success: false, message: '表单数据解析失败' }); } Object.keys(fields).forEach(function(property) { data[property] = fields[property].toString(); }); // Create Mail object with options const mail = { from: `"********" <${process.env.USER}>`, to: '************', // receiver email, subject: 'Quote Request', template: 'email.body', // Import variables into email for use with handlebars context: { name: data.name, email: data.email, number: data.number, message: data.message } }; // Send email transporter.sendMail(mail, (err, info) => { if (err) { console.log('邮件发送失败:', err); res.json({ success: false, message: '邮件发送失败,请重试' }); } else { console.log('Email successfully sent to recipient!'); res.json({ success: true, message: '消息发送成功!' }); } }); }); });
2. 修改前端script.js
处理后端响应,动态生成提示并插入到表单下方:
// Contact Form Client Functions //get the form by its id const form = document.getElementById('contact-form'); // 创建提示容器,放在表单下方 const alertContainer = document.createElement('div'); alertContainer.id = 'form-alert'; form.parentNode.insertBefore(alertContainer, form.nextSibling); //add event listener (when clicking the submit button, do the following) form.addEventListener('submit', (event) => { // Prevent page from refreshing when submit button clicked event.preventDefault(); // 清空之前的提示 alertContainer.innerHTML = ''; //parse data to formData variable let mail = new FormData(form); //send mail sendMail(mail) .then(result => { // 根据结果渲染提示 const alert = document.createElement('h4'); alert.style.color = result.success ? 'lightgreen' : 'red'; alert.textContent = result.message; alertContainer.appendChild(alert); // 3秒后自动隐藏提示 setTimeout(() => alertContainer.innerHTML = '', 3000); // reset form fields to empty form.reset(); }) .catch(err => { console.log('请求出错:', err); const alert = document.createElement('h4'); alert.style.color = 'red'; alert.textContent = '请求出错,请检查网络后重试'; alertContainer.appendChild(alert); }); }); const sendMail = (mail) => { return fetch('/send', { method: 'post', body: mail }).then((response) => { return response.json(); }); };
3. 调整Handlebars模板(可选,服务器渲染场景)
如果页面是服务器渲染,需要在GET请求时传递状态变量(比如用户刷新页面时保留提示),可以修改路由:
// 假设表单页面路由是/contact app.get('/contact', (req, res) => { // 从查询参数获取状态 const mailSent = req.query.success === 'true'; const mailError = req.query.error === 'true'; res.render('contact', { mailSent, mailError }); });
模板保留原逻辑:
<div id="form-alert"> {{#if mailSent}} <h4 style="color: lightgreen">Your message has been sent successfully!</h4> {{else if mailError}} <h4 style="color: red">ERROR: There was an issue sending your message, please try again.</h4> {{/if}} </div>
这种方式需要后端在POST请求后重定向到GET路由并携带参数,适合非AJAX提交场景。
内容的提问来源于stack exchange,提问作者Austin
相关产品推荐
相关产品推荐

