欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2.使用ElementUI搭建前端系统框架二

程序员文章站 2022-05-10 21:02:41
...

通常的系统页面采用如下页面布局,在第一章完成项目的基础上,搭建如下前端页面组件实现下图网页区域分配。
2.使用ElementUI搭建前端系统框架二

拆分路由表

将路由组件实例与路由表分离

新建/src/router/staticRoutes.js


const staticRoute = [
    {
        path: '/',
        name: 'home',
        component: () => import('../gf/home')
    }
]

export default staticRoute

修改/src/router/index.js文件

import Vue from 'vue'
import Router from 'vue-router'
import staticRoute from './staticRoutes'

Vue.use(Router)

export default new Router({
  mode: 'hash',
  routes: staticRoute
})

新建页面排列组件

新建/src/gf/layout/HeaderPane.vue组件,它是最上层的Logo层

<template>
  <div class="sys-header">
    <slot name="logo"></slot>
    <div class="logo">
        <font color="red">{{orgname}}</font>-{{username}},欢迎回来!
    </div>

    <ul class="userInfo">
      <li class="icon element-icons lis_button" @click="logout">&#xe639;</li>
      <li>
        <b style="font-size:12pt;color:white;">{{username}}</b>
      </li>
    </ul>
  </div>
</template>

<style>

</style>
<script>

export default {
  data(){
    return{
      orgname:'古方红糖信息管理系统',
      username:'admin'
    };
  },
  methods: {
    logout() {
      
    }
  }
}
</script>

2.使用ElementUI搭建前端系统框架二
新建/src/gf/layout/LeftPane.vue组件,它位于左侧导航区域

<template>
    <div class="sidediv">
      <div @mouseenter="fn" class="floatdiv">
        <div style="margin-left:0.3rem;margin-top:1.875rem">
          <img src="~static/images/demo.png" alt style="width:25px;" />
        </div>
        <div style="margin-left:0.3rem;margin-top:1.875rem">
          <img src="~static/images/demo2.png" alt style="width:25px;" />
        </div>
        <div style="margin-left:0.3rem;margin-top:1.875rem">
          <img src="~static/images/demo3.png" alt style="width:25px;" />
        </div>
        <div style="margin-left:0.3rem;margin-top:1.875rem">
          <img src="~static/images/demo4.png" alt style="width:25px;" />
        </div>
        <div style="margin-left:0.3rem;margin-top:1.875rem">
          <img src="~static/images/demo5.png" alt style="width:25px;" />
        </div>
        <div style="margin-left:0.3rem;margin-top:1.875rem">
          <img src="~static/images/demo6.png" alt style="width:25px;" />
        </div>
      </div>
      <div class="fly" v-show="hidde" @mouseleave="leave()">
        <div style="height:25px"></div>
        <ul class="uls">
          <li v-for="(item,i) in arr" @click="fun(i)">{{item.name}}</li>
        </ul>
      </div>

      <div class="menudiv">
        <el-menu
          router
          ref="navbar"
          :default-active="defActive"
          :mode="navMode"
          menu-trigger="click"
          @select="selectMenu"
          @open="openMenu"
          @close="closeMenu"
          unique-opened>
          <div class="nav_css">
            <left-menu  v-for="(item, n) in navList" :item="item" :navIndex="String(n)" :key="n"></left-menu>
          </div>
        </el-menu>
      </div>
    </div>
</template>
<style scoped>
.sidediv{
  
}
.menudiv {
  z-index: -1;
  margin-left: 2.4rem;
  width: 7rem;
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
}
.nav_css{
  max-height:33rem;
  overflow: hidden;
  width: 9rem;
  overflow-y: scroll;
  text-align:left;
  line-height:33px;
  border:0;
}
.floatdiv {
  position: absolute;
  width: 2.4rem;
  height: 100%;
  background: #001529;
  float: left;
}
.fly {
  width: 7rem;
  height: 100%;
  float: left;
  background: #001529;
  position: absolute;
  left: 2.4rem;
  z-index: 100;
}
.uls li {
  width: 6rem;
  height: 40px;
  line-height: 40px;
  padding-left: 5px;
  margin-bottom: 14.5px;
  color: white;
  cursor:pointer;
}
</style>
<script>
import { mapState } from "vuex";
import LeftMenu from "./LeftMenu";

export default {
  data() {
    return {
      navBgShow: false,
      hidde: false,
      tagNavList: [],
      hometag: {},
      currenttag: {},
      arr: [
        { name: "待办工作" },
        { name: "关闭页签" },
        { name: "导航切换" }
      ],
      navList: [{name:'系统管理',url:'',child:[{name:'用户管理',visible:true,url:'/gf/home',child:[]}]}]
    };
  },
  props: ["layout"],
  computed: {
    defActive() {
      return this.$route.path;
    },
    navMode() {
      if (this.layout == "left") {
        return "vertical";
      }
      if (this.layout == "top") {
        return "horizontal";
      }
    },
    isDark() {
      return true;
    }
  },
  watch: {
    $route() {

    }
  },
  methods: {
    fn() {
      this.hidde = !this.hidde;
    },
    leave() {
      this.hidde = false;
    },
    fun(i) {
      if (i == 0) {
        this.$router.push("/home");
        this.hidde = false;
      }else if (i == 1) {
         this.closeAllTag();
      }else if (i == 2) {
         this.changeMenu();
      }

      // this.$router.push('/'+this.arr.url[i])
    },
    selectMenu(index, indexPath) {
      let openedMenus = this.$refs.navbar.openedMenus;
      let openMenuList;
      if (indexPath.length > 1) {
        let parentPath = indexPath[indexPath.length - 2];
        openMenuList = openedMenus.slice(openedMenus.indexOf(parentPath) + 1);
      } else {
        openMenuList = openedMenus;
      }
      openMenuList = openMenuList.reverse();
      openMenuList.forEach(ele => {
        this.$refs.navbar.closeMenu(ele);
      });
      if (this.navMode == "horizontal") {
        this.navBgShow = false;
      }
    },
    openMenu() {
      if (this.navMode == "horizontal") {
        this.navBgShow = true;
      }
    },

    closeAllTag() {
      this.hometag={};
      this.currenttag={};
      this.tagNavList = this.$store.state.tagNav.openedPageList;

      this.tagNavList.forEach(item =>{
          if (item.path == '/home'){
            this.hometag = item;
          }

          if (item.path == this.$route.path){
            this.currenttag = item;
          }
      })

      this.$store.commit("tagNav/removeTagNav", null);
      this.$store.commit("tagNav/addTagNav", this.hometag);
      this.$store.commit("tagNav/addTagNav", this.currenttag);
    },

    changeMenu() {
      if (this.isBig) {
        this.isBig= false;
      }else{
        this.isBig= true;
      }

      if (this.isSmall) {
        this.isSmall= false;
      }else{
        this.isSmall= true;
      }
    },

    closeMenu() {
      if (this.navMode == "horizontal") {
        this.navBgShow = false;
      }
    },
    closeAll() {
      let openMenu = this.$refs.navbar.openedMenus.concat([]);
      openMenu = openMenu.reverse();
      openMenu.forEach(ele => {
        this.$refs.navbar.closeMenu(ele);
      });
      if (this.navMode == "horizontal") {
        this.navBgShow = false;
      }
    }
  },
  components: { LeftMenu }
};
</script>

LeftPane组件采用标准VUE语法写法
2.使用ElementUI搭建前端系统框架二
LeftPane组件中引用了组件LeftMenu,需要定义LeftMenu.vue组件
2.使用ElementUI搭建前端系统框架二

LeftMenu.vue文件

<template>
    <!-- 如果菜单包含子菜单,进一步调用LeftMenu组件循环展开 -->
    <el-submenu v-if="item.child && item.child.length" :index="navIndex"> 
        <!-- 显示父菜单名称 -->
        <template slot="title"><i v-if="item.icon" class="item.icon"></i>{{ item.name }}</template>
        <!-- 调用LeftMenu组件循环展开 -->
        <left-menu v-for="(subItem,i) in item.child" :key="navIndex+'-'+i" :navIndex="navIndex+'-'+i" :item="subItem" ></left-menu>
    </el-submenu>

    <!-- 如果菜单不包括子菜单,只显示主菜单,其中visible属性决定是否显示 -->
    <el-menu-item v-else-if="item.visible" :index="item.path" :route="{path: item.url}"><i v-if="item.icon" class="item.icon"></i>{{ item.name }}</el-menu-item>
</template>
<script>
export default {
    name: 'LeftMenu',
    props: ['item','navIndex']
}
</script>

定义全局的组件main.vue,作为布局管理全局组件,在路由表中引入

<template>
    <div class="wrapper">
        <template>
            <!-- 
              引用HeaderPane组件 
              其中slot=logo将显示在HeaderPane中的 <slot name="logo"></slot> 根据名称匹配
            -->
            <header-pane v-once>
                <p slot="logo"><img src="~static/images/logo.png"></p>
            </header-pane>
            <!-- 引入左侧组件 -->
            <left-pane></left-pane>
        </template>

    </div>
</template>

<style>
  .el-container{
    top:0px;
  }
  .el-header {
    background-color: #B3C0D1;
    color: #333;
    line-height: 60px;
  }
  
  .el-aside {
    color: #333;
    overflow-y: auto;
  }
</style>

<script>
import HeaderPane from './HeaderPane'
import LeftPane from './LeftPane'

export default {
    mounted() {

    },
    computed: {
        tagNavList(){
            return [];
        }
    },
    components:{
      HeaderPane,LeftPane
    }
}
</script>

重新定义路由表

const Layout = () => import('../gf/layout/main')

const staticRoute = [
    {
        path: '/gf',
        component: Layout,
        children: [
            {
                path: 'home',
                component: () => import('../gf/home'),
            },
        ]
    }
]

export default staticRoute

当访问http://localhost:8080/#/gf/home时,将Home组件加载到Layout组件上
2.使用ElementUI搭建前端系统框架二
将上部的Logo去掉
2.使用ElementUI搭建前端系统框架二
2.使用ElementUI搭建前端系统框架二
2.使用ElementUI搭建前端系统框架二

定义右侧办公区域

右边办公区域分为上下两部分,上面定义TabPane组件,下面是路由组件route-view

TabPane.vue

<template>
    <div class="tag-nav">
        <tab-scroll-bar ref="scrollBar">
            <router-link ref="tag" class="tag-nav-item"
                :class="isActive(item) ? 'cur' : ''" v-for="(item, index) in openedList" 
                :to="item.path" :key="index">
                <span class='ivu-tag-dot-inner'></span>
                    {{item.title}}
                <span class='el-icon-close' @click.prevent.stop="closePage(item, index)"></span>
            </router-link>
        </tab-scroll-bar>
    </div>
</template>

<script>
import TabScrollBar from './TabScrollBar'

export default {
    data(){
        return {
            defaultPage: '/gf/home'
        }
    },
    computed: {
        openedList(){
            return [{title:'用户管理',path:'/gf/home'}];
        }
    },
    mounted(){
        //this.openPage()
    },
    watch: {
        $route(){
            this.openPage()
            this.scrollToCurPage()
        }
    },
    methods: {
        openPage(){
            if(this.$router.getMatchedComponents()[1])
            {
                this.$store.commit("auth/addPage", {
                    name: this.$router.getMatchedComponents()[1].name,
                    path: this.$route.path,
                    title: this.$route.meta.name
                })
            }
        },
        isActive(item){
            return item.path === this.$route.path
        },
        closePage(item, index){
            this.$store.commit("auth/removePage", item)
            if(this.$route.path == item.path){
                if(index){
                    this.$router.push(this.openedList[index-1].path)
                } else {
                    this.$router.push(this.defaultPage)
                    if(this.$route.path == "/gf/home"){
                        this.openPage()
                    }
                }
            } 
        },
        scrollToCurPage(){
            this.$nextTick(() =>{
                for (let item of this.$refs.tag) {
                    if (item.to === this.$route.path) {
                        this.$refs.scrollBar.scrollToCurPage(item.$el)
                        break
                    }
                }
            })
        }
    },
    components: {TabScrollBar}
}
</script>

默认打开的Tab页签使用静态计算属性定义,这个需要动态参数化

    computed: {
        openedList(){
            return [{title:'用户管理',path:'/gf/home'}];
        }
    },

其中引用了TabScrollBar组件,控制Tab页签排列。

import TabScrollBar from './TabScrollBar'
components: {TabScrollBar}

TabScrollBar.vue

<template>
    <div class="scroll-wrap" ref="scrollWrap" @wheel.prevent="scroll">
        <div class="scroll-cont" ref="scrollCont" :style="{left: left + 'px'}">
            <slot></slot>
        </div>
    </div>
</template>

<style lang="scss" scoped>
.scroll-wrap{
    position: relative;
    top:0px;
    width: 100%;
    height: 100%;
    white-space: nowrap;
}
.scroll-cont{
    position: absolute;
    transition: all .3s ease;
}
</style>

<script>
export default {
    data(){
        return {
            left: 0,
            wheelSpeed: 30,
        }
    },
    mounted(){

    },
    methods: {
        scroll(e){
            const scrollWrapWidth = this.$refs.scrollWrap.offsetWidth
            const scrollContWidth = this.$refs.scrollCont.offsetWidth
            if(scrollContWidth > scrollWrapWidth){
                const scrollSpace = e.deltaY > 0 ? -1 * this.wheelSpeed : this.wheelSpeed
                if(e.deltaY > 0){ 
                    if(Math.abs(this.left + scrollSpace) <= (scrollContWidth - scrollWrapWidth)){
                        this.left += scrollSpace
                    }
                } else {
                    if(this.left + scrollSpace < 0){
                        this.left += scrollSpace
                    } else {
                        this.left = 0
                    }
                }
            } else {
                return
            }
        },
        scrollToCurPage(tar){
            const scrollWrapWidth = this.$refs.scrollWrap.offsetWidth
            const tarWidth = tar.offsetWidth
            const tarLeft = tar.offsetLeft
            
            if(tarLeft < -1 * this.left){
                this.left = -tarLeft
            } else if(tarLeft + tarWidth > scrollWrapWidth){
                this.left = -(tarLeft + tarWidth - scrollWrapWidth)
            }
        }
    }
}
</script>


修改全局组件main.vue,在其中加入TabPane组件。
2.使用ElementUI搭建前端系统框架二

<template>
    <div class="wrapper">
        <template>
            <!-- 
              引用HeaderPane组件 
              其中slot=logo将显示在HeaderPane中的 <slot name="logo"></slot> 根据名称匹配
            -->
            <header-pane v-once>
                <p slot="logo"><img src="~static/images/logo.png"></p>
            </header-pane>
            <!-- 引入左侧组件 -->
            <left-pane></left-pane>
        </template>
        <div class="sys-content">
            <tab-pane></tab-pane>
            <keep-alive :include="tagNavList">
                <router-view></router-view>
            </keep-alive>
        </div>
    </div>
</template>

<style>
  .el-container{
    top:0px;
  }
  .el-header {
    background-color: #B3C0D1;
    color: #333;
    line-height: 60px;
  }
  
  .el-aside {
    color: #333;
    overflow-y: auto;
  }
</style>

<script>
import HeaderPane from './HeaderPane'
import LeftPane from './LeftPane'
import TabPane from './TabPane'

export default {
    mounted() {

    },
    computed: {
        tagNavList(){
            return [];
        }
    },
    components:{
      HeaderPane,LeftPane,TabPane
    }
}
</script>
import HeaderPane from './HeaderPane'
import LeftPane from './LeftPane'
import TabPane from './TabPane'

    components:{
      HeaderPane,LeftPane,TabPane
    }

访问页面效果为
2.使用ElementUI搭建前端系统框架二
下一步需要参数化和事件响应控制

下载前端代码gfvue_v1.2.zip
链接:https://pan.baidu.com/s/1IOpuw-mx1BcnTd-gfftLsw
提取码:d5ba