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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 09:09:17