基於iview的後臺管理模板佈局頁面

代碼在線預覽

最近項目使用iview來開發,iview UI設計仍是蠻好的相對於element-ui,可是後臺模板佈局是塊硬傷,因此本身寫了一個通用頁面,以便之後能夠直接拿來用,下面貼上代碼,分享一下:
view admin的後臺管理系統模板,可是我的愚見感受有點過重了,因此本身結合iview的頁面佈局本身寫了一套通用的模板頁面,方便後續開發使用。vue

clipboard.png

clipboard.png

首先,咱們新建一個Layout.vue頁面,這個頁面就是整個佈局模板的頁面,咱們設置好sidebar、topbar、以及中間的content就好,而後content,咱們放上<router-view>就能夠了,路由就隨便你怎麼跳轉了。android

Layout.vueios

<style lang="less" scoped>
@import '../../../assets/gls-theme/common.less';
.ivu-layout.ivu-layout-has-sider{
    height: 100%;
}
.ivu-layout-sider{
    background: #fff;
}
.ivu-layout-header{
    height: 100px;
    line-height: 18px;
}
.ivu-menu{
    height: 100%;
}
.admin-layout-container{
    position: absolute;
    width: 100%;
    height: 100%;
    .layout{
        background: #f5f7f9;
        position: relative;
        overflow: hidden;
        height: 100%;
        & .dropdown-wrap{
            background: rgb(73, 80, 96);
        }
        & .logo{
            background: #4c364f80;
            border-bottom: 1px solid #363e4f;
            width: auto;
            height: 60px;
            display: flex;
            text-align: center;
            align-items: center;
            justify-content: center;
            cursor: pointer;
        }
    }
    .layout-header-bar{
        background: #fff;
    }
    .layout-logo-left{
        width: 90%;
        height: 30px;
        background: #5b6270;
        border-radius: 3px;
        margin: 15px auto;
    }
    .menu-icon{
        transition: all .3s;
    }
    .rotate-icon{
        transform: rotate(-90deg);
    }
    .menu-item span{
        display: inline-block;
        overflow: hidden;
        width: 69px;
        text-overflow: ellipsis;
        white-space: nowrap;
        vertical-align: bottom;
        transition: width .2s ease .2s;
    }
    .menu-item i{
        transform: translateX(0px);
        transition: font-size .2s ease, transform .2s ease;
        vertical-align: middle;
        font-size: 16px;
    }
    .collapsed-menu span{
        width: 0px;
        transition: width .2s ease;
    }
    .collapsed-menu i{
        transform: translateX(5px);
        transition: font-size .2s ease .2s, transform .2s ease .2s;
        vertical-align: middle;
        font-size: 22px;
    }
}

</style>
<template>
  <section class="admin-layout-container">
      <div class="layout">
        <Layout>
            <Sider ref="side1" hide-trigger collapsible :collapsed-width="78" v-model="isCollapsed" style="background: rgb(73, 80, 96);">
                <div class="logo" >
                    <img :src="logo" width="100" v-if="!isCollapsed"/>
                    <Avatar icon="person" size="large" v-else/>
                </div>
                <Menu 
                    ref="side_menu"
                    :active-name="activeMenuName" 
                    :open-names="openMenuName"
                    theme="dark"
                    width="auto" 
                    :class="menuitemClasses"
                    @on-select="choosedMenu"
                    v-if="!isCollapsed">
                    <template v-for="(menu,menu_index) in menus">
                        <Submenu :name="menu.name" v-if="menu.children">
                            <template slot="title">
                                <Icon :size="20" :type="menu.icon"></Icon>
                                {{menu.title}}
                            </template>
                            <MenuItem :name="child.name" v-for="(child ,child_index) in menu.children" :key="child_index">
                                <Icon :size="20" :type="child.icon"></Icon>
                                {{child.title}}
                            </MenuItem>
                        </Submenu>
                        <MenuItem :name="menu.name" v-if="!menu.children && menu.showInMenus">
                             <Icon :size="20" :type="menu.icon"></Icon>
                            {{menu.title}}
                        </MenuItem>
                    </template>                    
                </Menu>
                <div class="dropdown-wrap">
                    <template v-for="(menu,menu_index) in menus" v-if="isCollapsed">
                        <Dropdown transfer placement="right-start" v-if="menu.children" @on-click="dropdownClick">
                            <Button style="width: 85px;margin-left: -5px;padding:10px 0;" type="text">
                                <Icon :size="25" color="#fff" :type="menu.icon"></Icon>
                            </Button>
                            <DropdownMenu style="width: 200px;" slot="list">
                                <template v-for="(child, i) in menu.children">
                                    <DropdownItem :name="child.name">
                                        <div style="display:flex;align-items:center;">
                                            <Icon :size="16" :type="child.icon"></Icon>
                                            <span style="padding-left:10px;">
                                                {{ child.title }}
                                            </span>
                                        </div>
                                    </DropdownItem>
                                </template>  
                            </DropdownMenu>
                        </Dropdown>
                        <Dropdown transfer v-if="!menu.children && menu.showInMenus" placement="right-start" @on-click="dropdownClick">
                            <Button style="width: 85px;margin-left: -5px;padding:10px 0;" type="text">
                                <Icon :size="25" color="#fff" :type="menu.icon"></Icon>
                            </Button>
                            <DropdownMenu style="width: 200px;" slot="list">
                                <DropdownItem :name="menu.name">
                                    <div style="display:flex;align-items:center;">
                                        <Icon :size="16" :type="menu.icon"></Icon>
                                        <span style="padding-left:10px;">
                                            {{ menu.title }}
                                        </span>
                                    </div>
                                </DropdownItem>
                            </DropdownMenu>
                        </Dropdown>
                    </template>         
                </div>            
            </Sider>
            <Layout>
                <Header :style="{position: 'fixed',
                        width: isCollapsed?'calc(100% - 78px)':'calc(100% - 200px)',
                        padding: 0,
                        display:'flex',
                        flexDirection:'column',
                        zIndex:20
                    }" class="layout-header-bar">
                    <div style="
                        display:flex;
                        align-tems:center;
                        justify-content:space-between;
                        position: relative;
                        height:60px;
                        line-height: 60px;
                        z-index: 1;
                        box-shadow: 0 2px 1px 1px rgba(100, 100, 100, 0.1);">
                        <div style="display:flex;align-items:center;">
                            <Icon @click.native="collapsedSider" :class="rotateIcon" :style="{margin: '0 20px 0'}" type="navicon-round" size="24"></Icon>
                            <span style="font-size:18px;font-weight:bold">{{user.mechanism.name}}後臺管理系統</span>
                        </div>
                        <div style="margin-right:20px">
                            <!-- <Button type="text" icon="person" size="large">我的中心</Button>
                            <Button type="text" icon="android-notifications" size="large" @click="clickNotice">消息通知</Button> -->
                            <Button type="text" icon="android-exit" size="large" @click="quit">退出系統</Button>
                        </div>
                    </div>     
                    <div style="display: flex;
                                position: relative;
                                padding-left:10px;
                                height: 40px;
                                background: #f5f7f9;
                                align-items: center;
                                box-shadow: 0 2px 1px 1px rgba(100, 100, 100, 0.1);">
                        <template v-for="(tab,tab_index) in tags">
                            <Tag type="dot" 
                            :closable="tab.closable" 
                            :color="tab.choosed ? 'blue':'#e9eaec'"
                            :name="tab.name"
                            @click.native="clickTag(tab)"
                            @on-close="closeTag" >
                                {{tab.title}}
                            </Tag>
                        </template>
                    </div>                  
                </Header>                
                <Content :style="{
                    height: 'calc(100% - 100px)',
                    position: 'absolute',
                    top: '100px',
                    overflow: 'auto',
                    padding: '10px',
                    width:isCollapsed?'calc(100% - 78px)':'calc(100% - 200px)'
                    }">
                    <!--保存組件狀態到內存,避免從新渲染-->
                    <keep-alive>
                        <router-view/>    
                    </keep-alive>               
                </Content>
            </Layout>
        </Layout>
    </div>
  </section>
</template>
<script>
import {mapActions,mapState} from 'vuex'

export default {
    data(){
        return{
            logo:`${this.$qiniuFileUrl}${process.env.LOGO}`,
            isCollapsed: false,
            // ------------------------------  菜單操做開始  --------------------------------
            title:'首頁',
            activeMenuName:'admin',
            openMenuName:[],
            menus:[
                {
                    title:'首頁',
                    num:1,
                    name:'admin',
                    icon:'home',
                    href:'/admin',
                    closable:false,
                    showInTags:true,
                    showInMenus:true,
                    choosed:true,
                },
                {
                    title:'課程管理',
                    name:'course-manage',
                    icon:'ios-bookmarks',
                    href:'/admin/course',
                    closable:true,
                    showInTags:false,
                    showInMenus:true,
                    choosed:false,
                },
                {
                    title:'老師管理',
                    name:'teacher-manage',
                    icon:'person-stalker',
                    href:'/admin/teacher',
                    closable:true,
                    showInTags:false,
                    showInMenus:true,
                    choosed:false,
                },               
                {
                    title:'學生管理',
                    name:'student-manage',
                    icon:'university',
                    href:'/admin/student',
                    closable:true,
                    showInTags:false,
                    showInMenus:true,
                    choosed:false,
                },
                {
                    title:'課堂',
                    name:'class-manage-parent',
                    icon:'easel',
                    children:[
                        {
                            title:'課堂管理',
                            name:'classroom-manage',
                            icon:'erlenmeyer-flask',
                            href:'/admin/classroom',
                            closable:true,
                            showInTags:false,
                            showInMenus:true,
                            choosed:false,
                        },
                        {
                            title:'上課管理',
                            name:'class-manage',
                            icon:'android-time',
                            href:'/admin/class',
                            closable:true,
                            showInTags:false,
                            showInMenus:true,
                            choosed:false,
                        }
                    ]
                },
                {
                    title:'APK管理',
                    name:'apk-manage',
                    icon:'social-android',
                    href:'/admin/apk',
                    closable:true,
                    showInTags:false,
                    showInMenus:true,
                    choosed:false,
                },
                {
                    title:'設置',
                    name:'setting',
                    icon:'gear-a',
                    href:'/admin/setting',
                    closable:true,
                    showInTags:false,
                    showInMenus:true,
                    choosed:false,
                },
                {
                    title:'消息通知',
                    name:'notice',
                    icon:'ios-navigate',
                    href:'/notice',
                    closable:true,
                    showInTags:false,
                    showInMenus:false,
                    choosed:false,
                }
            ]
            // ------------------------------  菜單操做結束  --------------------------------   
        }
    },
    computed: {
        ...mapState(
            {
                user:state=>state.user
            }
        ),
        // 篩選menus中選中的menu
        tags(){
            let tags = [];
            // 將menus中showInTags=true的標籤放到tags數組中
            this.menus.forEach(menu=>{
                if(menu.showInTags){
                    tags.push(menu);
                }else if(menu.children){
                    menu.children.forEach(child=>{
                        if(child.showInTags){
                            tags.push(child)
                        }
                    })
                }
            });
            console.log('tags=>',tags)

            //標籤數組排序,從小到到
            tags.sort((a,b)=>{
                return (a.num - b.num)
            })
            return tags;
        },
        rotateIcon () {
            return [
                'menu-icon',
                this.isCollapsed ? 'rotate-icon' : ''
            ];
        },
        menuitemClasses () {
            return [
                'menu-item',
                this.isCollapsed ? 'collapsed-menu' : ''
            ]
        }
    },
    // ------------------------------  菜單操做開始  --------------------------------
    //刷新頁面以後保存並選中最後一次菜單和標籤
    beforeRouteEnter (to, from, next) {
        next(vm => {
            // 經過 `vm` 訪問組件實例
            let activeMenuName = localStorage.activeMenuName;
            vm.activeMenuName = activeMenuName;

            let tags_last_num = vm.tags[vm.tags.length - 1].num; 

            if(activeMenuName && activeMenuName.length != 0){
                vm.menus.forEach(_menu=>{
                    if(activeMenuName == _menu.name){                        
                        _menu.choosed = true;
                        _menu.showInTags = true;
                        _menu.num = tags_last_num + 1;
                    }
                    else if(_menu.children){
                        _menu.children.forEach(child=>{
                            if(activeMenuName == child.name){
                                child.choosed = true;
                                child.showInTags = true;
                                child.num = tags_last_num + 1;
                                vm.openMenuName = [_menu.name];      
                            }
                        })                 
                    }
                    else{
                        // 排除首頁
                        if(_menu.name != 'admin'){
                            _menu.choosed = false;
                            _menu.showInTags = false;
                        }else{
                            _menu.choosed = false;
                        }
                    }
                })
            }
            vm.$nextTick(()=>{
                vm.$refs.side_menu.updateOpened();
                vm.$refs.side_menu.updateActiveName();
            });           
        })        
    },
    // ------------------------------  菜單操做結束  --------------------------------
    methods: {
        ...mapActions([
            'logout'
        ]),
        quit(){
            this.logout();
            localStorage.removeItem('token');
            localStorage.removeItem('activeMenuName');
            this.$router.push('/login')
        },
        clickNotice(){
            this.choosedMenu('notice');
        },
        collapsedSider() {
            this.$refs.side1.toggleCollapse();
        },
        // ------------------------------  菜單操做開始  --------------------------------
        closeTag(event, name){
            // 判斷該標籤是不是選中狀態
            // 若是是那麼就要設置標籤數組中最後一個標籤成選中狀態
            // 若是否那麼就直接刪除就好
            let is_choosed = false;
            this.menus.forEach((menu,_index)=>{
                if(menu.name == name){
                    is_choosed = menu.choosed;
                    menu.showInTags = false;
                }else if(menu.children){
                    menu.children.forEach(child=>{
                        if(child.name == name){
                            is_choosed = child.choosed;
                            child.showInTags = false;
                        }
                    })
                }
            })          
            // 關閉標籤並選中tags中最後一個標籤高亮  
            if(is_choosed){
                let last_tag = this.tags[this.tags.length-1];
                last_tag.choosed = true;
                this.$router.push(last_tag.href);
                this.activeMenuName = last_tag.name;
                localStorage.activeMenuName = this.activeMenuName;
            }            
        },
        clickTag(tag){
            this.tags.forEach(_tag=>{
                if(_tag.name == tag.name){
                    _tag.choosed=true;
                }else{
                    _tag.choosed= false;
                }
            })
            // 設置菜單選中name
            this.activeMenuName = tag.name;
            localStorage.activeMenuName = this.activeMenuName;
            // 刷新菜單
            this.$nextTick(()=>{
                if(this.$refs.side_menu){
                    this.$refs.side_menu.updateActiveName()
                }
            });
            //點擊tab跳轉
            this.$router.push(`${tag.href}`);
        },
        choosedMenu(name){
            // 獲取標籤數組最後一個元素的num
            let tags_last_num = this.tags[this.tags.length - 1].num;
            // 設置選中菜單name
            this.activeMenuName = name;
            localStorage.activeMenuName = this.activeMenuName;
            let if_tab = false;

            //根據name查找對應的菜單對象
            let menu = null;
            this.menus.forEach(_menu=>{
                if(_menu.name == name){   
                    // 只有不在tags數組中的元素才能設置num                 
                    if(!_menu.showInTags){                   
                        _menu.num = tags_last_num + 1;
                    }
                    menu = _menu;
                    _menu.showInTags = true;
                    _menu.choosed = true;                
                                        
                }
                else if(_menu.children){
                    _menu.children.forEach(child=>{
                        if(child.name == name){     
                            // 只有不在tags數組中的元素才能設置num                       
                            if(!_menu.showInTags){
                                child.num = tags_last_num + 1; 
                            }            
                            menu = child;                
                            child.showInTags = true;
                            child.choosed = true;
                            
                        }else{
                            child.choosed = false;
                        }
                    })
                }
                else {
                    _menu.choosed = false;
                }
            })
            this.$router.push(`${menu.href}`);
        },
        dropdownClick(name){
            this.choosedMenu(name);
        }
        // ------------------------------  菜單操做結束  --------------------------------
    }
}
</script>

在路由頁面裏面,我引入了幾個頁面,大家能夠根據個人路徑本身新建一下便可,而後把組件和路由結合起來就能夠成功運行並應用個人Layout.vue頁面進行後臺整個頁面的佈局了,是否是超方便的。git

Router.vuegithub

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/views/admin/Home.vue'
import AdminLayout from '@/components/admin/Layout.vue'
import Admin from '@/views/admin/Admin.vue'
import UserManage from '@/views/admin/UserManage.vue'
import CityManage from '@/views/admin/CityManage.vue'
import ConditionManage from '@/views/admin/ConditionManage.vue'
import ConditionTypeManage from '@/views/admin/ConditionTypeManage.vue'
import IndustryManage from '@/views/admin/IndustryManage.vue'
import Setting from '@/views/admin/Setting.vue'
import Notice from '@/views/admin/Notice.vue'

import Login from '@/views/login/Login.vue'

Vue.use(Router)

let router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'admin',
      component: AdminLayout,
      children:[
        {
          path:'',
          name:'index',
          meta:{
            title:'首頁',
          },
          component:Admin
        },        
        {
          path:'usermanage',
          name:'user-manage',
          meta:{
            title:'用戶管理',
          },
          component:UserManage
        },
        {
          path:'citymanage',
          name:'citymanage',
          meta:{
            title:'城市管理'
          },
          component:CityManage
        },
        {
          path:'conditiontypemanage',
          name:'conditiontypemanage',
          meta:{
            title:'條件類型管理'
          },
          component:ConditionTypeManage
        },
        {
          path:'conditionmanage',
          name:'conditionmanage',
          meta:{
            title:'條件管理'
          },
          component:ConditionManage
        },
        {
          path:'industrymanage',
          name:'industrymanage',
          meta:{
            title:'一級行業'
          },
          component:IndustryManage
        },
        {
          path:'setting',
          name:'setting',
          meta:{
            title:'設置'
          },
          component:Setting
        },
        {
          path:'notice',
          name:'notice',
          meta:{
            title:'通知'
          },
          component:Notice
        },
        {
          path:'test',
          name:'test',
          meta:{
            title:'測試'
          },
          component:Setting
        }
      ]
    },
    {
      path:'/login',
      name:'login',
      meta:{
        title:'登陸',
      },
      component:Login
    },
  ]
})


router.beforeEach((to, from, next) => {
  let token = localStorage.token;
  if(token && to.name != 'login'){
    next()
  }else if(token && to.name == 'login'){
    next('/');
  }else if(!token && to.name != 'login'){
    next('/login')
  }else{
    next()
  }
})

export default router;

最後,總結一下:其實網上有好多相似的模板管理頁面,可是我的感受通常,因此本身寫了一個,相信在不久的未來這樣的模板佈局頁面會愈來愈多的。vue-router

一、iview官網vuex


如下內容是2018年12月14日更新

clipboard.png

clipboard.png

相關文章
相關標籤/搜索