优秀的编程知识分享平台

网站首页 > 技术文章 正文

用vue3实现一个简单的登录功能

nanyue 2025-01-21 20:25:52 技术文章 7 ℃

以前用react写过一个登录页面,不过实际工作中还是决定使用vue进行开发,这里就再记录一次用vue3实现一个登录页面。

演示准备

还是采用VSCode,暂时就个人感受来讲,免费的前端编程ide中,VSCode应该是首选。安装一下npm、pnpm,准备一些后端接口,可以用mock,或者随便找点后端框架写一点,我是用python flask在本地弄了一些需要的接口。

实操演示-创建工程

到工作目录打开cmd界面,通过命令新建一个vue项目工程:

npm create vue@latest

然后就是根据提示选择是否添加组件:

项目虽然创建成功了,但是里面是没有引入各种资源库的,需要通过命令安装一下:

此时可以通过命令启动这个新建的项目:

可以通过浏览器访问:

界面能正常显示出来,就表示项目创建成功。

实操演示-依赖库添加

先添加sass,这个库可以让我们更灵活的写css,我自己不算是前端开发,写css其实不是很频繁,但是看其他几个前端开发都挺喜欢用sass的。

通过命令添加:

再添加一个axios,这个是用来请求后端接口的:

最后再加一个element-plus,做这个登录页面,用不用element-plus都可以,可以根据自己喜好添加element-plus或者ant-design-vue都可以,都是类似功能的组件。

实操演示-清理不需要的内容

将新建项目时自动带入的一些组件、图片、样式文件等删除:

这些删除的文件在留存的代码中有对应的引用,也删除一下,可以通过运行项目,看哪边报错,找对应位置进行修改:

还有些比较复杂的,可以直接清除原内容,还原成一些基础代码,比如App.vue:

网上找一个reset.scss(npm的官网上就有),清除当前所有默认样式:

引用这个reset.scss:

这里的@路径别称是项目创建时自动配置的,可以在vite.config.ts中看到:

实操演示-静态结构搭建

如果刚开始没什么思路,可以到element-plus的官网上抄类似的代码:

只需要在外层配一个背景,改一下参数名称,其实就可以用了。

因为从element-plus上抄了代码,所以要配置对应的样式,和使用对应的组件:

我为了和后面登录效果做铺垫,先在App.vue中加一个路由组件:

因为要使用路由,所以要在main.tx中使用路由模块:

配置路由信息:

要写一个登录页面:

<script setup lang="ts">
import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
import { ref, reactive } from 'vue';
import { useRouter } from 'vue-router';

const router = useRouter()
const url = ref('/images/favicon.ico')
const fit = 'scale-down'
const boxbg = ref('/images/login-box-bg.svg')


const form = reactive({
    userName: '',
    passWord: ''
})

const rules = reactive<FormRules>({
    userName: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
    passWord: [{ required: true, message: '请输入密码', trigger: 'blur' }]
})
const ruleFormRef = ref<FormInstance>()
const onSubmit = async (ruleFormRef: FormInstance | undefined) => {
    if (!ruleFormRef) return;
    await ruleFormRef.validate(async (valid, fields) => {
        if (valid) {
            // 这里要调用后端接口,根据后端返回的值,决定是否走后面的路由进入系统内部
            router.push({ path: '/desktop' });
        } else {
            let errors: string = "";
            fields?.userName?.forEach(element => {
                errors += element.message + '; '
            })
            fields?.passWord?.forEach(element => {
                errors += element.message + '; '
            })
            ElMessage({
                type: "warning",
                message: errors
            })
        }
    })
}

</script>

<template>
    <div class="login">
        <div class="relative">
            <div class="left">
                <el-row>
                    <el-col :span="24">
                        <div class="homepageLogo">
                            <ul>
                                <li>
                                    <el-image style="width: 50px; height: 40px;" :src="url" :fit="fit" />
                                </li>
                                <li><span>Allure System</span></li>
                            </ul>
                        </div>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col>
                        <el-image class="boxgb" :src="boxbg" :fit="fit" />
                        <p class="p1">欢迎使用本系统</p>
                        <p class="p2">一个很潦草的后端管理系统</p>
                    </el-col>
                </el-row>
            </div>
            <div class="right">
                <el-row>
                    <el-col :span="24">
                        <h2>登录</h2>
                    </el-col>
                </el-row>
                <el-row>
                    <el-col :span="24">
                        <el-form :model="form" label-width="120px" label-position="top" size="large" class="form"
                            :rules="rules" ref="ruleFormRef">
                            <el-form-item label="用户名" prop="userName">
                                <el-input v-model="form.userName"></el-input>
                            </el-form-item>
                            <el-form-item label="密码" prop="passWord">
                                <el-input v-model="form.passWord" type="password" show-password></el-input>
                            </el-form-item>
                            <el-form-item>
                                <el-button class="submitBtn" type="primary" @click="onSubmit(ruleFormRef)">登录</el-button>
                            </el-form-item>
                        </el-form>
                    </el-col>
                </el-row>
            </div>
        </div>
    </div>
</template>

<style lang="scss" scoped>
.login {
    width: 100%;
    height: 100%;

    .relative {
        width: 100%;
        height: 100%;
        text-align: center;

        .left {
            width: 50%;
            height: 100%;
            float: left;
            background-image: url('/images/login-bg.jpg');

            .boxbg {
                width: 350px;
                height: 350px;
                margin-top: 100px;
            }

            .homepageLogo {
                height: 50px;
                line-height: 50px;
                margin-top: 40px;
                margin-left: 40px;

                span {
                    color: white;
                    font-size: 24px;
                }

                ul {
                    list-style: none;

                    li {
                        float: left;
                        margin-left: 5px;
                    }
                }
            }

            p {
                color: white;
            }

            .p1 {
                font-size: 1.875rem;
                line-height: 2.825rem;
            }

            .p2 {
                font-size: 0.875rem;
                line-height: 1.25rem;
            }
        }

        .right {
            width: 50%;
            float: left;
            padding-top: 15%;

            .form {
                width: 50%;
                margin: 0px auto;

                .submitBtn {
                    width: 100%;
                }
            }
        }
    }
}
</style>

实现效果就是这样:

实操演示-后端交互封装

使用axios封装一下filter.ts:

//导入axios
import axios from 'axios'
import { ElMessage } from 'element-plus'
//创建一个axios实例 
const instance = axios.create({
    withCredentials: true,
    headers: {
        'content-type': 'application/json,text/plain,*/*'
    },
    // withCredentials: true,
    timeout: 5000  //5秒
})
instance.interceptors.request.use(
    config => {
        return config
    },
    error => {
        ElMessage.error("遇到报错:", error)
    }
)
//http 拦截器
instance.interceptors.response.use(
    response => {
        console.log(response.data)
        //拦截请求,统一相应
        if (response.data.isSuccess) {
            return response.data.result
        } else {
            ElMessage.error(response.data.msg)
            return response.data.result
        }
    },
    //error也可以处理
    error => {
        console.log(error)
        if (error.response) {
            switch (error.response.status) {
                case 401:
                    ElMessage.warning("资源没有访问权限!")
                    break
                case 404:
                    ElMessage.warning("接口不存在,请检查接口地址是否正确!")
                    break
                case 500:
                    ElMessage.warning("内部服务器错误,请联系系统管理员!")
                    break
                default:
                    return Promise.reject(error.response.data)   // 返回接口返回的错误信息 
            }
        }
        else {
            ElMessage.error("遇到跨域错误,请设置代理或者修改后端允许跨域访问!")
        }
    }
)
export default instance

在根据上面封装的filter.ts,写一下获取token的请求:

//需要拦截器的地方使用instance对象, 有自定义返回逻辑的地方沿用axios,在组件内部处理返回结果即可
import instance from './filter'
const http = "/api";

//获取token
export const getToken = (name: string, password: string) => {
    return instance.get(http + "/Login/GetToken?name=" + name + "&password=" + password);
}

应该会遇到跨域问题,所以上面没有写具体url,到vite.config.ts中配置代理:

回到LoginPage.vue,调用getToken方法:

这个token是我随便写的,正常的需要经过一些转换才能读取其中的信息。

如果token中还有其他信息,也可以存储到本地cookie中,当然如果token要被经常使用到,也可以直接将token持久化,比如这样:

总结

一个潦草的登录模块就这样做好了。当然一个完整的登录模块,还有很多鉴权、路由控制等很多功能,这里就不展开了。

最近发表
标签列表