通过 Vue 组件、Vue Router、Vuex 和 Laravel 实现表单提交


在这篇教程中,我们来为咖啡店添加一些数据。我们构建这个应用的目的是为了帮助咖啡爱好者找到下一杯咖啡,所以首先需要让认证用户可以提交咖啡店到应用,不论何时在单页面应用中处理表单,都需要让 Laravel API 和调用 JavaScript 路由并更新 Vuex 储存数据的 Vuex 模块协同工作。听起来需要做的事情很多,但如果我们将它们拆解开来各个击破,也没有那么复杂。

第一步:回顾我们现在有什么

我们在 Laravel API 中定义了一个路由来处理新增咖啡店,该路由需要一下参数:

  • 名称
  • 地址
  • 城市
  • 省份
  • 邮编

这些只是一个咖啡店的基本参数,后面还会添加更多。

我们还有一个 Vue Router 路由 /cafes/new 用来在前端处理新增咖啡店以及一个用于新增咖啡店的模板文件:/resources/assets/js/pages/NewCafe.vue

我们已经做好了以上准备工作,并且在 /resources/assets/js/api/cafe.js 文件中还有一个接收上述 5 个参数来提交一个咖啡店的 JavaScript API 调用:postAddNewCafe,但是还有一些工作要做:

  • 添加一个提交新咖啡店的表单到 NewCafe.vue 文件
  • 发送请求动作到 Cafes 模块以便提交新咖啡店
  • 通过 JavaScript API 提交新咖啡店到 Laravel API
  • 将处理结果返回给前端,尤其是 Vuex 模块
  • 重新加载咖啡店并更新 Vuex 模块

以上就是基于 API + Vue 驱动的单页面应用添加内容到数据库的基本流程,接下来我们就按照这个基本流程一步一步来操作。

第二步:添加表单到 NewCafe.vue 页面

首先打开 /resources/assets/js/pages/NewCafe.vue 文件,现在这个页面空的,我们将新增咖啡店表单插入到这个模板中:

<template>
    <div class="page">
        <form>
            <div class="grid-container">
                <div class="grid-x grid-padding-x">
                    <div class="large-12 medium-12 small-12 cell">
                        <label>Name
                            <input type="text" placeholder="咖啡店名">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <label>Address
                            <input type="text" placeholder="地址">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <label>City
                            <input type="text" placeholder="城市">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <label>State
                            <input type="text" placeholder="省份">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <label>Zip
                            <input type="text" placeholder="邮编">
                        </label>
                    </div>
                </div>
            </div>
        </form>
    </div>
</template>

注意:

  • 我们使用的是 Zurb Foundation 6.4 XY-Grid 栅格系统进行布局,其中某些风格已经预定义好了,如果你想了解更多关于这个栅格布局的内容,可以查看官方文档
  • 我为 <div> 容器中新增了 class 属性 page,对应的样式定义位于 /resources/assets/sass/layouts/_page.scss

接下来需要在页面中设置模型,在页面组件中添加一个 data() 函数并以对象方式返回模型数据:

export default {
    data() {
        return {
            name: '',
            address: '',
            city: '',
            state: '',
            zip: ''
        }
    }
}

现在我们需要通过 v-model 将模型数据和表单输入框绑定起来,Vue 会帮助我们同步模型数据和表单元素,并且这个同步是双向的,关于 v-model 指令可以参考 Vue 官方文档了解更多明细:

<div class="page">
    <form>
        <div class="grid-container">
            <div class="grid-x grid-padding-x">
                <div class="large-12 medium-12 small-12 cell">
                    <label>Name
                        <input type="text" placeholder="咖啡店名" v-model="name">
                    </label>
                </div>
                <div class="large-12 medium-12 small-12 cell">
                    <label>Address
                        <input type="text" placeholder="地址" v-model="address">
                    </label>
                </div>
                <div class="large-12 medium-12 small-12 cell">
                    <label>City
                        <input type="text" placeholder="城市" v-model="city">
                    </label>
                </div>
                <div class="large-12 medium-12 small-12 cell">
                    <label>State
                        <input type="text" placeholder="省份" v-model="state">
                    </label>
                </div>
                <div class="large-12 medium-12 small-12 cell">
                    <label>Zip
                        <input type="text" placeholder="邮编" v-model="zip">
                    </label>
                </div>
            </div>
        </div>
    </form>
</div>

至此,我们的表单组件已经构建完成了,它具备在模型数据和表单元素之间双向同步数据的功能。

运行 npm run dev 重新构建项目后就可以通过 http://roast.test/#/cafes/new 访问新增咖啡店页面了:

如果你打开开发者工具中 Vue 查看器,在表单中输入数据就可以看到数据会同步到数据模型中:

最后,我们为这个表单添加一个提交按钮,并为表单提交创建一个点击处理方法 submitNewCafe,完整代码如下:

<style>

</style>

<template>
    <div class="page">
        <form>
            <div class="grid-container">
                <div class="grid-x grid-padding-x">
                    <div class="large-12 medium-12 small-12 cell">
                        <label>名称
                            <input type="text" placeholder="咖啡店名" v-model="name">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <label>地址
                            <input type="text" placeholder="地址" v-model="address">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <label>城市
                            <input type="text" placeholder="城市" v-model="city">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <label>省份
                            <input type="text" placeholder="省份" v-model="state">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <label>邮编
                            <input type="text" placeholder="邮编" v-model="zip">
                        </label>
                    </div>
                    <div class="large-12 medium-12 small-12 cell">
                        <a class="button" v-on:click="submitNewCafe()">提交</a>
                    </div>
                </div>
            </div>
        </form>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                name: '',
                address: '',
                city: '',
                state: '',
                zip: ''
            }
        },
        methods: {
            submitNewCafe: function () {

            }
        }
    }
</script>

这样每次用户点击「提交」按钮,都会调用 submitNewCafe 方法来处理新增咖啡店操作(目前留空)。

第三步:提交新增的咖啡店数据

我们在上一步已经定义好了表单数据模型和视图,现在我们来编写 submitNewCafe 方法提交收集的表单数据。

由于我们是在 Vuex 模块上调用处理动作,所以需要在 Vuex 上分发一个 addCafe 动作方法(下一步实现该方法),同时以 JSON 对象方式将表单数据传递给该 addCafe 方法:

submitNewCafe: function () {
    this.$store.dispatch('addCafe', {
        name: this.name,
        address: this.address,
        city: this.city,
        state: this.state,
        zip: this.zip
    });
}

第四步:在 Vuex 模块中处理新增操作

很显然,我们紧接着要做的就是实现上一步中要分发的 addCafe 方法,打开 /resources/assets/js/modules/cafes.js 编辑 Vuex 模块 cafes

首先,需要添加一个变量 cafeAddStatusstate 以便跟踪咖啡店添加状态:

state: {
    cafes: [],
    cafesLoadStatus: 0,

    cafe: {},
    cafeLoadStatus: 0,

    cafeAddStatus: 0
},

然后,将 addCafe 方法添加到 actions 中,紧随 loadCafe 之后:

addCafe( { commit, state, dispatch }, data ){

}

需要注意的是 addCafe 的方法签名,第一个参数中包含了 dispatch,我们可以通过它从 Vuex 模块中分发动作,比如新增咖啡店后重新加载 Cafes 模块,第二个参数 data 就是我们在上一步传递过来的表单数据了。

我们已经在 通过 Axios 库构建 API 请求 这篇教程中定义好了前端 API 请求(位于 resources/assets/js/api/cafe.js),其中包含新增咖啡店请求,在 addCafe 方法中,我们将添加如下代码调用之前定义好的 API 发送请求:

addCafe( { commit, state, dispatch }, data ){
    // 状态1表示开始添加
    commit( 'setCafeAddStatus', 1 );

    CafeAPI.postAddNewCafe( data.name, data.address, data.city, data.state, data.zip )
            .then( function( response ){
                // 状态2表示添加成功
                commit( 'setCafeAddStatus', 2 );
                dispatch( 'loadCafes' );
            })
            .catch( function(){
                // 状态3表示添加失败
                commit( 'setCafeAddStatus', 3 );
            });
}

最后记得在 mutations 中新增 setCafeAddStatus 方法:

setCafeAddStatus(state, status) {
    state.cafeAddStatus = status;
}

getters 中新增 getCafeAddStatus 方法:

getCafeAddStatus( state) {
    return state.cafeAddStatus;
}

至此,前端工作已经全部完成了。

第五步:回顾 Laravel 的处理并构建应用

相应的 Laravel 后端 API 也已经在 实现 Laravel 后端 API 接口 这篇教程中定义好了:POST /api/v1/cafes。所以我们现在要做的就是通过 npm run dev 重新构建前端资源文件并通过 http://roast.test/#/cafes/new 页面新增一个咖啡店:

点击「提交」按钮,添加成功后就可以在数据库看到新增的数据了:

访问首页 http://roast.test/#/home,在 Vue 组件和 Vuex 模块中也都可以看到刚刚新增的咖啡店了:

至此,我们已经成功在 Roast 应用中通过提交表单完成新增咖啡店的功能。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 为 Vue Router 添加页面布局

>> 下一篇: 通过 JavaScript 和 Laravel 验证表单请求