Vue项目 成员管理系统 项目布局与权限&退出(5)

一、路由配置

1.1 在 src\components 目录下新建布局组件文件 Loyout.vue

基础布局都放到 components 下面.

页面部分:

<template>
    <div>
        <!-- 头部区域 -->
        <div class="header">
            <app-header />
        </div>
        <!-- 左侧导航 -->
        <div class="navbar">
            <app-navbar />
        </div>
        <!-- 右侧区域 -->
        <div class="main">
            <app-main />
        </div>
    </div>
</template>

 2.2 在 src\router.js 中增加路由配置,如下:

import Layout from '../components/Layout.vue'
{
    path: '/',
    name: 'Layout',
    component: Layout,
  }

二、布局设计

2.1 在 src\components\Layout.vue 文件中定义布局样式

样式部分:

<style  scoped>
/* 头部 */
.header {
    position: absolute;
    line-height: 50px;
    padding: 0px;
    top: 0px;
    left: 0px;
    right: 0px;;
    background-color: blue;
}
/* 左侧导航 */
.navbar {
    position: absolute;
    width: 230px;
    top: 50px; /* 把上边header的部分让出来 */
    left: 0px;
    bottom: 0px;
    overflow-y: auto; /* 纵坐标滚动条 */
    background-color: red;
}
/* 右侧主体区域 */
.main {
    position: absolute;
    top: 50px;
    left: 230px; /* 把左边navbar的部分让出来 */
    right: 0px;
    bottom: 0px;
    overflow-y: auto;
    background-color: blueviolet;
}
</style>

2.2在 src\components 目录下新建3个子目录存放子组件: AppHeader 、 AppNavbar 、 AppMain

并分别在其中创建index.vue

2.3 在 Layout.vue 中使用 components 选项将3个组件作为子组件引入

<script>
import AppHeader from './AppHeader';
import AppMain from './AppMain';
import AppNavbar from './AppNavbar';
export default {
    data() {
        return {
        }
    },

    components: {
        AppHeader,
        AppMain,
        AppNavbar,
    },

    methods: {},

}
</script>

 布局实现:


三、头部区域实现

2.1 下拉菜单

下拉菜单参考:https://element.eleme.cn/#/zh-CN/component/dropdown#zhi-ling-shi-jian

        <el-dropdown @command="handleCommand">
            <span class="el-dropdown-link">
                下拉菜单<i class="el-icon-arrow-down el-icon--right"></i>
            </span>
            <el-dropdown-menu slot="dropdown">
                <el-dropdown-item command="a">修改密码</el-dropdown-item>
                <el-dropdown-item command="b">退出系统</el-dropdown-item>
            </el-dropdown-menu>
        </el-dropdown>
methods: {
        handleCommand(command) {
            this.$message('click on item ' + command);
        }
    }
.el-dropdown-link {
    cursor: pointer;
    color: #409eff;
}
.el-icon-arrow-down {
    font-size: 12px;
    cursor: pointer;
}
.el-dropdown {
    float: right;
    margin-right: 40px;
}

四、左侧导航实现

4.1导航组件实现

<template>
    <div>
        <el-menu
            default-active="2"
            class="el-menu-vertical-demo"
            @open="handleOpen"
            @close="handleClose"
            background-color="#545c64"
            text-color="#fff"
            active-text-color="#ffd04b"
        >
            <el-menu-item index="1">
                <i class="el-icon-menu"></i>
                <span slot="title">首页</span>
            </el-menu-item>
            <el-menu-item index="2">
                <i class="el-icon-menu"></i>
                <span slot="title">教师管理</span>
            </el-menu-item>
            <el-menu-item index="3">
                <i class="el-icon-menu"></i>
                <span slot="title">成员管理</span>
            </el-menu-item>
        </el-menu>
    </div>
</template>

4.2 解决白边

 引用element导航默认会出现白边

 所以在导航样式部分,取消掉:

<style  scoped>
.el-menu{/* element-ui 里面的标签相当于类名,不能用标签选择器 */
    border-right: none;
}
</style>

 4.3 路由模式

开启element自带的vue-router路由模式:

<el-menu
            :router='true'
            default-active="2"
            class="el-menu-vertical-demo"
            background-color="#545c64"
            text-color="#fff"
            active-text-color="#ffd04b"
        >

如果写成 router= 'true' ,默认为字符串,当想给某一个参数传js表达式的时候,需要v-model绑定,才能将后面的内容识别为js表达式.

开启路由,添加路径:

            <el-menu-item index="/home">
                <i class="el-icon-s-home"></i>
                <span slot="title">首页</span>
            </el-menu-item>
            <el-menu-item index="/teacher">
                <i class="el-icon-s-custom"></i>
                <span slot="title">教师管理</span>
            </el-menu-item>
            <el-menu-item index="/student">
                <i class="el-icon-s-check"></i>
                <span slot="title">成员管理</span>
            </el-menu-item>

4.4 添加子组件并更新路由配置

路由中引入相应内容:

import Home from '../views/home';
import Teacher from '../views/teacher';
import Student from '../views/student';

在Layout组件中添加子组件Home,Teacher,Student

{
    path: '/',
    name: 'Layout',
    component: Layout,
    children: [{
      path: '/home',
      component: Home,
      meta: { title: 'ROOT' }
    }, {
      path: '/teacher',
      component: Teacher,
      meta: { title: 'Teacher' },
    }, {
      path: '/student',
      component: Student,
      meta: { title: 'Student' },
    }]
  }

 另一种添加子组件的写法:

先加载父级组件Layout,然后再加载子组件Teacher

{
    path: '/teacher',
    component: Layout,
    children: [{
      path: '/',// '/'可以忽略掉
      component: Teacher,
      title: { title: 'Teacher' }
    }]
  }

将router的出口写到main中:

<template>
    <div>
        <router-view>
            <!-- 渲染子组件的出口 -->
        </router-view>
    </div>
</template>

 因为在其它页面刷新时,会默认回到/home中,所以需要获取当前路径

            :default-active="$route.path"

default-active 值当前激活菜单的index. 后添加js表达式,需要v-model双向绑定.


五、右侧主区域实现

5.1 主区域中除了 首页没有 横向指示导航,其他模块中都有,所以先渲染出面包屑

参考 Breadcrumb 面包屑:Element - The world's most popular Vue UI framework

 在component中创建AppLink文件夹,创建AppLink公共组件.并在AppMain中引入.

<template>
    <div>
        <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item
                class="line"
                :to="{ path: $route.path }"
            >{{$route.meta.title}}</el-breadcrumb-item>
        </el-breadcrumb>
    </div>
</template>
import AppLink from '../AppLink';//声明变量的时候,不要使用Link,默认存在Link,使用会报错

 组件导出:

        <app-link></app-link>

添加样式:

<style  scoped>
.el-breadcrumb {
    height: 10px;
    padding: 20px;
    border-radius: 5px;
    box-shadow: 5px 5px 2px 0 #888888;
    background-color: #ffffff;
    cursor: pointer;
}
.line {
    border-left: 3px solid rgb(81, 211, 161);
    padding-left: 10px;
}
</style>

效果:

5.2 在路由中添加重定向,避免组件没有内容显示

访问根目录的时候,跳转到/home上 

    redirect:'/home',

 在主页中,隐藏组件:

        <app-link v-show="$route.path !=='/home'"></app-link>
        <!-- 路径不等于/home的时候,显示组件 -->

使用v-show而不使用v-if来隐藏组件的原因:

v-if 组件不生成,v-show控制css中的display来隐藏,因为会频繁切换路径,使用v-show更好一点,在组件加载的时候就加载出来,通过样式决定显示不显示.这样不用于v-if,点击的时候加载局部,重新生成一遍,可能造成资源加载过慢.


六、退出系统

6.1 定义退出方法 logout

在api文件夹下创建logout.js,内容如下:

import request from '@/utils/request';

//退出登录
export function logout(token) {
    return request({
        method: 'post',
        url: '/user/logout',
        data: {
            token
        }
    })
}

6.2 重写handleCommand方法

在AppHeader中的index.vue中重写:

handleCommand(command) {
            // this.$message('click on item ' + command);
            switch (command) {
                case 'a'://修改密码
                    break;
                case 'b'://退出登录
                    logout(localStorage.getItem('stu-token')).then(response => {
                        const resp = response.data;
                        if (resp.flag) {//如果成功返回状态为true,就清除stu-token
                            localStorage.removeItem('stu-token');//清除token
                            localStorage.removeItem('stu-user');//清除用户信息
                            this.$router.push('/login');
                            //都清除之后,跳转到登录界面,实现退出登录功能
                            this.$message({
                                message: resp.message,
                                type: 'success'
                            })
                        } else {
                            this.$message({
                                message: resp.message,
                                type: 'error',
                            });
                            this.$router.push('login');
                        }
                    })
                    break;
                    dafault: break;
            }
        }

6.3 配置服务端router.js

router.post('/user/logout', function (req, res) {
    var body = req.body;
    User.findOne({//查询前端传过来的token是否存在
        token: body.token
    }, function (err, data) {
        if (err) {
            return res.status(500).json({
                code: 3000,
                flag: false,
                message: 'server error'
            })
        }
        if (!data) {
            return res.status(200).json({
                code: 4000,
                flag: false,
                message: '账号已注销或已过期'
            })
        }
        return res.status(200).json({
            code: 2000,
            flag: true,
            message: '退出系统成功'
        })
    })
})

成功退出:

6.4 获取nickname

修改下拉菜单名称,改为nickname:

            <span class="el-dropdown-link">
                {{user.nickname}}<i class="el-icon-arrow-down el-icon--right"></i>
            </span>

在data中直接获取:

data() {
        return {
            user: JSON.parse(localStorage.getItem('stu-user'))
            //获取本身为字符串,通过.parse()将字符串转换为对象.这样上面才能获取到nickname
        }
    },

七、权限校验

当用户未登录时,不让访问非登录页面,应该回到登录页面进行登录

7.1采用 Vue Router 中的路由前置钩子函数( beforeEach ),在前置中根据路由地址校验是否此路由是否允许访

新建 src\permission.js 权限校验文件,代码如下:

import router from './router/index.js'
import { getUserInfo } from './api/login.js'

router.beforeEach((to, from, next) => {
    const token = localStorage.getItem('stu-token');
    if (!token) {//没拿到token,证明没有登录
        if (to.path === '/login' || to.path === '/register') {
            //如果当前路径在登录或者注册界面,只需要调用next方法来结束这个钩子函数
            next();
        } else {
            next({ path: '/login' })//其它路径就跳转到 /login
        }
    } else {
        if (to.path === '/login') {
            next();
        } else if (to.path === '/register') {
            next();
        } else {
            getUserInfo(token).then(response => {
                const resp = response.data;
                if (resp.flag) {//为真 代表token去数据库里查,查到了没有问题.
                    localStorage.setItem('stu-user', JSON.stringify(resp.data))
                    //在localStorage中存的时候,需要将对象装换为字符串
                    //存人物信息,确保人物信息是最新的
                    next();
                } else {//没查到信息,说明token有问题,就转到登录界面
                    next({ path='/login' })
                }
            })
        }
    }
})

 7.2 将权限添加到全局中

在main.js中引入权限校验文件:

import './premission.js';

7.3 测试 

1.清空浏览器保存的用户数据和token

2.在未登录情况下访问 http://localhost:8888/home ,会回到 登录

3.只有登录后,才可以访问首页


  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不是独角兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值