Vue+Vant+Koa2+MongoDB实现用户注册
今天我们来实现一个用户注册的页面,在上一篇入门教程的基础上新增代码(当前的项目目录结构请参考上一篇教程),我们将原先 Vue 生成的默认页面中 About 页面替换为 注册页面 (效果图如下) 。我们从零开始,从最初的新建前端表单,到数据的后端验证存储,检测数据库中是否已经存在注册用户,若存在则提示 “该用户已注册” ,若不存在则提示 “注册成功” 。
一、前端部分
前端运用 Vue + Vant,首先我们完成第一步,编写 Register 表单
1.1 我们在 mall\src\components 目录下新建 Register.vue 文件,
在 <template> </template> 标签内添加:
<div id="register"> <van-form> <van-field v-model="username" label="用户名" placeholder="请输入用户名" :rules="[{required: true, message: '请填写用户名'}]" /> <van-field v-model="password" type = "password" label="密码" placeholder="请输入密码" :rules="[{required: true, message: '请输入密码'}]" /> <van-field v-model="telnumber" label="手机号码" placeholder="请输入手机号码" :rules="[{required: true, message: '请输入手机号码'}]" /> <div style="margin: 16px;"> <van-button square block type="info" native-type="submit" size="normal" @click="onSubmit"> 提交 </van-button> </div> </van-form> </div>
注:在表单中,除了提交按钮外,可能还有一些其他的功能性按钮,如发送验证码按钮。在使用这些按钮时,要注意将 native-type
设置为 button
,否则会触发表单提交。
这个问题的原因是浏览器中 button 标签 type 属性的默认值为submit
,导致触发表单提交。我们会在下个大版本中将 type 的默认值调整为 button
来避免这个问题。
在 <script> </script> 标签内添加:
import { Field } from 'vant'; import { Button } from 'vant'; import { Toast } from 'vant'; import { Form } from 'vant'; export default { components:{ [Field.name]: Field, [Button.name]: Button, [Toast.name]: Toast, [Form.name]: Form, }, data() { return { username: '', password: '', telnumber: '' } } }
1.2 修改 router\index.js,
顶端添加 :
import Register from '../components/Register.vue'
添加 routes 路由参数:
{ path: '/register', name: 'Register', component: Register },
1.3 修改 App.vue :
<router-link to="/about">About</router-link>
将上面的代码修改为:
<router-link to="/register">注册</router-link>
此时,重新运行 Vue 项目,可以看到页面:
二、 通过 axios 实现前端向后端传递数据
当用户填写完毕注册信息,点击提交按钮后,前端会将注册信息通过 axios 发送给后端服务器,并获取到返回信息,具体实现如下:
2.1 在 Register.vue 中 新增 提交按钮事件:
import ajax from '@/api'; //首先引入ajax类
methods: { async onSubmit() { // async修饰符非常重要,表示该函数为异步执行 let { username, password, telnumber } = this.$data; //获取表单中的数据 let res = await ajax.register(username, password, telnumber); //await表示该语句等待 await后的语句有返回了之后,再接着执行 onSubmit的语句 console.log(res) },
}
也许你会发现 ajax.register 目前为止还是未定义的,不着急,接下来我们就会编写 ajax 类。
2.2 编写 ajax 类,修改 mall\src\api\index.js ,添加如下代码:
// 注册 | POST register(username, password, telnumber) { return axios.post('http://localhost:3000/users/registerUser',{username, password, telnumber}) }
OK,到这里我们的前端部分就基本完成了,下面我们进行后端部分开发。
三、后端 Koa2 部分
后端部分的主要实现逻辑:
1> 新建 user 数据集合存储用户信息,
2> 编写 router.post 路由接收前端数据,
3> 后端验证注册信息并存储返回
3.1 新建 mongDB 数据集合
在 mall-server 文件夹下新建 models 文件夹,新建 user.js :
const mongoose = require('mongoose'); var Schema = mongoose.Schema; var userSchema = new Schema({ username: {type: String, unique: true}, password: String, telnumber: String }); module.exports = mongoose.model('User',userSchema)
进一步,我们不可以直接存储明文密码,这样安全性得不到保障,因此在存储前,需要对密码进行加密,用的 bcryptjs,在 user.js 里继续添加:
const bcrypt = require('bcryptjs'); // 用于密码哈希的加密算法
/** * 对密码进行加盐 * 使用 pre 中间件在用户信息存储前执行 */ userSchema.pre('save', function(next) { // 进行加密 | 产生一个 salt bcrypt.genSalt(SALT_WORK_FACTOR, (err, salt) => { if (err) return next(err); // 结合 salt 产生新的hash bcrypt.hash(this.password, salt, (err, hash) => { if (err) return next(err); // 使用 hash 覆盖明文密码 this.password = hash; next(); }); }); });
此时我们的数据模型已经新建完毕,若对 mongoDB 不熟悉的小伙伴,可以翻阅我之前的文章有介绍说明。
3.2 编写 router.post 路由接收前端数据
修改 routes\user.js , 添加代码:
const userService = require('../service/user'); //引入userService类 会在下一步编写,主要用于向数据库中存储用户注册信息
router.post('/registerUser', async function (ctx) { let {username, password, telnumber} = ctx.request.body; //koa-bodyparser 解析request.body if(!username || !password || !telnumber) return ctx.body = {code: 4020,msg: '请填写完整的注册信息'}; let args = {username, password, telnumber}; const userData = await userService.accountHandle(args); //userService类会在下一步编写 ctx.body = (userData.code === 200) ? {code: 200, msg: '注册成功'} : userData })
3.3 编写 userService 类,用于后端验证注册信息并存储返回
在 mall-server 文件夹下新建,user.js :
const UserModel = require('../models/user') //引入 model class userService { async accountHandle({username, password, telnumber}) { const user = await UserModel.findOne({username}) if (user) return { code: 0, msg: '该用户已经注册' }; //若用户已存在,停止向下执行,并返回错误提示信息 let userEntity = new UserModel({ username, password, telnumber }); // 保存到数据库中 let userInfo = await userEntity.save(); return { code: 200, username: userInfo.username, password: userInfo.password, telnumber: userInfo.telnumber } } } module.exports = new userService(); // 导出这个类,注意与ES6导出类写法的差别
OK ,到这里,我们就基本实现了用户注册的功能,当然还有不完善的地方,比如需要添加手机号正则验证、短信验证码、axios 添加响应拦截器、JWT 认证,将会在下面的文章中一起研究。当然,有不正确的地方,欢迎大家留意指正。