创建联系表单页面并通过 Ajax 提交表单请求数据

回顾下上篇教程更新主题后的博客系统,可以看到顶部右上角导航菜单有两个链接,分别指向关于页面和联系表单页面:

-w1140

对应的 HTML 模板代码位于 resources/views/header.php 中:

<div class="collapse navbar-collapse" id="navbarResponsive">
    <ul class="navbar-nav ml-auto">
        <li class="nav-item">
            <a class="nav-link" href="/">首页</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="/about">关于</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="/contact">联系</a>
        </li>
    </ul>
</div>

现在我们来为这两个页面定义 URL 路由和对应的页面渲染逻辑。在 app/routes/web.php 中注册路由:

$router->register('get', 'about', 'HomeController@about');
$router->register(['get', 'post'], 'contact', 'HomeController@contact');

我们将请求处理逻辑都放到了 HomeController 控制器对应的 Action 方法中实现。

关于页面

对于关于页面而言,我们直接对应的路由定义为重定向到外部链接:

class HomeController extends Controller
{
    ...

    // 关于页面
    public function about()
    {
        $response = new Response('', 301, ['Location' => 'https://xueyuanjun.com/about-us']);
        $response->send();
    }
    
    ...
}

渲染联系表单页面

对于联系表单页面,需要分两块处理,首先是渲染联系表单,这是一个 GET 请求:

// 联系表单页面
public function contact()
{
    if ($this->request->getMethod() == 'GET') {
        $pageTitle = '联系我 - ' . $this->container->resolve('app.name');
        $siteName = $this->container->resolve('app.name');
        $this->view->render('contact.php', compact('pageTitle', 'siteName'));
    } else {
        // @todo 处理表单请求数据(放到下一篇教程详细介绍)
    }
}

我们通过 $this->request->getMethod() 获取 HTTP 请求方法,并以此作为依据进行下一步处理:如果是 GET 请求,则渲染联系表单页面,如果是 POST 请求,则处理表单请求数据。

渲染联系表单页面对应的视图模板是 resources/views/contact.php,我们创建这个视图文件,并初始化代码如下:

<?php include 'header.php';?>

<!-- Page Header -->
<header class="masthead" style="background-image: url('/image/contact.jpg')">
    <div class="overlay"></div>
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-md-10 mx-auto">
                <div class="page-heading">
                    <h1>联系我</h1>
                    <span class="subheading">你有问题?我有答案。</span>
                </div>
            </div>
        </div>
    </div>
</header>

<!-- Main Content -->
<div class="container">
    <div class="row">
        <div class="col-lg-8 col-md-10 mx-auto">
            <p>你可以通过填写并提交下面的表单给我发送反馈消息,我会尽快给你回复!</p>
            <form name="sentMessage" id="contactForm" novalidate>
                <div class="control-group">
                    <div class="form-group floating-label-form-group controls">
                        <label>用户名</label>
                        <input type="text" class="form-control" placeholder="Name" id="name" required data-validation-required-message="请输入你的用户名">
                        <p class="help-block text-danger"></p>
                    </div>
                </div>
                <div class="control-group">
                    <div class="form-group floating-label-form-group controls">
                        <label>邮箱地址</label>
                        <input type="email" class="form-control" placeholder="Email Address" id="email" required data-validation-required-message="请输入你的邮箱">
                        <p class="help-block text-danger"></p>
                    </div>
                </div>
                <div class="control-group">
                    <div class="form-group col-xs-12 floating-label-form-group controls">
                        <label>手机号码</label>
                        <input type="tel" class="form-control" placeholder="Phone" id="phone" required data-validation-required-message="请输入你的手机号码">
                        <p class="help-block text-danger"></p>
                    </div>
                </div>
                <div class="control-group">
                    <div class="form-group floating-label-form-group controls">
                        <label>消息内容</label>
                        <textarea rows="5" class="form-control" placeholder="Message" id="message" required data-validation-required-message="请输入你要发聩的消息内容"></textarea>
                        <p class="help-block text-danger"></p>
                    </div>
                </div>
                <br>
                <div id="success"></div>
                <button type="submit" class="btn btn-primary" id="sendMessageButton">发送</button>
            </form>
        </div>
    </div>
</div>

<hr>

<?php include 'footer.php';?>
<script src="/js/contact.js"></script>

</body>

</html>

这里主要包含的是一个联系表单,参照 node_modules/startbootstrap-clean-blog/contact.html 编写即可。

提交表单请求

在上面的视图模板中,可以看到最后额外引入了 /js/contact.js 文件,这个文件是联系表单页面需要额外用到的 JavaScript 脚本文件,目前还不存在,需要编写对应的前端处理代码,并通过 Laravel Mix 组件编译打包生成。

resources/js 目录下新建 contact.js,并初始化代码如下:

require('./bootstrap')

require('startbootstrap-clean-blog/js/jqBootstrapValidation')

$(function() {

    $("#contactForm input,#contactForm textarea").jqBootstrapValidation({
        preventSubmit: true,
        submitError: function($form, event, errors) {
            // additional error messages or events
        },
        submitSuccess: function($form, event) {
            event.preventDefault(); // prevent default submit behaviour
            // get values from FORM
            var name = $("input#name").val();
            var email = $("input#email").val();
            var phone = $("input#phone").val();
            var message = $("textarea#message").val();
            var firstName = name; // For Success/Failure Message
            // Check for white space in name for Success/Fail message
            if (firstName.indexOf(' ') >= 0) {
                firstName = name.split(' ').slice(0, -1).join(' ');
            }
            $this = $("#sendMessageButton");
            $this.prop("disabled", true); // Disable submit button until AJAX call is complete to prevent duplicate messages
            $.ajax({
                url: "/contact",
                type: "POST",
                data: {
                    name: name,
                    phone: phone,
                    email: email,
                    message: message
                },
                cache: false,
                success: function(resp) {
                    // Success message
                    $('#success').html("<div class='alert alert-success'>");
                    $('#success > .alert-success').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-success')
                        .append("<strong>消息已发送。</strong>");
                    $('#success > .alert-success')
                        .append('</div>');
                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
                error: function(resp) {
                    // Fail message
                    $('#success').html("<div class='alert alert-danger'>");
                    $('#success > .alert-danger').html("<button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×")
                        .append("</button>");
                    $('#success > .alert-danger').append($("<strong>").text(resp.responseText));
                    $('#success > .alert-danger').append('</div>');
                    //clear all fields
                    $('#contactForm').trigger("reset");
                },
                complete: function() {
                    setTimeout(function() {
                        $this.prop("disabled", false); // Re-enable submit button when AJAX call is complete
                    }, 1000);
                }
            });
        },
        filter: function() {
            return $(this).is(":visible");
        },
    });

    $("a[data-toggle=\"tab\"]").click(function(e) {
        e.preventDefault();
        $(this).tab("show");
    });
});

/*When clicking on Full hide fail/success boxes */
$('#name').focus(function() {
    $('#success').html('');
});

这里我们首先通过 require('./bootstrap') 引入 jQuery 及 Bootstrap 模块,然后引入 jqBootstrapValidation 组件对表单请求数据进行简单验证,比如字段不能为空等,最后编写了一段 jQuery 代码处理表单数据的异步提交(Ajax 请求),关于代码实现细节就不展开介绍了,重点关注 submitSuccess 的情况下,$.ajax({...}) 中的处理代码。

访问联系表单页面

完成以上工作后,在项目根目录下的 webpack.mix.js 中添加 contact.js 编译代码:

mix.js('resources/js/app.js', 'public/js')
    .js('resources/js/contact.js', 'public/js/contact.js')
    .sass('resources/sass/app.scss', 'public/css');

运行 npm run dev 重新编译打包前端代码,成功后就可以在 public/js 目录下看到 contact.js 了。

在浏览器中访问 http://localhost:9000/contact,就可以看到联系表单页面了:

-w1116

我们可以尝试提交空表单,会显示报错信息,这就是 jqBootstrapValidation 组件生效的效果:

-w809

这个处理逻辑是前端的,表单数据前端验证通过发送给后端的验证和处理逻辑,我们放到下篇教程介绍。

上一篇: 将博客主题替换成 Clean Blog

下一篇: PHP 后端表单验证和请求处理