前言

学无止境,无止境学。大家好,我是张大鹏,之前在抖音有5万多粉丝,不过现在不拍视频,专心写公众号了。笔者目前是高级Python工程师,之前是全栈工程师,主要擅长Golang和Python开发,对于Java,Vue,React也有一些研究。工作之余,喜欢学习和分享,希望能够通过此公众号"张大鹏520",将自己学到的东西分享给大家,和大家一起交流,一起成长,一起进步。

今天要给大家分享的是《前后端分离电商管理系统实战07 实现并完善用户登录功能》,这是一个系列的教程,从零基础到项目实战。在本教程中,我会给大家介绍如何使用vue3实现用户登录的完整功能。主要包括以下知识点:

  • 创建登录页面

  • 登录页面布局

  • 添加登录页面元素

  • 美化登录页面

  • 引入图标

  • 登录输入框添加图标

  • 用户登录表单校验

  • 整合axios发送请求

  • 引入cookie

  • 配置axios拦截器

  • 常用工具库封装

  • 使用vuex管理用户信息

  • 登录权限校验

  • 完善登录功能

  • 实现退出登录的功能

  • 全局loading进度条实现

  • 实现动态页面标题

如果大家需要本教程的PDF电子书或者完整的源码,可以在文末找到获取方式哈。

创建登录页面

创建pages/login.vue,作为我们的登录页面:

<template>
    <div>
        登录
    </div>
</template>

在router/index.js中配置登录的路由:

//引入依赖
import{createRouter,createWebHashHistory}from"vue-router";
//引入页面
importIndexfrom"@/pages/index.vue";
importNotFoundfrom"@/pages/404.vue";
importLoginfrom"@/pages/login.vue";

//路由数组
constroutes=[
//首页
{path:"/",name:"Index",component:Index},
//404错误页面
{path:"/:pathMatch(.*)*",name:"NotFound",component:NotFound},
//登录页面
{path:"/login",name:"Login",component:Login},
];

//创建路由
constrouter=createRouter({
history:createWebHashHistory(),
routes,
});

//导出路由
exportdefaultrouter;

浏览器访问:http://localhost:5173/#/login

登录页面布局

使用element-plus和windicss配合,我们可以轻松的实现登录界面的左右布局:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :span="16">
                左
            </el-col>

            <!-- 右侧 -->
            <el-col :span="8" class="bg-light-50">
                右
            </el-col>
        </el-row>
    </div>
</template>

此时的页面显示效果如下:

image-20221112131719762

这样,我们就实现了一个基本的左右布局样式。

添加登录页面元素

修改pages/login.vue,我们添加登录需要的基本元素:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :span="16" class="flex items-center justify-center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p>基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :span="8" class="flex flex-col bg-light-50 items-center justify-center">
                <h2>欢迎回来</h2>
                <div>
                    <span></span>
                    <span>账号密码登录</span>
                    <span></span>
                </div>
                <el-form :model="form">
                    <el-form-item>
                        <el-input v-model="form.username" placeholder="请输入用户名" />
                    </el-form-item>
                    <el-form-item>
                        <el-input v-model="form.password" placeholder="请输入密码" />
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" @click="onSubmit">登 录</el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { reactive } from 'vue'

const form = reactive({
    username: '',
    password: '',
})

const onSubmit = () => {
    console.log('submit!')
}
</script>

修改以后,整个页面的布局基本如下:

美化登录界面

接着,我们给登录界面的元素添加一些样式,继续修改pages/login.vue,添加样式:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :span="16" class="flex items-center justify-center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :span="8" class="flex flex-col bg-light-50 items-center justify-center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5 text-gray-300 items-center justify-center">
                    <span class="bg-gray-200 h-[1px] w-16"></span>
                    <span>账号密码登录</span>
                    <span class="bg-gray-200 h-[1px] w-16"></span>
                </div>

                <!-- 表单 -->
                <el-form :model="form" class="w-[250px]">
                    <el-form-item>
                        <el-input v-model="form.username" placeholder="请输入用户名" />
                    </el-form-item>
                    <el-form-item>
                        <el-input v-model="form.password" placeholder="请输入密码" />
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { reactive } from 'vue'

const form = reactive({
    username: '',
    password: '',
})

const onSubmit = () => {
    console.log('submit!')
}
</script>

这里需要对这里面的一些样式做一些讲解,参考文档:https://cn.windicss.org/utilities/general/typography.html

flex items-center justify-centerbg-gray-200 h-[1px] w-16w-[250px]

整个页面美化后如下:

引入图标

安装element plus的图标:

#选择一个你喜欢的包管理器

#NPM
$npminstall@element-plus/icons-vue
#Yarn
$yarnadd@element-plus/icons-vue
#pnpm
$pnpminstall@element-plus/icons-vue

接着修改main.js,引入element-plus的图标:

import{createApp}from"vue";
importAppfrom"./App.vue";
importElementPlusfrom"element-plus";
import"element-plus/dist/index.css";
importrouterfrom"./router";
import*asElementPlusIconsVuefrom"@element-plus/icons-vue";

constapp=createApp(App);

app.use(router);
app.use(ElementPlus);

//引入element-plus的图标
for(const[key,component]ofObject.entries(ElementPlusIconsVue)){
app.component(key,component);
}

//注意,位置不是在顶部
import"virtual:windi.css";

app.mount("#app");

登录输入框添加图标

参考文档,我们在登录页面的输入框中添加图标。

修改pages/login.vue,添加图标:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :lg="16" :md="12" class="flex items-center justify-center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :lg="8" :md="12" class="flex flex-col bg-light-50 items-center justify-center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5 text-gray-300 items-center justify-center">
                    <span class="bg-gray-200 h-[1px] w-16"></span>
                    <span>账号密码登录</span>
                    <span class="bg-gray-200 h-[1px] w-16"></span>
                </div>

                <!-- 表单 -->
                <el-form :model="form" class="w-[250px]">
                    <el-form-item>
                        <el-input v-model="form.username" placeholder="请输入用户名">
                            <!-- 使用前缀插槽插入element-plus的图标 -->
                            <template #prefix>
                                <el-icon class="el-input__icon">
                                    <User />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-input v-model="form.password" placeholder="请输入密码">
                            <template #prefix>
                                <el-icon class="el-input__icon">
                                    <Lock />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { reactive } from 'vue'
// 引入element-plus的图标
import { User, Lock } from '@element-plus/icons-vue'
const form = reactive({
    username: '',
    password: '',
})

const onSubmit = () => {
    console.log('submit!')
}
</script>

添加图标以后的登录界面效果如下:

实际上,咱们在开始配置的时候进行了全局引入,所以图标使用的时候,不再显式的引入也是可以的,所以登录界面可以改写为如下代码:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :lg="16" :md="12" class="flex items-center justify-center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :lg="8" :md="12" class="flex flex-col bg-light-50 items-center justify-center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5 text-gray-300 items-center justify-center">
                    <span class="bg-gray-200 h-[1px] w-16"></span>
                    <span>账号密码登录</span>
                    <span class="bg-gray-200 h-[1px] w-16"></span>
                </div>

                <!-- 表单 -->
                <el-form :model="form" class="w-[250px]">
                    <el-form-item>
                        <el-input v-model="form.username" placeholder="请输入用户名">
                            <!-- 使用前缀插槽插入element-plus的图标 -->
                            <template #prefix>
                                <el-icon>
                                    <User />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-input v-model="form.password" placeholder="请输入密码">
                            <template #prefix>
                                <el-icon>
                                    <Lock />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { reactive } from 'vue'
const form = reactive({
    username: '',
    password: '',
})

const onSubmit = () => {
    console.log('submit!')
}
</script>

用户登录表单校验

我们实现如下功能:

  • 用户名不能为空,用户名长度为3-36

  • 密码不能为空,密码长度为6-72

这个时候,我们需要用到element-plus给我们提供的表单校验功能,修改pages/login.vue,完整代码如下:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :lg="16" :md="12" class="center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :lg="8" :md="12" class="flex-col bg-light-50  center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5  text-gray-300">
                    <span class="line"></span>
                    <span>账号密码登录</span>
                    <span class="line"></span>
                </div>

                <!-- 表单 -->
                <el-form ref="formRef" :model="form" :rules="rules" class="w-[250px]">
                    <el-form-item prop="username">
                        <el-input v-model="form.username" placeholder="请输入用户名">
                            <!-- 使用前缀插槽插入element-plus的图标 -->
                            <template #prefix>
                                <el-icon>
                                    <User />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item prop="password">
                        <el-input v-model="form.password" type="password" placeholder="请输入密码" show-password>
                            <template #prefix>
                                <el-icon>
                                    <Lock />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

// 表单引用
const formRef = ref(null)

// 表单属性
const form = reactive({
    username: '',
    password: '',
})

// 表单规则
const rules = reactive({
    username: [
        { required: true, message: '用户名不能为空', trigger: 'blur' },
        { min: 2, max: 36, message: '用户名长度为2到36', trigger: 'blur' },
    ],
    password: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 6, max: 72, message: '密码长度为6到72', trigger: 'blur' },
    ],
})

const onSubmit = () => {
    // 校验表单内容
    formRef.value.validate((valid) => {
        console.log(valid)
    })
}
</script>

<style scoped>
.line {
    @apply bg-gray-200 h-[1px] w-16;
}

.center {
    @apply flex items-center justify-center;
}
</style>

整合axios发送请求

安装:

npminstallaxios

创建utils/axios.js,对axios做一个基本的封装:

importaxiosfrom"axios";

//创建实例
constapi=axios.create({
baseURL:"/api",
});

//导出实例
exportdefaultapi;

修改vite.config.js,配置用户代理,解决跨域问题:

//https://vitejs.dev/config/
import{defineConfig}from"vite";
importvuefrom"@vitejs/plugin-vue";
importWindiCSSfrom"vite-plugin-windicss";
importpathfrom"path";

exportdefaultdefineConfig({
//配置解析模块
resolve:{
//配置别名
alias:{
"@":path.resolve(__dirname,"src"),
},
},
//服务配置
server:{
//代理
proxy:{
"/api":{
target:"http://192.168.101.2:8889/api/v1",
changeOrigin:true,
rewrite:(path)=>path.replace(/^\/api/,""),
},
},
},
plugins:[vue(),WindiCSS()],
});

创建api/auth.js,封装登录接口:

//权限管理模块相关的api接口
importapifrom"@/utils/axios";

//登录接口
exportfunctionlogin(username,password){
returnapi.post("/auth/login",{username,password});
}

修改login.vue,使用登录接口,登录并跳转到首页:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :lg="16" :md="12" class="center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :lg="8" :md="12" class="flex-col bg-light-50  center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5  text-gray-300">
                    <span class="line"></span>
                    <span>账号密码登录</span>
                    <span class="line"></span>
                </div>

                <!-- 表单 -->
                <el-form ref="formRef" :model="form" :rules="rules" class="w-[250px]">
                    <el-form-item prop="username">
                        <el-input v-model="form.username" placeholder="请输入用户名">
                            <!-- 使用前缀插槽插入element-plus的图标 -->
                            <template #prefix>
                                <el-icon>
                                    <User />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item prop="password">
                        <el-input v-model="form.password" type="password" placeholder="请输入密码" show-password>
                            <template #prefix>
                                <el-icon>
                                    <Lock />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from "vue-router"
import { login } from "@/api/auth"
import { ElNotification } from "element-plus"

// 路由器
const router = useRouter()

// 表单引用
const formRef = ref(null)

// 表单属性
const form = reactive({
    username: '',
    password: '',
})

// 表单规则
const rules = reactive({
    username: [
        { required: true, message: '用户名不能为空', trigger: 'blur' },
        { min: 2, max: 36, message: '用户名长度为2到36', trigger: 'blur' },
    ],
    password: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 6, max: 72, message: '密码长度为6到72', trigger: 'blur' },
    ],
})

// 点击登录按钮触发的方法
const onSubmit = () => {
    // 校验表单内容
    formRef.value.validate((valid) => {
        if (!valid) {
            return false
        }

        // 调用登录方法
        let that = this;
        login(form.username, form.password)
            .then((res) => {
                console.log(res)
                let data = res.data;
                if (data.status && data.code === 10000) {
                    console.log("登录成功")
                    ElNotification({
                        message: "登录成功",
                        type: "success",
                        duration: 3000,
                    })
                    router.push("/")
                } else {
                    ElNotification({
                        message: data.msg,
                        type: "error",
                        duration: 3000,
                    })
                }
            })
            .catch((err) => {
                console.log(err)
                ElNotification({
                    message: err.response.data.msg || "请求失败",
                    type: "error",
                    duration: 3000,
                })
            })
    })
}
</script>

<style scoped>
.line {
    @apply bg-gray-200 h-[1px] w-16;
}

.center {
    @apply flex items-center justify-center;
}
</style>

引入cookie

安装依赖:

npmi@vueuse/core
npmi@vueuse/integrations
npmiuniversal-cookie

cookie的官方使用示例如下:

<template>
  <div>
    <strong>locale</strong>: {{ cookies.get('locale') }}
    <hr>
    <pre>{{ cookies.getAll() }}</pre>
    <button @click="cookies.set('locale', 'ru-RU')">Russian</button>
    <button @click="cookies.set('locale', 'en-US')">English</button>
  </div>
</template>

<script>
  import { defineComponent } from 'vue'
  import { useCookies } from '@vueuse/integrations/useCookies'

  export default defineComponent({
    setup() {
      const cookies = useCookies(['locale'])
      return {
        cookies,
      }
    },
  })
</script>

修改pages/login.vue,我们在登录成功以后,引入cookie,使用cookie存储用户的token:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :lg="16" :md="12" class="center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :lg="8" :md="12" class="flex-col bg-light-50  center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5  text-gray-300">
                    <span class="line"></span>
                    <span>账号密码登录</span>
                    <span class="line"></span>
                </div>

                <!-- 表单 -->
                <el-form ref="formRef" :model="form" :rules="rules" class="w-[250px]">
                    <el-form-item prop="username">
                        <el-input v-model="form.username" placeholder="请输入用户名">
                            <!-- 使用前缀插槽插入element-plus的图标 -->
                            <template #prefix>
                                <el-icon>
                                    <User />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item prop="password">
                        <el-input v-model="form.password" type="password" placeholder="请输入密码" show-password>
                            <template #prefix>
                                <el-icon>
                                    <Lock />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from "vue-router"
import { login } from "@/api/auth"
import { ElNotification } from "element-plus"
import { useCookies } from '@vueuse/integrations/useCookies'

// cookie 缓存器
const cookie = useCookies()

// 路由器
const router = useRouter()

// 表单引用
const formRef = ref(null)

// 表单属性
const form = reactive({
    username: '',
    password: '',
})

// 表单规则
const rules = reactive({
    username: [
        { required: true, message: '用户名不能为空', trigger: 'blur' },
        { min: 2, max: 36, message: '用户名长度为2到36', trigger: 'blur' },
    ],
    password: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 6, max: 72, message: '密码长度为6到72', trigger: 'blur' },
    ],
})

// 点击登录按钮触发的方法
const onSubmit = () => {
    // 校验表单内容
    formRef.value.validate((valid) => {
        if (!valid) {
            return false
        }

        // 调用登录方法
        let that = this;
        login(form.username, form.password)
            .then((res) => {
                console.log(res)
                let data = res.data;
                if (data.status && data.code === 10000) {
                    console.log("登录成功", data)
                    ElNotification({
                        message: "登录成功",
                        type: "success",
                        duration: 3000,
                    })
                    cookie.set("shop-admin-token", data.data.token)
                    router.push("/")
                } else {
                    ElNotification({
                        message: data.msg,
                        type: "error",
                        duration: 3000,
                    })
                }
            })
            .catch((err) => {
                console.log(err)
                ElNotification({
                    message: err.response.data.msg || "请求失败",
                    type: "error",
                    duration: 3000,
                })
            })
    })
}
</script>

<style scoped>
.line {
    @apply bg-gray-200 h-[1px] w-16;
}

.center {
    @apply flex items-center justify-center;
}
</style>

配置Axios拦截器

我们可以通过配置Axios拦截器的方式,在请求的前后添加统一的处理逻辑,比如错误处理,请求头添加等。

修改utils/axios.js,添加拦截器:

importaxiosfrom"axios";
import{ElNotification}from"element-plus";
import{useCookies}from"@vueuse/integrations/useCookies";

//创建实例
constapi=axios.create({
baseURL:"/api",
});

//请求拦截器
api.interceptors.request.use(
//拦截配置
function(config){
//自动添加cookie
constcookie=useCookies();
consttoken=cookie.get("shop-admin-token");
if(token){
config.headers["zdppy-auth-token"]=token;
}
returnconfig;
},

//拦截错误
function(error){
returnPromise.reject(error);
}
);
//响应拦截器
api.interceptors.response.use(
//拦截成功
function(response){
console.log("拦截成功:",response);
letdata=response.data;
if(data.status&&data.code===10000){
returndata.data;
}else{
ElNotification({
message:data.msg,
type:"error",
duration:3000,
});
returnPromise.reject(response);
}
},

//拦截失败
function(error){
returnPromise.reject(error);
}
);

//导出实例
exportdefaultapi;

修改pages/login.vue,简化登录请求的处理逻辑:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :lg="16" :md="12" class="center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :lg="8" :md="12" class="flex-col bg-light-50  center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5  text-gray-300">
                    <span class="line"></span>
                    <span>账号密码登录</span>
                    <span class="line"></span>
                </div>

                <!-- 表单 -->
                <el-form ref="formRef" :model="form" :rules="rules" class="w-[250px]">
                    <el-form-item prop="username">
                        <el-input v-model="form.username" placeholder="请输入用户名">
                            <!-- 使用前缀插槽插入element-plus的图标 -->
                            <template #prefix>
                                <el-icon>
                                    <User />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item prop="password">
                        <el-input v-model="form.password" type="password" placeholder="请输入密码" show-password>
                            <template #prefix>
                                <el-icon>
                                    <Lock />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef"
                            :loading="loginBtnLoading" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from "vue-router"
import { login } from "@/api/auth"
import { ElNotification } from "element-plus"
import { useCookies } from '@vueuse/integrations/useCookies'

// cookie 缓存器
const cookie = useCookies()

// 路由器
const router = useRouter()

// 表单引用
const formRef = ref(null)

// 登录按钮加载状态
const loginBtnLoading = ref(false)

// 表单属性
const form = reactive({
    username: '',
    password: '',
})

// 表单规则
const rules = reactive({
    username: [
        { required: true, message: '用户名不能为空', trigger: 'blur' },
        { min: 2, max: 36, message: '用户名长度为2到36', trigger: 'blur' },
    ],
    password: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 6, max: 72, message: '密码长度为6到72', trigger: 'blur' },
    ],
})

// 点击登录按钮触发的方法
const onSubmit = () => {

    // 校验表单内容
    formRef.value.validate((valid) => {
        if (!valid) {
            return false;
        }
        loginBtnLoading.value = true;

        // 调用登录方法
        login(form.username, form.password)
            .then((data) => {
                console.log("登录成功", data)
                ElNotification({
                    message: "登录成功",
                    type: "success",
                    duration: 3000,
                })
                cookie.set("shop-admin-token", data.token)
                router.push("/")
            })
            .finally(() => {
                loginBtnLoading.value = false;
            })
    })
}
</script>

<style scoped>
.line {
    @apply bg-gray-200 h-[1px] w-16;
}

.center {
    @apply flex items-center justify-center;
}
</style>

常用工具库封装

封装cookie操作工具库:utils/cookie.js

import{useCookies}from"@vueuse/integrations/useCookies";

consttokenKey="zdppy-auth-token";
constcookie=useCookies();

//获取token
exportfunctiongetToken(){
returncookie.get(tokenKey);
}

//设置token
exportfunctionsetToken(token){
returncookie.set(tokenKey,token);
}

//清除token
exportfunctionremoveToken(){
returncookie.remove(tokenKey);
}

封装消息提示工具库:utils/message.js

import{ElNotification}from"element-plus";

//提示信息
exportfunctiontoast(message,type="success",isHtml=false){
ElNotification({
message,
type,
dangerouslyUseHTMLString:isHtml,//是否作为HTML片段处理
duration:3000,
});
}

修改pages/login.vue,使用工具库简化代码:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :lg="16" :md="12" class="center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :lg="8" :md="12" class="flex-col bg-light-50  center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5  text-gray-300">
                    <span class="line"></span>
                    <span>账号密码登录</span>
                    <span class="line"></span>
                </div>

                <!-- 表单 -->
                <el-form ref="formRef" :model="form" :rules="rules" class="w-[250px]">
                    <el-form-item prop="username">
                        <el-input v-model="form.username" placeholder="请输入用户名">
                            <!-- 使用前缀插槽插入element-plus的图标 -->
                            <template #prefix>
                                <el-icon>
                                    <User />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item prop="password">
                        <el-input v-model="form.password" type="password" placeholder="请输入密码" show-password>
                            <template #prefix>
                                <el-icon>
                                    <Lock />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef"
                            :loading="loginBtnLoading" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from "vue-router"
import { login } from "@/api/auth"
import { ElNotification } from "element-plus"
import { setToken } from "@/utils/cookie"
import { toast } from "@/utils/message"

// 路由器
const router = useRouter()

// 表单引用
const formRef = ref(null)

// 登录按钮加载状态
const loginBtnLoading = ref(false)

// 表单属性
const form = reactive({
    username: '',
    password: '',
})

// 表单规则
const rules = reactive({
    username: [
        { required: true, message: '用户名不能为空', trigger: 'blur' },
        { min: 2, max: 36, message: '用户名长度为2到36', trigger: 'blur' },
    ],
    password: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 6, max: 72, message: '密码长度为6到72', trigger: 'blur' },
    ],
})

// 点击登录按钮触发的方法
const onSubmit = () => {

    // 校验表单内容
    formRef.value.validate((valid) => {
        if (!valid) {
            return false;
        }
        loginBtnLoading.value = true;

        // 调用登录方法
        login(form.username, form.password)
            .then((data) => {
                console.log("登录成功", data)
                toast("登录成功")
                setToken(data.token)
                router.push("/")
            })
            .finally(() => {
                loginBtnLoading.value = false;
            })
    })
}
</script>

<style scoped>
.line {
    @apply bg-gray-200 h-[1px] w-16;
}

.center {
    @apply flex items-center justify-center;
}
</style>

修改utils/axios.js,使用工具库简化代码:

importaxiosfrom"axios";
import{getToken}from"./cookie";
import{toast}from"./message";

//创建实例
constapi=axios.create({
baseURL:"/api",
});

//请求拦截器
api.interceptors.request.use(
//拦截配置
function(config){
//自动添加token
config.headers["zdppy-auth-token"]=getToken()||"";
returnconfig;
},

//拦截错误
function(error){
returnPromise.reject(error);
}
);
//响应拦截器
api.interceptors.response.use(
//拦截成功
function(response){
console.log("拦截成功:",response);
letdata=response.data;
if(data.status&&data.code===10000){
returndata.data;
}else{
toast(data.msg,"error");
returnPromise.reject(response);
}
},

//拦截失败
function(error){
returnPromise.reject(error);
}
);

//导出实例
exportdefaultapi;

使用vuex管理用户信息

安装:

npminstallvuex@next--save

创建store/index.js,提供基本的状态管理器:

import{createStore}from"vuex";

//创建一个新的store实例
conststore=createStore({
state(){
return{
//用户信息
user:{},
};
},
mutations:{
//记录用户信息
setUserinfo(state,user){
state.user=user;
},
},
});

exportdefaultstore;

修改main.js,引入vuex并使用:

import{createApp}from"vue";
importAppfrom"./App.vue";
importElementPlusfrom"element-plus";
import"element-plus/dist/index.css";
importrouterfrom"./router";
importstorefrom"./store";
import*asElementPlusIconsVuefrom"@element-plus/icons-vue";

constapp=createApp(App);

app.use(router);
app.use(store);
app.use(ElementPlus);

//引入element-plus的图标
for(const[key,component]ofObject.entries(ElementPlusIconsVue)){
app.component(key,component);
}

//注意,位置不是在顶部
import"virtual:windi.css";

app.mount("#app");

修改pages/login.vue,在登录成功以后,记录用户基本信息:

<template>
<div>
<el-rowclass="min-h-screenbg-indigo-500">
<!--左侧-->
<el-col:lg="16":md="12"class="center">
<div>
<h1class="font-boldmb-4text-5xltext-light-50">欢迎使用商城后台管理系统</h1>
<pclass="text-basetext-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
</div>
</el-col>

<!--右侧-->
<el-col:lg="8":md="12"class="flex-colbg-light-50center">
<h2class="font-boldtext-3xltext-gray-800">欢迎回来</h2>
<divclass="flexspace-x-1my-5text-gray-300">
<spanclass="line"></span>
<span>账号密码登录</span>
<spanclass="line"></span>
</div>

<!--表单-->
<el-formref="formRef":model="form":rules="rules"class="w-[250px]">
<el-form-itemprop="username">
<el-inputv-model="form.username"placeholder="请输入用户名">
<!--使用前缀插槽插入element-plus的图标-->
<template#prefix>
<el-icon>
<User/>
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-itemprop="password">
<el-inputv-model="form.password"type="password"placeholder="请输入密码"show-password>
<template#prefix>
<el-icon>
<Lock/>
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-buttonclass="w-[250px]"type="primary"@click="onSubmit"color="#626aef"
:loading="loginBtnLoading"round>登录
</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</template>

<scriptsetup>
import{ref,reactive}from'vue'
import{useRouter}from"vue-router"
import{useStore}from"vuex"
import{login}from"@/api/auth"
import{setToken}from"@/utils/cookie"
import{toast}from"@/utils/message"

//路由器
constrouter=useRouter()
//状态管理器
conststore=useStore()

//表单引用
constformRef=ref(null)

//登录按钮加载状态
constloginBtnLoading=ref(false)

//表单属性
constform=reactive({
username:'',
password:'',
})

//表单规则
construles=reactive({
username:[
{required:true,message:'用户名不能为空',trigger:'blur'},
{min:2,max:36,message:'用户名长度为2到36',trigger:'blur'},
],
password:[
{required:true,message:'密码不能为空',trigger:'blur'},
{min:6,max:72,message:'密码长度为6到72',trigger:'blur'},
],
})

//点击登录按钮触发的方法
constonSubmit=()=>{

//校验表单内容
formRef.value.validate((valid)=>{
if(!valid){
returnfalse;
}
loginBtnLoading.value=true;

//调用登录方法
login(form.username,form.password)
.then((data)=>{
store.commit("setUserinfo",{id:data.id,username:data.username})
toast("登录成功")
setToken(data.token)
router.push("/")
})
.finally(()=>{
loginBtnLoading.value=false;
})
})
}
</script>

<stylescoped>
.line{
@applybg-gray-200h-[1px]w-16;
}

.center{
@applyflexitems-centerjustify-center;
}
</style>

修改index.vue,访问状态管理器中的用户信息:

<template>
    <div>
        后台首页
        <h1>欢迎您:{{ $store.state.user }}</h1>
    </div>
</template>
<script setup>
</script>

登录权限校验

需求:如果用户未登录,我们则让其跳转到登录页面,如果已登录,但是又访问了登录页面,则直接跳转到首页或者原来的页面。

创建utils/permission.js,作为权限库:

importrouterfrom"@/router";
import{getToken}from"./cookie";
import{toast}from"./message";

//全局前置守卫
router.beforeEach((to,from,next)=>{
console.log("全局前置守卫:",to,from);

//如果没有登录,就跳转到登录页面
consttoken=getToken();
if(!token&&to.path!="/login"){
toast("请先登录","error");
returnnext({path:"/login"});
}

//防止重复登录
if(token&&to.path=="/login"){
toast("您已经登录过","warning");
returnnext({path:from.path?from.path:"/"});
}

next();
});

在main.js中引入使用即可:

import{createApp}from"vue";
importAppfrom"./App.vue";
importElementPlusfrom"element-plus";
import"element-plus/dist/index.css";
importrouterfrom"./router";
importstorefrom"./store";
import*asElementPlusIconsVuefrom"@element-plus/icons-vue";

constapp=createApp(App);

app.use(router);
app.use(store);
app.use(ElementPlus);

//引入element-plus的图标
for(const[key,component]ofObject.entries(ElementPlusIconsVue)){
app.component(key,component);
}

//注意,位置不是在顶部
import"virtual:windi.css";
import"@/utils/permission";

app.mount("#app");

完善登录功能

需求:

  • 1、用户登录以后,获取用户信息

  • 2、刷新页面以后,用户信息不会丢失

  • 3、按Enter键的时候,触发登录方法

修改api/auth.js,添加获取用户信息的接口:

//权限管理模块相关的api接口
importapifrom"@/utils/axios";

//登录接口
exportfunctionlogin(username,password){
returnapi.post("/auth/login",{username,password});
}

//获取用户信息接口
exportfunctiongetUserinfo(){
returnapi.get("/auth/userinfo");
}

修改store/index.js,封装用户登录和获取用户信息的action:

import{createStore}from"vuex";
import{login,getUserinfo}from"@/api/auth";
import{setToken}from"@/utils/cookie";

//创建一个新的store实例
conststore=createStore({
state(){
return{
//用户信息
user:{},
};
},
mutations:{
//记录用户信息
setUserinfo(state,user){
state.user=user;
},
},
actions:{
//登录
storeLogin({commit},{username,password}){
returnnewPromise((resolve,reject)=>{
login(username,password)
.then((data)=>{
setToken(data.token);
resolve(data);
})
.catch((err)=>reject(err));
});
},
//获取用户信息
storeGetUserinfo({commit}){
returnnewPromise((resolve,reject)=>{
getUserinfo()
.then((data)=>{
commit("setUserinfo",data);
resolve(data);
})
.catch((err)=>reject(err));
});
},
},
});

exportdefaultstore;

修改utils/permission.js,如果用户已登录,自动获取用户信息:

importrouterfrom"@/router";
importstorefrom"@/store";
import{getToken}from"./cookie";
import{toast}from"./message";

//全局前置守卫
router.beforeEach(async(to,from,next)=>{
console.log("全局前置守卫:",to,from);

//如果没有登录,就跳转到登录页面
consttoken=getToken();
if(!token&&to.path!="/login"){
toast("请先登录","error");
returnnext({path:"/login"});
}

//防止重复登录
if(token&&to.path=="/login"){
toast("您已经登录过","warning");
returnnext({path:from.path?from.path:"/"});
}

//如果用户登录了,就自动获取用户信息并存储在vuex中
if(token){
awaitstore.dispatch("storeGetUserinfo");
}

//路由继续前行
next();
});

修改pages/login.vue,优化登录相关的逻辑:

<template>
    <div>
        <el-row class="min-h-screen bg-indigo-500">
            <!-- 左侧 -->
            <el-col :lg="16" :md="12" class="center">
                <div>
                    <h1 class="font-bold mb-4 text-5xl text-light-50">欢迎使用商城后台管理系统</h1>
                    <p class="text-base text-gray-200">基于Vue3+Vite+ElementPlus+Windicss等主流技术研发</p>
                </div>
            </el-col>

            <!-- 右侧 -->
            <el-col :lg="8" :md="12" class="flex-col bg-light-50  center">
                <h2 class="font-bold text-3xl text-gray-800">欢迎回来</h2>
                <div class="flex space-x-1 my-5  text-gray-300">
                    <span class="line"></span>
                    <span>账号密码登录</span>
                    <span class="line"></span>
                </div>

                <!-- 表单 -->
                <el-form ref="formRef" :model="form" :rules="rules" class="w-[250px]">
                    <el-form-item prop="username">
                        <el-input v-model="form.username" placeholder="请输入用户名">
                            <!-- 使用前缀插槽插入element-plus的图标 -->
                            <template #prefix>
                                <el-icon>
                                    <User />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item prop="password">
                        <el-input v-model="form.password" type="password" placeholder="请输入密码" show-password>
                            <template #prefix>
                                <el-icon>
                                    <Lock />
                                </el-icon>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="w-[250px]" type="primary" @click="onSubmit" color="#626aef"
                            :loading="loginBtnLoading" round>登 录
                        </el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>

<script setup>
import { ref, reactive, onMounted, onBeforeMount } from 'vue'
import { useRouter } from "vue-router"
import { useStore } from "vuex"
import { toast } from "@/utils/message"

// 路由器
const router = useRouter()
// 状态管理器
const store = useStore()

// 表单引用
const formRef = ref(null)

// 登录按钮加载状态
const loginBtnLoading = ref(false)

// 表单属性
const form = reactive({
    username: '',
    password: '',
})

// 表单规则
const rules = reactive({
    username: [
        { required: true, message: '用户名不能为空', trigger: 'blur' },
        { min: 2, max: 36, message: '用户名长度为2到36', trigger: 'blur' },
    ],
    password: [
        { required: true, message: '密码不能为空', trigger: 'blur' },
        { min: 6, max: 72, message: '密码长度为6到72', trigger: 'blur' },
    ],
})

// 点击登录按钮触发的方法
const onSubmit = () => {

    // 校验表单内容
    formRef.value.validate((valid) => {
        if (!valid) {
            return false;
        }
        loginBtnLoading.value = true;

        // 使用vuex的axtions简化登录逻辑
        store.dispatch("storeLogin", form)
            .then((data) => {
                toast("登录成功")
                router.push("/")
            })
            .finally(() => {
                loginBtnLoading.value = false;
            })
    })
}

// 监听回车事件
function onKeyUp(e) {
    if (e.key === "Enter") onSubmit()
}

// 添加键盘监听
onMounted(() => {
    document.addEventListener("keyup", onKeyUp)
})

// 移除键盘监听
onBeforeMount(() => {
    document.removeEventListener("keyup", onKeyUp)
})

</script>

<style scoped>
.line {
    @apply bg-gray-200 h-[1px] w-16;
}

.center {
    @apply flex items-center justify-center;
}
</style>

实现退出登录的功能

修改api/auth.js,封装请求后端注销接口的方法:

//权限管理模块相关的api接口
importapifrom"@/utils/axios";

//登录接口
exportfunctionlogin(username,password){
returnapi.post("/auth/login",{username,password});
}

//获取用户信息接口
exportfunctiongetUserinfo(){
returnapi.get("/auth/userinfo");
}

//注销接口
exportfunctionlogout(){
returnapi.put("/auth/logout");
}

修改store/index.js,封装一个退出登录的action:

import{createStore}from"vuex";
import{login,getUserinfo}from"@/api/auth";
import{setToken,removeToken}from"@/utils/cookie";

//创建一个新的store实例
conststore=createStore({
state(){
return{
//用户信息
user:{},
};
},
mutations:{
//记录用户信息
setUserinfo(state,user){
state.user=user;
},
},
actions:{
//登录
storeLogin({commit},{username,password}){
returnnewPromise((resolve,reject)=>{
login(username,password)
.then((data)=>{
setToken(data.token);
resolve(data);
})
.catch((err)=>reject(err));
});
},
//获取用户信息
storeGetUserinfo({commit}){
returnnewPromise((resolve,reject)=>{
getUserinfo()
.then((data)=>{
commit("setUserinfo",data);
resolve(data);
})
.catch((err)=>reject(err));
});
},
//退出登录
storeLogout({commit}){
removeToken();
commit("setUserinfo",{});
},
},
});

exportdefaultstore;

修改index.vue,我们简单的实现退出登录的逻辑:

<template>
    <div>
        后台首页
        <h1>欢迎您:{{ $store.state.user }}</h1>
        <el-button @click="handleLogout">退出登录</el-button>
    </div>
</template>
<script setup>
import { confirm, toast } from '@/utils/message';
import { logout } from "@/api/auth"
import { useRouter } from "vue-router"
import { useStore } from "vuex"

const router = useRouter()
const store = useStore()

function handleLogout() {
    console.log("注销")
    confirm("是否要退出登录?").then(r => {
        console.log("确认:", r);
        logout()
            .finally(() => {
                store.dispatch("storeLogout")
                toast("退出登录成功")
                router.push("/login")
            })
    })
}
</script>

全局loading进度条实现

安装依赖:

npminprogress

在main.js中引入样式:

import{createApp}from"vue";
importAppfrom"./App.vue";
importElementPlusfrom"element-plus";
import"element-plus/dist/index.css";
importrouterfrom"./router";
importstorefrom"./store";
import*asElementPlusIconsVuefrom"@element-plus/icons-vue";

constapp=createApp(App);

app.use(router);
app.use(store);
app.use(ElementPlus);

//引入element-plus的图标
for(const[key,component]ofObject.entries(ElementPlusIconsVue)){
app.component(key,component);
}

//注意,位置不是在顶部
import"virtual:windi.css";
import"@/utils/permission";
import"nprogress/nprogress.css";

app.mount("#app");

在App.vue中修改进度条颜色:

<script setup></script>

<template>
  <div>
    <router-view></router-view>
  </div>
</template>

<style>
/* 全局进度条颜色 */
#nprogress .bar {
  background-color: #f4f4f4 !important;
  height: 3px !important;
}
</style>

在utils/message.js中封装动画方法:

import{ElNotification,ElMessageBox}from"element-plus";
importnprogressfrom"nprogress";

//提示信息
exportfunctiontoast(message,type="success",isHtml=false){
ElNotification({
message,
type,
dangerouslyUseHTMLString:isHtml,//是否作为HTML片段处理
duration:3000,
});
}

//弹出确认框
exportfunctionconfirm(content="提示内容",type="warning",title=""){
returnElMessageBox.confirm(content,title,{
confirmButtonText:"确认",
cancelButtonText:"取消",
type,
});
}

//显示全屏loading
exportfunctionshowFullLoading(){
nprogress.start();
}

//隐藏全屏loading
exportfunctionhideFullLoading(){
nprogress.done();
}

在utils/permission.js中配置动画,在每个路由开始之前加载动画,每个路由结束以后结束动画:

importrouterfrom"@/router";
importstorefrom"@/store";
import{getToken}from"./cookie";
import{toast,showFullLoading,hideFullLoading}from"./message";

//全局前置守卫
router.beforeEach(async(to,from,next)=>{
//显示全屏加载动画
showFullLoading();

//如果没有登录,就跳转到登录页面
consttoken=getToken();
if(!token&&to.path!="/login"){
toast("请先登录","error");
returnnext({path:"/login"});
}

//防止重复登录
if(token&&to.path=="/login"){
toast("您已经登录过","warning");
returnnext({path:from.path?from.path:"/"});
}

//如果用户登录了,就自动获取用户信息并存储在vuex中
if(token){
awaitstore.dispatch("storeGetUserinfo");
}

//路由继续前行
next();
});

//全局后置守卫
router.afterEach((to,from)=>{
//隐藏全屏加载动画
hideFullLoading();
});

实现动态页面标题

修改router/index.js,给每个路由都设置一个title:

//引入依赖
import{createRouter,createWebHashHistory}from"vue-router";
//引入页面
importIndexfrom"@/pages/index.vue";
importNotFoundfrom"@/pages/404.vue";
importLoginfrom"@/pages/login.vue";

//路由数组
constroutes=[
//首页
{path:"/",name:"Index",component:Index,meta:{title:"后台首页"}},
//404错误页面
{
path:"/:pathMatch(.*)*",
name:"NotFound",
component:NotFound,
meta:{title:"404"},
},
//登录页面
{
path:"/login",
name:"Login",
component:Login,
meta:{title:"后台登录页"},
},
];

//创建路由
constrouter=createRouter({
history:createWebHashHistory(),
routes,
});

//导出路由
exportdefaultrouter;

修改utils/permission.js,在每个路由跳转之前设置文档的标题:

importrouterfrom"@/router";
importstorefrom"@/store";
import{getToken}from"./cookie";
import{toast,showFullLoading,hideFullLoading}from"./message";

//全局前置守卫
router.beforeEach(async(to,from,next)=>{
//显示全屏加载动画
showFullLoading();

//如果没有登录,就跳转到登录页面
consttoken=getToken();
if(!token&&to.path!="/login"){
toast("请先登录","error");
returnnext({path:"/login"});
}

//防止重复登录
if(token&&to.path=="/login"){
toast("您已经登录过","warning");
returnnext({path:from.path?from.path:"/"});
}

//如果用户登录了,就自动获取用户信息并存储在vuex中
if(token){
awaitstore.dispatch("storeGetUserinfo");
}

//设置页面的标题
lettitle=(to.meta.title?to.meta.title:"")+"-企业级商城后台管理系统";
document.title=title;

//路由继续前行
next();
});

//全局后置守卫
router.afterEach((to,from)=>{
//隐藏全屏加载动画
hideFullLoading();
});

结语

以上就是今天要分享的全部内容了。

今天的内容真的特别多,一共7000多个字,整了非常长的时间。但是今天的内容都是和登录相关的,所以也没有将文章拆分成好几篇发出来,给大家水文字。希望大家看得开心,学得过瘾。

如果大家想要今天的完整代码,只需要打赏20元以上,然后留言评论"已打赏"即可获取哈~

作为一个程序员,光会后端其实是不够的,前端,算法这些最好都能够掌握一些,特别是要精通各种算法,熟悉各种架构。前端更新非常快,要深入掌握很难,但是至少应该是当你想要自己做一个项目的时候,能够自己把页面写出来。

所以,除了学习算法和后端架构,我偶尔也会学习一些前端知识,当然我也很乐意将自己学到的东西分享给大家。

希望大家多多支持,谢谢~