Vue3(2):路由配置+登录模块+layout组件+路由鉴权

一、路由配置

经过分析,项目一共需要4个一级路由:登录(login)、主页(home)、404、任意路由(重定向到404)。

1、安装路由插件

pnpm install vue-router

2、创建路由组件 

在src目录下新建views文件夹,在views中创建login、home、404路由组件。这几个路由组件里面也要新建index.vue,以便于测试。

3、配置路由

在src目录下新建router文件夹,书写路由配置(包含index.ts和routes.ts,注意一定是ts文件!

(1)src/router/routes.ts

// 对外暴露配置路由(常量路由)
export const constantRoute = [
    {
        // 登录
        path: '/login',
        component: () => import('@/views/login/index.vue'),
        name: 'login'
    },
    {
        // 登录成功以后展示数据的路由
        path: '/',
        component: () => import('@/views/home/index.vue'),
        name: 'layout'
    },
    {
        // 404
        path: '/404',
        component: () => import('@/views/404/index.vue'),
        name: '404'
    },
    {
        // 任意路由
        path: '/:pathMatch(.*)*',
        redirect: '/404',
        name: 'Any'
    }
]

(2)src/router/index.ts

// 通过vue-router插件实现路由配置
import { createRouter, createWebHashHistory } from 'vue-router';
// 引入routes配置项
import { constantRoute } from './routes';
// 创建路由
let router = createRouter({
    // 路由模式hash
    history: createWebHashHistory(),
    routes: constantRoute,
    // 滚动行为
    scrollBehavior() {
        return {
            left: 0,
            top: 0
        }
    }
})
 
export default router;

4 、引入路由

在main.ts引入

// 引入路由
import router from '@/router'
// 注册模板路由
app.use(router)

5、测试

在App.vue中

<router-view></router-view>

运行项目:

在这里输入不同的路径,home/login/404 ,能够切换即为成功 

二、登录模块

1、登录路由静态的搭建 

采用element-plus中的Layout布局(栅格布局)、From表单组件、input组件、button组件。

Layout布局:一共是24 分栏,:span代表栅格占据的列数,:xs代表屏幕宽度<768px时栅格占据的列数。

input组件::prefix-icon代表前缀图标,show-password代表是否显示切换密码图标

src/views/login/index.vue

<template>
    <div class="login_container">
        <el-row>
            <el-col :span="12" :xs="0"></el-col>
            <el-col :span="12" :xs="24">
                <el-form class="login_from">
                    <h1>Hello</h1>
                    <h2>欢迎来到唧唧bong甄选</h2>
                    <el-form-item>
                        <el-input :prefix-icon="User" v-model="loginFrom.username"></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-input type="password" :prefix-icon="Lock" v-model="loginFrom.password" show-password></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button class="login_btn" type="primary" size="default">登录</el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>
 
<script setup lang="ts">
import {User, Lock} from '@element-plus/icons-vue'
import { reactive } from 'vue';
let loginFrom = reactive({
    username: 'admin',
    password: '111111'
})
</script>
 
<style scoped lang="scss">
.login_container {
    width: 100%;
    height: 100vh;
    background: url('@/assets/images/background.jpg') no-repeat;
    background-size: cover;
    .login_from{
        width: 80%;
        position: relative;
        top: 30vh;
        background: url('@/assets/images/login_form.png') no-repeat;
        background-size: cover;
        padding: 40px;
 
        h1{
            color: white;
            font-size: 40px;
        }
 
        h2{
            color: white;
            font-size: 20px;
            margin: 20px 0;
        }
 
        .login_btn{
            width: 100%;
        }
    }
}
</style>

 2、模板封装登录业务

我们需要做的:点击登录时,会携带用户名和密码向服务器发请求获取token,此时我们需要把token存储起来,用于后续向服务端发请求获取信息的身份验证,这里我们用pinia和loacalStroage进行存储。并且实现弹窗提示信息,以及加载清除效果。

(1)安装pinia

pnpm i pinia

(2)创建大仓库:src/store/index.ts

import { createPinia } from 'pinia'
//创建大仓库
const pinia = createPinia()
//对外暴露:入口文件需要安装仓库
export default pinia

(3)在入口文件(main.ts)中引入并安装pinia:src/main.ts

// 引入大仓库
import pinia from './store'
// 安装仓库
app.use(pinia)

(4)创建小仓库:src/store/modules/user.ts

// 创建用户相关的小仓库
import { defineStore } from 'pinia'
// 接口
import {reqLogin} from '@/api/user'
// 引入数据类型
import type {loginForm} from '@/api/user/type'
//创建用户小仓库
let useUserStore = defineStore('User', {
  //小仓库存储数据地
  state: () => {
    return {
        token:localStorage.getItem("TOKEN"),//存储用户唯一标识,本地存储持久化token
    }
  },
  //异步|逻辑的地方
  actions: {
    // 用户登录的方法
    async userLogin(data:loginForm){
        // 登录请求
        let result:any = await reqLogin(data);
        console.log(result);
        //登录请求:成功200->token
        //登录请求:失败201->登录失败错误的信息
        if(result.code == 200){
            //由于pinia|vuex存储数据其实利用js对象
            //pinia仓库存储一下token
            this.token = result.data.token;
            //本地存储持久化存储一份
            localStorage.setItem("TOKEN",result.data.token);
            // 能保证当前asnyc函数返回一个成功的promise
            return 'ok';
        }else{
            return Promise.reject(new Error (result.data.message))
        }
    }
  },
  getters: {},
})
//对外暴露获取小仓库方法
export default useUserStore

(5)在登录页面中引入小仓库,点击登录时通知user小仓库发请求,存储token:src/views/login/index.vue

<template>
    <div class="login_container">
        <el-row>
            <el-col :span="12" :xs="0"></el-col>
            <el-col :span="12" :xs="24">
                <el-form class="login_from">
                    <h1>Hello</h1>
                    <h2>欢迎来到椰果甄选</h2>
                    <el-form-item>
                        <el-input :prefix-icon="User" v-model="loginForm.username"></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-input type="password" :prefix-icon="Lock" v-model="loginForm.password" show-password></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button :loading="loading" class="login_btn" type="primary" size="default" @click="login">登录</el-button>
                    </el-form-item>
                </el-form>
            </el-col>
        </el-row>
    </div>
</template>
 
<script setup lang="ts">
import { User, Lock } from '@element-plus/icons-vue'
import { reactive,ref } from 'vue';
// 引入用户相关的小仓库
import useUserStore from '@/store/modules/user'
import {useRouter} from 'vue-router';
import {ElNotification} from 'element-plus'
let useStore = useUserStore()
let $router = useRouter()
let loading = ref(false)
// 收集账号与密码的数据
let loginForm = reactive({
    username: 'admin',
    password: '111111'
})
// 登录按钮回调
const login = async()=>{
    // 加载效果:开始加载
    loading.value=true
    // 成功的话到首页,失败的话弹出失败信息
    try {
        await useStore.userLogin(loginForm);
        $router.push('/')
        // 登陆成功提示
        ElNotification({
            type:'success',
            message:'登陆成功'
        }) 
        // 登录成功加载效果消失
        loading.value = false
    } catch (error) {
        // 登录失败加载效果消失
        loading.value = false
        // 登录失败的提示信息
        ElNotification({
            type: 'error',
            message: (error as Error).message
        })
    }
}
</script>

(6)注意点

  • userLogin会返回一个Promise,此处可以使用try...catch...或.then来进行下一步结果处理。
  • 不管成功或失败,都需要使登录加载效果消失,因此也可以统一写在finally里面:
  • try {
            // 保证登录成功
            await useStore.userLogin(loginFrom)
            // 编程式导航跳转到展示数据首页
            $router.push('/')
            // 登录成功信息提示
            ElNotification({
                type: 'success',
                message: '登录成功',
            }) 
        } catch (error) {
            // 登录失败的提示信息
            ElNotification({
                type: 'error',
                message: (error as Error).message
            })
        } finally{
            // 登录成功/失败加载效果消失
            loading.value = false
        }

    3、用户仓库数据ts类型的定义

我们要做的,封装用户仓库数据ts类型的定义 ,因为之前在user.ts里面使用了很多未封装未声明类型的ts数据,写的也很长,所以需要封装一下。

(1)定义小仓库数据state类型:src\store\modules\types\type.ts

// 定义小仓库数据state类型
export interface UserState {
  token: string | null
}

(2)登录接口返回的数据类型:src\api\user\type.ts 

登录请求可能返回成功/失败的数据,因此类型需要dataType需要包括成功的数据token和失败的数据message,且是可选的,要加上"?"。

interface dataType {
    token?: string,
    message?:string
}
 
// 登录接口返回的数据类
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值