零基础快速开发Vue图书管理系统—登录注册篇(一)

简介: 前端主要采用:Vue3.x (vuex/vue-router)、Ant Design Vue、Axios等

零基础快速开发Vue图书管理系统—登录注册篇(一)

一、图书管理系统项目功能

2345_image_file_copy_482.jpg

二、项目技术选型

  • 前端主要采用:Vue3.x (vuex/vue-router)、Ant Design Vue、Axios
  • 服务端主要采用:Node.js、Koa、Mongoose
  • 数据库主要采用:MongoDB

2345_image_file_copy_483.jpg

三、使用vue-cli3创建项目

2345_image_file_copy_484.jpg

四、搭建所需的文件

在view的目录下新建Auth文件夹,里面分别放以下三个文件

2345_image_file_copy_485.jpg

前端UI框架主要采用Ant Design Vue

2345_image_file_copy_486.jpg

2345_image_file_copy_487.jpg

😛index.vue内容如下

<template>
    <div class="auth">
        <div class="bg"></div>
        <div class="title-info">
            <img src="https://ncstatic.clewm.net/rsrc/2020/1016/02/4757e4910cb527fc040d019a93ded74f.png?x-oss-process=image/resize,w_750/format,gif/sharpen,100/quality,Q_80/interlace,1/auto-orient,1"
                alt="">
            <h2 class="title">图书后台管理系统</h2>
        </div>
        <div class="form">
            <a-tabs>
                <a-tab-pane key="1" tab="登录">
                    <div class="item">
                        <a-input size="large" placeholder="账户">
                            <template v-slot:prefix>
                                <UserOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a-input size="large" placeholder="密码">
                            <template v-slot:prefix>
                                <LockOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a href="">忘记密码</a>
                    </div>
                    <div class="item">
                        <a-button size="large" type="primary">
                            登录
                        </a-button>
                    </div>
                </a-tab-pane>
                <a-tab-pane key="2" tab="注册">
                    <div class="item">
                        <a-input size="large" placeholder="账户">
                            <template v-slot:prefix>
                                <UserOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a-input size="large" placeholder="密码">
                            <template v-slot:prefix>
                                <LockOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a-input size="large" placeholder="邀请码">
                            <template v-slot:prefix>
                                <MailOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a-button size="large" type="primary">
                            注册
                        </a-button>
                    </div>
                </a-tab-pane>
            </a-tabs>
        </div>
    </div>
</template>
<script src="./index.js">
</script>
<style lang="scss" scoped>
    @import './index.scss'
</style>

😅index.scss内容如下:

.bg {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    background-image: url("https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg");
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center center;
}
.auth {
    .title-info {
        display: flex;
        margin-top: 100px;
        text-align: center;
        align-items: center;
        justify-content: center;
        margin-bottom: 32px;
        img {
            width: 60px;
            height: 60px;
        }
        h2 {
            margin: 0;
            margin-left: 18px;
        }
    }
    .form {
        width: 400px;
        margin: 0 auto;
        .item {
            margin-bottom: 16px;
            button {
                width: 100%;
            }
        }
    }
}

🤣index.js内容如下:

 import { defineComponent } from 'vue';
 import { UserOutlined, LockOutlined, MailOutlined } from '@ant-design/icons-vue';
 export default defineComponent({
     components: {
         UserOutlined,
         LockOutlined,
         MailOutlined
     },
     setup() {
     }
 });

五、服务端开发

执行以下命令安装koa

npm i @koa/router

服务端文件结构如下:

2345_image_file_copy_488.jpg

2345_image_file_copy_498.jpg

2345_image_file_copy_499.jpg

2345_image_file_copy_500.jpg

2345_image_file_copy_501.jpg

六、nodemon使用

编写调试Node的时候,项目代码做了修改,需要频繁手动停止,在重新启动,非常繁琐,使用nodemon能够监听项目文件的变动,当代码被修改后,nodemon会自动重启项目,极大方便了开发和调试

在终端中,运行如下命令,即可将nodemon安装为全局可用的工具:

npm install -g nodemon
  • 传统的方式是运行node app.js命令启动项目,需要手动重启
  • 现在将node命令替换为nodemon命令,使用nodemon app.js启动项目,会自动重启

七、使用JWT和Session实现登录注册

2345_image_file_copy_502.jpg

2345_image_file_copy_503.jpg

2345_image_file_copy_504.jpg

📢📢📢登录部分(服务端)

2345_image_file_copy_505.jpg

2345_image_file_copy_506.jpg

核心代码如下:

const Router = require('@koa/router');
const mongoose = require('mongoose');
const { getBody } = require('../../helpers/utils')
const jwt = require('jsonwebtoken');
const User = mongoose.model('User');
const router = new Router({
    prefix: '/auth',
});
router.post('/register', async(ctx) => {
    // console.log(ctx.request.body);
    const {
        account,
        password,
    } = getBody(ctx);
    const one = await User.findOne({
        account,
    }).exec();
    if (one) {
        ctx.body = {
            code: 0,
            msg: '已存在该用户',
            data: null,
        }
        return;
    }
    const user = new User({
        account,
        password
    });
    const res = await user.save();
    ctx.body = {
        code: 1,
        msg: '注册成功',
        data: res,
    }
});
router.post('/login', async(ctx) => {
    const {
        account,
        password,
    } = getBody(ctx);
    const one = await User.findOne({
        account,
    }).exec();
    if (!one) {
        ctx.body = {
            code: 0,
            msg: '用户名或者密码错误',
            data: null,
        }
        return;
    }
    const user = {
        account: one.account,
        _id: one._id,
    }
    if (one.password === password) {
        ctx.body = {
            code: 1,
            msg: '登录成功',
            data: {
                user,
                token: jwt.sign(user, 'manage')
            },
        }
        return;
    }
    ctx.body = {
        code: 0,
        msg: '用户名或密码错误',
        data: null,
    }
});
module.exports = router;

📢📢📢登录部分(前端)

2345_image_file_copy_507.jpg

2345_image_file_copy_508.jpg

核心代码:

 import { defineComponent, reactive } from 'vue';
 import { UserOutlined, LockOutlined, MailOutlined } from '@ant-design/icons-vue';
 import { auth } from '@/service';
 export default defineComponent({
     components: {
         UserOutlined,
         LockOutlined,
         MailOutlined,
     },
     setup() {
         //注册相关的逻辑
         const regForm = reactive({
                 account: '',
                 password: '',
             })
             //注册逻辑
         const register = () => {
                 auth.register(regForm.account, regForm.password)
             }
             //登录相关的逻辑
         const loginForm = reactive({
             account: '',
             password: '',
         });
         //登录逻辑
         const login = () => {
             auth.login(loginForm.account, loginForm.password)
         }
         return {
             //注册相关的数据
             register,
             regForm,
             //登录相关的数据
             login,
             loginForm,
         }
     }
 });

index.vue

2345_image_file_copy_509.jpg

<template>
    <div class="auth">
        <div class="bg"></div>
        <div class="title-info">
            <img src="https://ncstatic.clewm.net/rsrc/2020/1016/02/4757e4910cb527fc040d019a93ded74f.png?x-oss-process=image/resize,w_750/format,gif/sharpen,100/quality,Q_80/interlace,1/auto-orient,1"
                alt="">
            <h2 class="title">图书后台管理系统</h2>
        </div>
        <div class="form">
            <a-tabs>
                <a-tab-pane key="1" tab="登录">
                    <div class="item">
                        <a-input 
                        v-model:value="loginForm.account"
                        size="large" 
                        placeholder="账户">
                            <template v-slot:prefix>
                                <UserOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a-input 
                        v-model:value="loginForm.password"
                        size="large" 
                        placeholder="密码">
                            <template v-slot:prefix>
                                <LockOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a href="">忘记密码</a>
                    </div>
                    <div class="item">
                        <a-button 
                        @click="login"
                        size="large" 
                        type="primary">
                            登录
                        </a-button>
                    </div>
                </a-tab-pane>
                <a-tab-pane key="2" tab="注册">
                    <div class="item">
                        <a-input 
                        size="large"
                        placeholder="账户"
                        v-model:value="regForm.account"
                        >
                            <template v-slot:prefix>
                                <UserOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a-input 
                        size="large" 
                        placeholder="密码"
                        v-model:value="regForm.password"
                        >
                            <template v-slot:prefix>
                                <LockOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a-input size="large" placeholder="邀请码">
                            <template v-slot:prefix>
                                <MailOutlined />
                            </template>
                        </a-input>
                    </div>
                    <div class="item">
                        <a-button 
                        size="large" 
                        type="primary"
                        @click="register">
                            注册
                        </a-button>
                    </div>
                </a-tab-pane>
            </a-tabs>
        </div>
    </div>
</template>
<script src="./index.js">
</script>
<style lang="scss" scoped>
    @import './index.scss'
</style>

八、交互优化、表单校验、处理请求结果优化

登录注册逻辑校验

2345_image_file_copy_510.jpg

2345_image_file_copy_511.jpg

2345_image_file_copy_512.jpg

2345_image_file_copy_513.jpg

2345_image_file_copy_514.jpg

2345_image_file_copy_515.jpg

九、邀请码实现,完善注册流程

2345_image_file_copy_516.jpg

2345_image_file_copy_517.jpg

const Router = require('@koa/router');
const mongoose = require('mongoose');
const { getBody } = require('../../helpers/utils')
const jwt = require('jsonwebtoken');
const User = mongoose.model('User');
const InviteCode = mongoose.model('InviteCode');
const router = new Router({
    prefix: '/auth',
});
router.post('/register', async(ctx) => {
    const {
        account,
        password,
        inviteCode,
    } = getBody(ctx);
    //表单校验
    if (account === '' || password === '' || inviteCode === '') {
        ctx.body = {
            code: 0,
            msg: '字段不能为空',
            data: null,
        }
        return;
    }
    //找是否有邀请码
    const findCode = await InviteCode.findOne({
        code: inviteCode,
    }).exec();
    //如果没有找到邀请码
    if ((!findCode) || findCode.user) {
        ctx.body = {
            code: 0,
            msg: '邀请码不正确',
            data: null,
        }
        return;
    }
    //去找account为传递上来的account的用户
    const findUser = await User.findOne({
        account,
    }).exec();
    //判断是否有用户
    if (findUser) {
        //如果有表示已经存在
        ctx.body = {
            code: 0,
            msg: '已存在该用户',
            data: null,
        }
        return;
    }
    //创建用户
    const user = new User({
        account,
        password
    });
    //把创建的用户同步到mongdb
    const res = await user.save();
    findCode.user = res._id;
    findCode.meta.updatedAt = new Date().getTime();
    await findCode.save();
    //响应成功
    ctx.body = {
        code: 1,
        msg: '注册成功',
        data: res,
    }
});
router.post('/login', async(ctx) => {
    const {
        account,
        password,
    } = getBody(ctx);
    if (account === '' || password === '') {
        ctx.body = {
            code: 0,
            msg: '字段不能为空',
            data: null,
        }
        return;
    }
    const one = await User.findOne({
        account,
    }).exec();
    if (!one) {
        ctx.body = {
            code: 0,
            msg: '用户名或者密码错误',
            data: null,
        }
        return;
    }
    const user = {
        account: one.account,
        _id: one._id,
    }
    if (one.password === password) {
        ctx.body = {
            code: 1,
            msg: '登录成功',
            data: {
                user,
                token: jwt.sign(user, 'manage')
            },
        }
        return;
    }
    ctx.body = {
        code: 0,
        msg: '用户名或密码错误',
        data: null,
    }
});
module.exports = router;
相关文章
|
1月前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
6天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
1月前
|
JavaScript 前端开发 开发者
Vue是如何劫持响应式对象的
Vue是如何劫持响应式对象的
29 1
|
1月前
|
JavaScript 前端开发 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
1月前
|
存储 JavaScript 前端开发
介绍一下Vue的核心功能
介绍一下Vue的核心功能
|
1月前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
1月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
39 1
vue学习第一章
|
1月前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
30 1
|
1月前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
38 1
vue学习第四章
|
1月前
|
JavaScript 前端开发 算法
vue学习第7章(循环)
欢迎来到瑞雨溪的博客,一名热爱JavaScript和Vue的大一学生。本文介绍了Vue中的v-for指令,包括遍历数组和对象、使用key以及数组的响应式方法等内容,并附有综合练习实例。关注我,将持续更新更多优质文章!🎉🎉🎉
25 1
vue学习第7章(循环)