零基础快速开发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;
相关文章
|
8天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
7天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
7天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
22天前
|
数据采集 监控 JavaScript
在 Vue 项目中使用预渲染技术
【10月更文挑战第23天】在 Vue 项目中使用预渲染技术是提升 SEO 效果的有效途径之一。通过选择合适的预渲染工具,正确配置和运行预渲染操作,结合其他 SEO 策略,可以实现更好的搜索引擎优化效果。同时,需要不断地监控和优化预渲染效果,以适应不断变化的搜索引擎环境和用户需求。
|
8天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
8天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
8天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
9天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
9天前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
14天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发

相关实验场景

更多