• Vue + Element UI 实现权限管理系统 (功能组件封装)


    组件封装

    为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度。

    组件结构

    组件封装重构后,试图组件结构如下图所示

    代码一览

    Home组件被简化,包含导航、头部和主内容三个组件。

    Home.vue

    复制代码
    <template>
      <div class="container">
          <!-- 导航菜单栏 -->
          <MenuBar></MenuBar>
          <!-- 头部区域 -->
          <HeadBar></HeadBar>
          <!-- 主内容区域 -->
          <Main></Main>
      </div>
    </template>
    
    <script>
    import HeadBar from "./HeadBar/HeadBar"
    import MenuBar from "./MenuBar/MenuBar"
    import Main from "./Main/Main"
    export default {
      components:{
            HeadBar,
            MenuBar,
            Main
      }
    };
    </script>
    
    <style scoped lang="scss">
      .container {
        position:absolute;
        top: 0px;
        left: 0px;
        right: 0px;
        background: #4b5f6e;
      }
    </style>
    复制代码

    HeadBar.vue

    复制代码
    <template> 
      <div class="container">
        <!-- 导航菜单隐藏显示切换 -->
        <span class="collapse-switcher" @click.prevent="collapse">
          <i class="el-icon-menu"></i>
        </span>
        <!-- 导航菜单 -->
        <span class="nav-bar">
          <el-menu :default-active="activeIndex" class="el-menu-demo" text-color="#fff"
              active-text-color="#ffd04b" mode="horizontal" @select="selectNavBar()">
            <el-menu-item index="1" @click="$router.push('/')">{{$t("common.home")}}</el-menu-item>
            <el-menu-item index="2">{{$t("common.doc")}}</el-menu-item>
            <el-menu-item index="3">{{$t("common.msgCenter")}}</el-menu-item>
          </el-menu>
        </span>
        <span class="tool-bar">
          <!-- 主题切换 -->
          <ThemePicker class="theme-picker"></ThemePicker>
          <!-- 语言切换 -->
          <LangSelector class="lang-selector"></LangSelector>   
          <!-- 用户信息 -->
          <el-dropdown class="user-info-dropdown" trigger="hover">
            <span class="el-dropdown-link"><img :src="this.userAvatar" /> {{username}}</span>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>{{$t("common.myMsg")}}</el-dropdown-item>
              <el-dropdown-item>{{$t("common.config")}}</el-dropdown-item>
              <el-dropdown-item divided @click.native="logout">{{$t("common.logout")}}</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </span>
      </div>
    </template>
    
    <script>
    import mock from "@/mock/index.js";
    import ThemePicker from "@/components/ThemePicker"
    import LangSelector from "@/components/LangSelector"
    export default {
      components:{
            ThemePicker,
            LangSelector
      },
      data() {
        return {
          isCollapse: false,
          username: "Louis",
          userAvatar: "",
          activeIndex: '1'
        };
      },
      methods: {
        selectNavBar(key, keyPath) {
          console.log(key, keyPath)
        },
        // 语言切换
        handleCommand(command) {
          let array = command.split(':')
          let lang = array[0] === '' ? 'zh_cn' : array[0]
          let label = array[1]
          document.getElementById("language").innerHTML = label
          this.$i18n.locale = lang
        },
        //折叠导航栏
        collapse: function() {
          this.isCollapse = !this.isCollapse;
        },
        //退出登录
        logout: function() {
          var _this = this;
          this.$confirm("确认退出吗?", "提示", {
            type: "warning"
          })
          .then(() => {
            sessionStorage.removeItem("user");
            this.$router.push
            ("/login");
          })
          .catch(() => {});
        }
      },
      mounted() {
        this.sysName = "I like Kitty";
        var user = sessionStorage.getItem("user");
        if (user) {
          this.userName = user;
          this.userAvatar = require("@/assets/user.png");
        }
      }
    };
    </script>
    
    <style scoped lang="scss">
    .container {
      position: absolute;
      left: 200px;
      right: 0px;
      height: 60px;
      line-height: 60px;
      .collapse-switcher {
         40px;
        float: left;
        cursor: pointer;
        border-color: rgba(111, 123, 131, 0.8);
        border-left- 1px;
        border-left-style: solid;
        border-right- 1px;
        border-right-style: solid;
        color: white;
        background: #504e6180;
      }
      .nav-bar {
        margin-left: auto;
        float: left;
        .el-menu {
          background: #504e6180;
        }
      }
      .tool-bar {
        float: right;
        .theme-picker {
          padding-right: 10px;
        }
        .lang-selector {
          padding-right: 10px;
          font-size: 15px;
          color: #fff;
          cursor: pointer;
        }
        .user-info-dropdown {
          font-size: 20px;
          padding-right: 20px;
          color: #fff;
          cursor: pointer;
          img {
             40px;
            height: 40px;
            border-radius: 10px;
            margin: 10px 0px 10px 10px;
            float: right;
          }
        }
      }
    }
    </style>
    复制代码

    MenuBar.vue

    复制代码
    <template>
        <div class="menu-bar-container">
        <!-- logo -->
        <div class="logo" :class="isCollapse?'menu-bar-collapse-width':'menu-bar-width'">
            <img :src="this.logo" /> <div>{{isCollapse?'':sysName}}</div>
        </div>
        <!-- 导航菜单 -->
        <el-menu default-active="1-1" :class="isCollapse?'menu-bar-collapse-width':'menu-bar-width'" @open="handleopen" @close="handleclose" @select="handleselect" :collapse="isCollapse">
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-location"></i>
              <span slot="title">{{$t("sys.sysMng")}}</span>
            </template>
            <el-menu-item index="1-1" @click="$router.push('user')">{{$t("sys.userMng")}}</el-menu-item>
            <el-menu-item index="1-2" @click="$router.push('dept')">{{$t("sys.deptMng")}}</el-menu-item>
            <el-menu-item index="1-3" @click="$router.push('role')">{{$t("sys.roleMng")}}</el-menu-item>
            <el-menu-item index="1-4" @click="$router.push('menu')">{{$t("sys.menuMng")}}</el-menu-item>
            <el-menu-item index="1-5" @click="$router.push('log')">{{$t("sys.logMng")}}</el-menu-item>
          </el-submenu>
          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-location"></i>
              <span slot="title">{{$t("sys.sysMonitor")}}</span>
            </template>
          </el-submenu>
          <el-menu-item index="3" disabled>
            <i class="el-icon-document"></i>
            <span slot="title">{{$t("sys.nav3")}}</span>
          </el-menu-item>
          <el-menu-item index="4">
            <i class="el-icon-setting"></i>
            <span slot="title">{{$t("sys.nv4")}}</span>
          </el-menu-item>
        </el-menu>
        </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          isCollapse: false,
          sysName: "",
          logo: "",
        };
      },
      methods: {
        handleopen() {
          console.log('handleopen');
        },
        handleclose() {
          console.log('handleclose');
        },
        handleselect(a, b) {
          console.log('handleselect');
        }
      },
      mounted() {
        this.sysName = "I like Kitty";
        this.logo = require("@/assets/logo.png");
      }
    };
    </script>
    
    <style scoped lang="scss">
    .menu-bar-container {
      .el-menu {
        position:absolute;
        top: 60px;
        bottom: 0px;
        text-align: left;
      }
      .logo {
        position:absolute;
        top: 0px;
        height: 60px;   
        line-height: 60px;
        background: #4b5f6e;
        img {
             40px;
            height: 40px;
            border-radius: 0px;
            margin: 10px 10px 10px 10px;
            float: left;
        }
        div {
          font-size: 22px;
          color: white;
          text-align: left;
        }
      }
      .menu-bar-width {
         200px;
      }
      .menu-bar-collapse-width {
         65px;
      }
    }
    </style>
    复制代码

    Main.vue

    复制代码
    <template>
      <div class="container">
        <el-breadcrumb separator="/" class="breadcrumb">
          <el-breadcrumb-item v-for="item in $route.matched" :key="item.path">
            <a href="www.baidu.com">{{ item.name }}</a>
          </el-breadcrumb-item>
        </el-breadcrumb>
        <transition name="fade" mode="out-in">
          <router-view></router-view>
        </transition>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
        };
      },
      methods: {
    
      },
      mounted() {
    
      }
    };
    </script>
    
    <style scoped lang="scss">
    .container {
      position: absolute;
      top: 60px;
      bottom: 0px;
      left: 200px;
      right: 0px;
      .breadcrumb {
        padding: 10px;  
        border-color: rgba(38, 86, 114, 0.2);
        border-bottom- 1px;
        border-bottom-style: solid;
        background: rgba(138, 158, 170, 0.2);
      }
    }
    </style>
    复制代码

    国际化语言切换也被封装成为了组件 LangSelector

    LangSelector/index.js

    复制代码
    <template>
      <el-dropdown class="lang-selector" @command="handleCommand">
        <span class="el-dropdown-link">
          <span id="language">中文</span><i class="el-icon-arrow-down el-icon--right"></i>
        </span>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item command="zh_cn:中文">中文</el-dropdown-item>
          <el-dropdown-item command="en_us:English">English</el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
    </template>
    
    <script>
      export default {
        methods: {
          // 语言切换
          handleCommand(command) {
            let array = command.split(':')
            let lang = array[0] === '' ? 'zh_cn' : array[0]
            let label = array[1]
            document.getElementById("language").innerHTML = label
            this.$i18n.locale = lang
          }
        }
      }
    </script>
    复制代码

    组件封装重构之后,同步修改路由配置

    复制代码
    import Vue from 'vue'
    import Router from 'vue-router'
    import Login from '@/views/Login'
    import NotFound from '@/views/404'
    import Home from '@/views/Home'
    import Intro from '@/views/Intro'
    import User from '@/views/SysMng/User'
    import Dept from '@/views/SysMng/Dept'
    import Role from '@/views/SysMng/Role'
    import Menu from '@/views/SysMng/Menu'
    import Log from '@/views/SysMng/Log'
    
    Vue.use(Router)
    
    const router = new Router({
      routes: [
        {
          path: '/',
          name: '首页',
          component: Home,
          children: [
            { path: '', component: Intro, name: '系统介绍' },
            { path: '/user', component: User, name: '用户管理' },
            { path: '/dept', component: Dept, name: '机构管理' },
            { path: '/role', component: Role, name: '角色管理' },
            { path: '/menu', component: Menu, name: '菜单管理' },
            { path: '/log', component: Log, name: '日志管理' }
          ]
        },
        {
          path: '/login',
          name: '登录',
          component: Login
        }
        ,{
          path: '/404',
          name: 'notFound',
          component: NotFound
        }
      ]
    })
    
    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()
        }
      }
    })
    
    export default router
    复制代码

    测试效果

    封装重构之后,启动界面,效果跟之前差别不大。

  • 相关阅读:
    iOS 成员变量,实例变量,属性变量的区别,联系
    iOS类别(category)不能添加成员变量但是可以添加属性的问题
    iOS缓存机制详解
    ios数据缓存方法
    仿360圆圈自动隐藏效果
    html 背景透明文字不透明
    netty
    关注网站
    关注URL
    DNS之XX记录
  • 原文地址:https://www.cnblogs.com/7788IT/p/10693040.html
Copyright © 2020-2023  润新知