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/ 

  • 相关阅读:
    Web API 强势入门指南
    毫秒必争,前端网页性能最佳实践
    Windbg Extension NetExt 使用指南 【3】 ---- 挖掘你想要的数据 Managed Heap
    Windbg Extension NetExt 使用指南 【2】 ---- NetExt 的基本命令介绍
    Windbg Extension NetExt 使用指南 【1】 ---- NetExt 介绍
    WCF : 修复 Security settings for this service require Windows Authentication but it is not enabled for the IIS application that hosts this service 问题
    透过WinDBG的视角看String
    Microsoft Azure Web Sites应用与实践【4】—— Microsoft Azure网站的“后门”
    企业IT管理员IE11升级指南【17】—— F12 开发者工具
    WCF : 如何将NetTcpBinding寄宿在IIS7上
  • 原文地址:https://www.cnblogs.com/CZheng7/p/13397650.html
Copyright © 2011-2022 走看看