zoukankan      html  css  js  c++  java
  • Vue + Element UI 实现权限管理系统 前端篇(四):优化登录流程

    继续笔记:在这里基本是大框架搭出来了。

    完善登入流程

    1.丰富登入界面

    1.1 Element 参考 搭建

    <template>
        <el-form 
            :model="loginForm" 
            ref="loginForm"
            :rules="fieldRules"
            label-position="left"
            label-width="0px"
            class="demo-ruleForm login-container"
            > 
            <h3 class="title">登入系统</h3>
            <el-form-item prop="account">
                <el-input type="text" v-model="loginForm.account" auto-complete="off" placeholder="账号"></el-input>
            </el-form-item>
            
            <el-form-item prop="password">
                <el-input type="password" v-model="loginForm.password" auto-complete="off" placeholder="密码"></el-input>
            </el-form-item>
            <!-- <el-checkbox v-model="checked" checked class="remember">记住密码</el-checkbox> -->
            <el-form-item style=" 100%;">
                <el-button type="primary" style=" 48%;" @click.native.prevent="reset">重 置</el-button>
                <el-button type="primary" style=" 48%;" @click.native.prevent="login" :loading="logining">登 入</el-button>
            </el-form-item>
        </el-form>
    </template>

    1.2添加页面组件显示规则和操作响应,登入成功后将登入信息存储到本地会话,用于配置路由跳转

    <script>
        import mock from '@/mock/index.js';
        import Cookies from 'js-cookie';
        
        export default {
            name: 'Login',
            data() {
                return {
                    logining: false,
                    loginForm: {            // 账号,密码
                        account: 'admin',
                        password: 'admin',
                    },
                    fieldRules: {           // 输入框规则 rules:表单验证规则,即 async-validator 所使用的校验规则,类型为 Object。
                        account: [
                            { required: true, message: '请输入账号', trigger: 'blur' },   // 'blur'是鼠标失去焦点的时候会触发验证  required 是否必填,如果不设置,则会根据校验规则自动生成
                        ],
                        password: [
                            { required: true, message: '请输入密码', trigger: 'blur' },
                        ],
                    },
                    // checked: true
                }
            },
            methods: {
                login() {
                    let userInfo = { account: this.loginForm.account, password: this.loginForm.password };  // 提取本地账号密码
                    this.$api.login(JSON.stringify(userInfo)).then((res) => {       // 传递给后台本地账号密码返回 token ,现在是没有验证账号密码过程的
                        alert(res.data.token)
                        Cookies.set('token', res.data.token);    // 放置token到Cookie
                        sessionStorage.setItem('user', userInfo.account);   // 保存用户到本地会话
                        this.$router.push('/');     // 登入成功,转跳到主页
                    }).catch((res) => {
                        alert(res);
                    })
                },
                reset() {
                    this.$refs.loginForm.resetFields();
                }
            }
        }
    </script>   

    1.3优化样式

    <style lang="scss" scoped>
        .login-container {
             400px;
            background: #fff;
            background-clip: padding-box;
            margin: 180px auto;
            padding: 35px 35px 15px;
            box-sizing: border-box;
            border: 1px solid #eaeaea;
            border-radius: 5px;
            box-shadow: 0 0 30px rgba(0, 0, 0 , 0.1);
            .title {
                text-align: center;
                color: #505458;
                margin: 0 auto 40px;
            }
            // .remember {
            //     margin: 0 0 25px;
            // }
        }

    1.4最后效果

     

    2.修改接口 post 请求

    修改 http/interface.js,把请求类型改为 post,并传入 data 参数。

    3.修改对应的 mock 接口

    修改 mock/modules/logins.js,把请求类型改为 post

    // 登入接口
    export function login () {
        return {
            // isOpen: false,
            url: 'http://localhost:8080/login',
            type: 'post',
            data: {
                'msg': 'success',
                'code': 0,
                'data': {
                    'token': '4344323121398'
                    // 其它数据
                }
            }
        }
    }

    4.添加导航守卫(只有登入后才能访问相应权限界面)

    // 导航守卫
    router.beforeEach((to, from, next) => {
        // 登入界面成功之后,会把用户信息保存在会话
        // 存在时间为会话生命周期,页面关闭既失效
        let user = sessionStorage.getItem('user');
        if(to.path == '/login') {
            // 访问登入界面,如果用户会话信息存在,代表已登入过,转跳到主页
            if(user) {
                next({ path: '/' })
            }else {
                next()
            }
        }else {
            // 访问非登入界面,且用户信息不存在,代表未登入,则转跳到登入界面
            if(!user) {
                next({ path: '/login' })
            }else {
                next()
            }
        }
    })

    5.完善主页界面

    5.1 构建主界面

    <template>
        <div class="container">
            <!-- 
                row: 行概念
                col: 列概念, col组件的 :span属性的布局调整 栅格占据的列数,默认值 24 
             -->
            <el-row class="header">           
                    <!-- 大标题 class 的切换 看 col 是否失效 lapse:失效 -->
                    <el-col :span="5" class="logo" :class="isCollapse ? 'logo-collapse-width' : 'logo-width'"> 
                        <img :src="this.logo" />
                        {{ isCollapse ? sysName : sysName }}
                    </el-col>
                    <!-- icon @click.prevent: 阻止默认行为 -->
                    <el-col :span="1">
                        <div class="tools" @click.prevent="collapse">
                            <i class="el-icon-menu"></i>
                        </div>
                    </el-col>
                    <!-- 顶部导航栏,
                        默认是垂直模式,通过 mode="horizontal" 设置成水平模式 horizontal: 水平的
                        default-openeds    当前打开的 sub-menu 的 index 的数组
                    -->
                    <el-col :span="13">
                        <div class="hearNavBar">
                            <!-- default-active 它的说明内容为:当前激活菜单的 index。(即当前哪一项被设置为高亮) 是为了浏览器刷新后,仍然可以定位到之前选中的路由。
                                mode 属性可以使导航菜单变更为水平模式
                            -->
                            <el-menu
                                :default-active="activeIndex"
                                class="el-menu-demo"
                                background-color="#4b5f6e"
                                text-color="#fff"
                                active-text-color="#ffd04b"
                                mode="horizontal"
                                @select="handleSelectHearNavBar"
                            >
                            <!-- index 唯一标志 默认值 null -->
                                <el-menu-item index="1">首页</el-menu-item>
                                <el-menu-item index="2">消息中心</el-menu-item>
                                <el-menu-item index="3">订单管理</el-menu-item>
                            </el-menu>
                        </div>
                    </el-col>
                    <el-col :span="5" class="userinfo">
                        <el-dropdown trigger="hover">
                            <span class="el-dropdown-link userinfo-inner">
                                <img :src="this.userAvatar" />
                                {{ username }}
                            </span>
                            <el-dropdown-menu slot="dropdown">
                                <el-dropdown-item>我的消息</el-dropdown-item>
                                <el-dropdown-item>设置</el-dropdown-item>
                                <!-- 自定义组件 @click + .native 后才能触发 -->
                                <el-dropdown-item divided @click.native="logout">退出登入</el-dropdown-item>
                            </el-dropdown-menu>
                        </el-dropdown>
                    </el-col>
            </el-row>
            <el-row class="main">
                <aside class="aside">
                    <!-- 导航菜单 -->
                    <el-menu 
                        default-active="1-2"
                        class="el-menu-vertical-demo"
                        :collapse="isCollapse"
                        @open="handleopen"
                        @close="handleclose"
                        @select="handleselect"
                    >
                        <!-- 这里的两个 slot 不懂 -->
                        <el-submenu index="1">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span slot="title">系统管理</span>
                            </template>
                            <el-menu-item index="1-1" @click="$router.push('user')">用户管理</el-menu-item>
                            <el-menu-item index="1-2" @click="$router.push('menu')">菜单管理</el-menu-item>
                        </el-submenu>
                        <el-submenu index="2">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span slot="title">系统监控</span>
                            </template>
                            <el-menu-item index="2-1" @click="$router.push('user')">服务监控</el-menu-item>
                            <el-menu-item index="2-2" @click="$router.push('menu')">任务监控</el-menu-item>
                        </el-submenu>
                        <el-menu-item index="3" disabled>
                            <i class="el-icon-document"></i>
                            <span slot="title">导航三</span>
                        </el-menu-item>
                        <el-menu-item index="4">
                            <i class="el-icon-setting"></i>
                            <span slot="title">导航四</span>
                        </el-menu-item>
                    </el-menu>
                </aside>
                <!--  section元素表示一个包含在HTML文档中的独立部分   content:内容    container:容器 -->
                <section class="content-container">
                    <div class="grid-content bg-purple-light">
                        <!-- 面包屑 由当前路由动态显示-->
                        <el-col :span="24" class="breadcrumb-container">
                            <el-breadcrumb separator="/" class="breadcrumb-inner">
                                <el-breadcrumb-item v-for="item in $route.matched" :key="item.path">
                                    {{ item.name }}
                                </el-breadcrumb-item>
                            </el-breadcrumb>
                        </el-col>
                        <!-- 子路由展示地方,transition过渡效果-->
                        <el-col :span="24" class="content-wrapper">
                            <transition name="fade" mode="out-in">
                                <router-view></router-view>
                            </transition>
                        </el-col>
                    </div>
                </section>
            </el-row>
    
        </div>
    </template>

    5.2 处理页面事件和页面数据显示,主要是两个事件和在 mounted 函数内获取页面数据。

    <script>
        import mock from '@/mock/index.js';
        export default {
            name: 'Home',
            data() {
                return {
                    isCollapse: false,
                    sysName: "kitty",
                    username: "louis",
                    userAvater: "",
                    logo: "",
                    activeIndex: '1'
                }
            },
            methods: {
                handleopen() {
                    console.log('handleopen');
                },
                handleclose() {
                    console.log('handleclose'); 
                },
                handleselect(a, b) {
                    console.log('handleselect');
                },
                handleSelectHearNavBar(key, keyPath) {
                    console.log(key, keyPath)
                },
                // 折叠导航栏
                collapse: function() {
                    this.isCollapse = !this.isCollapse;
                },
                // 退出登入
                logout: function() {
                    // 绑定 this
                    let _this = this;
                    this.$confirm("确认退出吗?", "提示", {
                        type: "warning"
                    })
                    .then(() => {
                        sessionStorage.removeItem("user");
                        this.$router.push("/login");
                    })
                    .catch(() => {});
                }
            },
            // 页面属性初始化
            mounted() {
                this.sysName = "I like Kitty";
                this.logo = require("@/assets/user/logo.png");
                let user = sessionStorage.getItem("user");
                if (user) {
                    this.userName = user;
                    this.userAvatar = require("@/assets/user/user.png")
                }
            }
        }
    </script>

    5.3 修饰调整 css 样式 调整完效果如下图所示。

    <style lang="scss" scoped>
        // 后续用 flex 布局重构下
        .container {
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
             100%;
            .header {
                height: 60px;
                line-height: 60px;
                background: #4b5f6e;
                color:#fff;
                .userinfo {
                    text-align: right;
                    padding-right: 30px;
                    float: right;
                    .userinfo-inner {
                        font-size: 20px;
                        cursor: pointer;
                        color: #fff;
                        img {
                             40px;
                            height: 40px;
                            border-radius: 10px;
                            margin: 10px 0px 10px 10px;
                            float: right;
                        }
                    }
                }
                .logo {
                    height: 60px;
                    font-size: 22px;
                    border-right- 1px;
                    border-right-style: solid;
                    border-color: rgba(238, 241, 146, 0.5);
                    text-align: left;
                    img {
                         40px;
                        height: 40px;
                        margin: 10px;
                        float: left;
                    }
                    .txt {
                        color: #fff;
                    }
                }
                // 切换左侧标签栏状态时变化
                .logo-width {
                     230px;
                }
                .logo-collapse-width {
                     65px;
                }
                //  切换图标
                .tools {
                     40px;
                    padding: 0 10px;
                    // 水平方向上居中
                    text-align: center;            
                    cursor: pointer;
                }
                .hearNavBar {
                     100%;
                    height: 60px;
                    background: #4b5f6e;
                     
                    line-height: 60px;
                    cursor: pointer;
                }
            }
            .main {
                 100%;
                display: flex;
                position: absolute;
                top: 60px;
                bottom: 0px;
                overflow: hidden;
                aside{
                    flex: 0 0 230px;
                     230px;
                    .el-menu {
                        height: 100%;
                        text-align: left;
                    }
                }
                .content-container {
                    // 占据剩下的空间
                    flex:1;
                    padding: 0px;
                    .breadcrumb-container {
                        height: 28px;
                        background: rgba(99, 138, 161, 0.2);
                        border: 1px solid rgba(38, 80, 114, 0.2);
                        .breadcrumb-inner {
                            padding: 5px 0px 5px 5px ;
                            text-align: left;
                            font-size: 18px;
                             100%;
                            height: 100%;
                            float: left;
                        }
                    }
                    .content-wrapper {
                        background: #fff;
                        box-sizing: border-box;
                    }
                }
            }
        }
    </style>
    style

     

    6.嵌套路由(主界面的 main)

    6.1 在 views 目录下新建 Main、User、Menu 页面,用于菜单路由,内容随便显示点什么就可以

    6.2 在 router/index.js 文件中添加子路由,分别指向子页面

    6.3 在 views/Home.vue 页面对应的导航菜单中添加点击事件,路由到对应的子页面

    6.4 登录之后,点击用户管理,路由到用户管理界面


    学习出处:https://www.cnblogs.com/xifengxiaoma/ 

  • 相关阅读:
    MyEclipse 快捷键
    Oracle使用split和splitstr函数批量分隔字符串
    linux解压 tar命令
    Crontab的用法
    .net 连接ORACLE中文显示乱码解决方案
    python 列表
    关于ios 11 的问题
    初步了解会计学
    iOS关于直播的链接
    知识链接中.....
  • 原文地址:https://www.cnblogs.com/CZheng7/p/13397650.html
Copyright © 2011-2022 走看看