前两个月一直学习 vue,node.js, 但没有真正地动手做项目, 恰好赶上公司要求我们做一个的登录注册的独立运行系统, 趁着这个机会学习巩固下自己之前学的内容. 前端使用 vue, 后端用 Express 做服务端提供数据接口, 数据库用 MySql. 实现对数据库的增改查操作.
demo 要求
完成一套可以独立运行的前端系统, 包括注册, 登录, 个人中心 3 个功能模块.
1. 不限定开发技术和开发框架.
2. 用户包括以下信息: 用户名称, 账号名称, 密码, 密码重复, 邮箱, 手机, 身份证, 出生日期, 性别
3. 注册时需要对用户信息进行非空校验和格式校验, 两次密码一致性校验, 表单提交需要注意防重复提交
4. 登录时需要有验证码, 需要对验证码正确性进行校验, 验证码校验失败自动更新验证码, 提供手动更新验证码操作
5. 登录成功展示个人中心, 提供修改个人信息操作, 退出操作, 修改密码操作
附加: 个人中心提供头像以及修改头像功能
准备工作
- node.js https://nodejs.org/zh-cn/
- https://www.mysql.com/
- https://git-scm.com/
- http://www.expressjs.com.cn/
- element-UI http://element.eleme.io/#/
目录结构
首先介绍下项目的目录结构
vue-cli 创建一个基于 webpack 的 Vue 登录注册系统项目
首先全局安装:
npm install -g vue-cli
安装依赖, 实现在 package.json 中对应添加相应的版本, 然后执行 npm install
- "dependencies": {
- "axios": "^0.15.3",
- "babel-polyfill": "^6.23.0",
- "body-parser": "^1.18.2",
- "element-ui": "1.3.1",
- "mysql": "^2.15.0",
- "vue": "^2.3.2",
- "vue-core-image-upload": "2.1.11",
- "vue-datasource": "1.0.9",
- "vue-router": "^2.3.1",
- },
服务端配置
在项目根文件夹下创建一个 service 文件夹. 然后创建下面四个文件: db/db.js --- 用来添加 MySQL 配置
- module.exports = {
- mysql: {
- host: 'localhost',
- user: 'root',
- password: '',
- port: '3306',
- database: 'login'
- }
- }
app.js --- Express 服务器入口文件
- const userApi = require('./api/userApi');
- const fs = require('fs');
- const path = require('path');
- const bodyParser = require('body-parser');
- const express = require('express');
- const app = express();
- app.use(bodyParser.json());
- app.use(bodyParser.urlencoded())
- app.use('/api/user', userApi);
- app.listen(3000);
- console.log('success listen at port: 3000')
db/sqlMap.js----SQL 语句映射文件, 这里主要是对数据库的增改查操作.
- var sqlMap = {
- user: {
- add: 'insert into user (username, account, password, repeatPass, email, phone, card, birth, sex) values (?,?,?,?,?,?,?,?,?)',
- select_name: 'select * from user',
- update_user: 'update user set'
- }
- }
- module.exports = sqlMap;
其中查询语句一直有问题
select_name: 'select * from user where username = ?',
node 一直报错, 后来, 将 where username = ? 放在 api 中拼接 具体见下, 如果你有更好的解决方案, 也请多指教.
- router.post('/login', (req, res) =>{
- var sql_name = $sql.user.select_name;
- // var sql_password = $sql.user.select_password;
- var params = req.body;
- console.log(params);
- if (params.name) {
- sql_name += "where username ='" + params.name + "'";
- }
- var keywords = JSON.parse(Object.keys(params)[0]);
- conn.query(sql_name, params.name,
- function(err, result) {
- if (err) {
- console.log(err);
- }
- // console.log(result);
- if (result[0] === undefined) {
- res.send('-1') // 查询不出 username,data 返回 - 1
- } else {
- var resultArray = result[0];
- console.log(resultArray.password);
- // console.log(keywords);
- if (resultArray.password === keywords.password) {
- jsonWrite(res, result);
- } else {
- res.send('0') //username
- }
- }
- })
- });
api/userApi.js ---- 测试用 api 示例
- var models = require('../db/db');
- var express = require('express');
- var router = express.Router();
- var mysql = require('mysql');
- var $sql = require('../db/sqlMap');
- var conn = mysql.createConnection(models.mysql);
- conn.connect();
- var jsonWrite = function(res, ret) {
- if (typeof ret === 'undefined') {
- res.send('err');
- } else {
- console.log(ret);
- res.send(ret);
- }
- }
- // 增加用户接口
- router.post('/addUser', (req, res) = >{
- var sql = $sql.user.add;
- var params = req.body;
- console.log(params);
- conn.query(sql, [params.name, params.account, params.password, params.repeatPass, params.email, params.phone, params.card, params.birth, params.sex],
- function(err, result) {
- if (err) {
- console.log(err);
- }
- if (result) {
- jsonWrite(res, result);
- }
- })
- });
- // 查找用户接口
- router.post('/login', (req, res) = >{
- var sql_name = $sql.user.select_name;
- // var sql_password = $sql.user.select_password;
- var params = req.body;
- console.log(params);
- if (params.name) {
- sql_name += "where username ='" + params.name + "'";
- }
- var keywords = JSON.parse(Object.keys(params)[0]);
- conn.query(sql_name, params.name,
- function(err, result) {
- if (err) {
- console.log(err);
- }
- // console.log(result);
- if (result[0] === undefined) {
- res.send('-1') // 查询不出 username,data 返回 - 1
- } else {
- var resultArray = result[0];
- console.log(resultArray.password);
- // console.log(keywords);
- if (resultArray.password === keywords.password) {
- jsonWrite(res, result);
- } else {
- res.send('0') //username
- }
- }
- })
- });
- // 获取用户信息
- router.get('/getUser', (req, res) = >{
- var sql_name = $sql.user.select_name;
- // var sql_password = $sql.user.select_password;
- var params = req.body;
- console.log(params);
- if (params.name) {
- sql_name += "where username ='" + params.name + "'";
- }
- conn.query(sql_name, params.name,
- function(err, result) {
- if (err) {
- console.log(err);
- }
- // console.log(result);
- if (result[0] === undefined) {
- res.send('-1') // 查询不出 username,data 返回 - 1
- } else {
- jsonWrite(res, result);
- }
- })
- });
- // 更新用户信息
- router.post('/updateUser', (req, res) = >{
- var sql_update = $sql.user.update_user;
- var params = req.body;
- console.log(params);
- if (params.id) {
- sql_update += "email ='" + params.email + "',phone ='" + params.phone +
"',card ='" + params.card +
"',birth ='" + params.birth +
"',sex ='" + params.sex +
- "'where id ='"+ params.id + "'";
- }
- conn.query(sql_update, params.id, function(err, result) {
- if (err) {
- console.log(err);
- }
- console.log(result);
- if (result.affectedRows === undefined) {
- res.send('更新失败, 请联系管理员') // 查询不出 username,data 返回 - 1
- } else {
- res.send('ok');
- }
- })
- });
- // 更改密码
- router.post('/modifyPassword', (req, res) => {
- var sql_modify = $sql.user.update_user;
- var params = req.body;
- console.log(params);
- if (params.id) {
- sql_modify += "password ='" + params.pass +
- "',repeatPass ='" + params.checkPass +
- "'where id ='"+ params.id + "'";
- }
- conn.query(sql_modify, params.id, function(err, result) {
- if (err) {
- console.log(err);
- }
- // console.log(result);
- if (result.affectedRows === undefined) {
- res.send('修改密码失败, 请联系管理员') // 查询不出 username,data 返回 - 1
- } else {
- res.send('ok');
- }
- })
- });
- module.exports = router;
此时在 service 文件夹下执行 node app(这里也可以加载 package.json 中, 然后使用 npm 执行)看到 success listen at port:3000...... 即服务端启动成功.
vue 登录组件
这里主要介绍 登录 login.vue 组件
- <template>
- <div class="login-wrap">
- <div class="ms-title">登录管理系统</div>
- <div class="ms-login">
- <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="0px" class="demo-ruleForm">
- <div v-if="errorInfo">
- <span>{{errInfo}}</span>
- </div>
- <el-form-item prop="name">
- <el-input v-model="ruleForm.name" placeholder="账号"></el-input>
- </el-form-item>
- <el-form-item prop="password">
- <el-input type="password" placeholder="密码" v-model="ruleForm.password" @keyup.enter.native="submitForm('ruleForm')"></el-input>
- </el-form-item>
- <el-form-item prop="validate">
- <el-input v-model="ruleForm.validate" class="validate-code" placeholder="验证码"></el-input>
- <div class="code" @click="refreshCode">
- <s-identify :identifyCode="identifyCode"></s-identify>
- </div>
- </el-form-item>
- <div class="login-btn">
- <el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
- </div>
- <p style="font-size:14px;line-height:30px;color:#999;cursor: pointer;float:right;" @click="handleCommand()">注册</p>
- </el-form>
- </div>
- </div>
- </template>
- <script>
- export default {
- name: 'login',
- data() {
- return {
- identifyCodes: "1234567890",
- identifyCode: "",
- errorInfo : false,
- ruleForm: {
- name: '',
- password: '',
- validate: ''
- },
- rules: {
- name: [
- { required: true, message: '请输入用户名', trigger: 'blur' }
- ],
- password: [
- { required: true, message: '请输入密码', trigger: 'blur' }
- ],
- validate: [
- { required: true, message: '请输入验证码', trigger: 'blur' }
- ]
- }
- }
- },
- mounted() {
- this.identifyCode = "";
- this.makeCode(this.identifyCodes, 4);
- },
- methods: {
- submitForm(formName) {
- const self = this;
- self.$refs[formName].validate((valid) => {
- if (valid) {
- localStorage.setItem('ms_username',self.ruleForm.name);
- localStorage.setItem('ms_user',JSON.stringify(self.ruleForm));
- console.log(JSON.stringify(self.ruleForm));
- self.$http.post('/api/user/login',JSON.stringify(self.ruleForm))
- .then((response) => {
- console.log(response);
- if (response.data == -1) {
- self.errorInfo = true;
- self.errInfo = '该用户不存在';
- console.log('该用户不存在')
- } else if (response.data == 0) {
- console.log('密码错误')
- self.errorInfo = true;
- self.errInfo = '密码错误';
- } else if (response.status == 200) {
- self.$router.push('/readme');
- }
- }).then((error) => {
- console.log(error);
- })
- } else {
- console.log('error submit!!');
- return false;
- }
- });
- },
- handleCommand() {
- this.$router.push('/register');
- },
- randomNum(min, max) {
- return Math.floor(Math.random() * (max - min) + min);
- },
- refreshCode() {
- this.identifyCode = "";
- this.makeCode(this.identifyCodes, 4);
- },
- makeCode(o, l) {
- for (let i = 0; i <l; i++) {
- this.identifyCode += this.identifyCodes[
- this.randomNum(0, this.identifyCodes.length)
- ];
- }
- console.log(this.identifyCode);
- }
- }
- }
- </script>
- <style scoped>
- .login-wrap{
- position: relative;
- width:100%;
- height:100%;
- }
- .ms-title{
- position: absolute;
- top:50%;
- width:100%;
- margin-top: -230px;
- text-align: center;
- font-size:30px;
- color: #fff;
- }
- .ms-login{
- position: absolute;
- left:50%;
- top:50%;
- width:300px;
- height:240px;
- margin:-150px 0 0 -190px;
- padding:40px;
- border-radius: 5px;
- background: #fff;
- }
- .ms-login span {
- color: red;
- }
- .login-btn{
- text-align: center;
- }
- .login-btn button{
- width:100%;
- height:36px;
- }
- .code {
- width: 112px;
- height: 35px;
- border: 1px solid #ccc;
- float: right;
- border-radius: 2px;
- }
- .validate-code {
- width: 136px;
- float: left;
- }
- </style>
设置代理与跨域
执行完上述 3 步之后, 在根目录下执行 npm run dev ,, 然后输入一组数据, 点击保存, 你会发现会报一个错误: vue-resource.common.js?e289:1071 POST http://localhost:8082/api/user/login 404 (Not Found). 这是由于直接访问 8082 端口, 是访问不到的, 所以这里需要设置一下代理转发映射.
vue-cli 的 config 文件中有一个 proxyTable 参数, 用来设置地址映射表, 可以添加到开发时配置 (dev) 中
- dev: {
- // ...
- proxyTable: {
- '/api': {
- target: 'http://127.0.0.1:3000/api/',
- changeOrigin: true,
- pathRewrite: {
- '^/api': ''
- }
- }
- },
- // ...
- }
即请求 / api 时就代表 http://127.0.0.1:3000/api/(这里要写 ip, 不要写 localhost), changeOrigin 参数接收一个布尔值, 如果为 true, 这样就不会有跨域问题了.
项目中要求防止多次提交, 实际上就是防抖操作: 具体请移步 节流和防抖 https://github.com/sakila1012/blog/issues/17
项目运行
- // 本地开发
- // 开启前端服务, 浏览器访问 http://localhost:8082
- npm run dev
- // 开启后端服务
- cd service
- node app
一整天加一个下午, 终于调通了, 在数据库那边遇到了好多问题, 不过经过不断的尝试终于解决了.
效果图
源码 https://github.com/sakila1012/vue-login-manage-system 不当之处, 还请指正, 欢迎 star
参考了以下 https://github.com/lin-xin/vue-manage-system , 海岛心 hey https://segmentfault.com/a/1190000008176208#articleHeader1 , 罗坤 https://segmentfault.com/a/1190000011288053
来源: https://www.thinksaas.cn/group/topic/839585/