后台管理系统的左侧菜单树+顶部页签组件(vue+element)

基本思路:

父组件:

此页面基本是整个项目的最上层组件 包含左侧菜单+右侧上方页签+右侧下方内容区 主要需要设置个动态缓存

参考:vue keep-alive 缓存 不生效解决方案_keep-alive keepalive:true, 缓存不生效-CSDN博客

左侧菜单树:

1 接口接收当前用户允许查看的路由树并渲染上

2 点击对应导航时 将相关数据传到vuex里保存起来 一会儿页签里面用

右侧页签:

操作vuex的列表数据  左侧导航新增相关页签到vuex后 页签直接使用vuex的页签列表 会自动更新  页签组件里负责点击删除后删除相关页签

vuex里:

设置新增与删除页签列表相关代码就行

代码(未注释版 暂时没时间仔细梳理注释 有问题评论或者私聊我)

父组件

<template>
  <div style="width:100%;height:100vh;display: flex;justify-content: flex-start;align-items: flex-start;" class="flex_SB_H">

    <left_navigation style="width:20%;max-width: 30rem;"></left_navigation>
    <article style="flex: 1;height: 100%; overflow: scroll;">
      <top_subtab></top_subtab>
      <keep-alive :max="40">
        <router-view v-if="$route.meta.keepAlive"></router-view>
      </keep-alive>
      <router-view v-if="!$route.meta.keepAlive"></router-view>
    </article>
  </div>
</template>
<script>
import left_navigation from '@/components/layout/left_navigation.vue'; /*左侧导航动态版(接口请求)组件*/
import top_subtab from '@/components/layout/top_subtab.vue';/*右侧顶部页签缓存版组件*/
// import {  } from 'element-ui';
export default ({
  name:'layout',
  components:{ left_navigation,top_subtab },
  data:()=>{
    return {

    //  state:store.state.keepAliveList
    }
  },
  mounted(){
  //  console.log('32131',store,store.state.keepAliveList)
  },
})
</script>
<style>
</style>


左侧菜单树

<template>
  <div class="left_nav" style="overflow-y: scroll;height:100%;">
    <el-menu style="height: 100%;" ref="layout"
            active-text-color="#ffd04b"
            background-color="#545c64"
            class="el-menu-vertical-demo"
            :default-active="menuActive"
            text-color="#fff"
            :unique-opened="fatherData.menu_uniqueOpened"
        >
          <div v-for="(item,index) in fatherData.list" :index="index">
            <!-- 有子集菜单 -->
            <template v-if="item.list">
              <el-submenu :index="item.name" :disabled="item.disabled">
                <template #title><el-icon><component :is="item.icon"></component></el-icon>{{ item.label }}</template>
                <el-menu-item v-for="(item2) in item.list" :index="item2.name" :disabled="item2.disabled" @click="childClickFn">
                  <template #title><el-icon><component :is="item2.icon"></component></el-icon>{{ item2.label }}</template>
                </el-menu-item>

              </el-submenu>
            </template>
            <!-- 无子集菜单的渲染 -->
            <template v-else>
              <el-menu-item :index="item.name" :disabled="item.disabled" @click="childClickFn">
                <template #title><el-icon><component :is="item.icon"></component></el-icon>{{ item.label }}</template>
              </el-menu-item>
            </template>

          </div>
    </el-menu>
  </div>
</template>
<script>
import store from '@/store'
import { Menu,Submenu,MenuItem,Icon,} from 'element-ui';
import { arrayMethod } from '@/assets/public.js'
export default({
  components:{
    store,
    [Menu.name]:Menu,
    [Submenu.name]:Submenu,
    [MenuItem.name]:MenuItem,
    [Icon.name]:Icon,
    arrayMethod,
  },
  data:()=>{
    return {
      fatherData:{
        menu_uniqueOpened: false,/* 是否只保持一个子菜单的展开 */
        list:[]
      },
      menuActive:store.state.menuActive
    }
  },
  created() {
    this.dataListFn()
  },
  methods:{
    dataListFn(){
      setTimeout(()=>{
        this.fatherData = {
          menu_uniqueOpened:false,
          list: [
            {label:'人物管理',icon:'Search',name:'person',
              list:[
                {label:'人物管理',icon:'Search',name:'renwu',},
                {label:'种族管理',icon:'Search',name:'zhongzu',},
                {label:'特性管理',icon:'Search',name:'dict',},
              ]
            },
            {label:'组件使用示例',icon:'Search',name:'examples',
              list:[
                {label:'table示例',icon:'Search',name:'et_table',},
                {label:'et_form里的et_inputTableSelect示例',icon:'Search',name:'et_inputTableSelect',},
              ]
            },
            {label:'测试2-1',icon:'Female',name:'pageD',},
            {label:'表格-动态增删列表项',icon:'Search',name:'table_userList', },
            {label:'测试4',icon:'Female',name:'layouA_4',},
            {label:'测试2',icon:'Search',name:'layouA_2', },
            {label:'测试2',icon:'Search',name:'layouA_2', },
            {label:'测试2',icon:'Search',name:'layouA_2', },
            {label:'测试2',icon:'Search',name:'layouA_2', },
            {label:'测试2',icon:'Search',name:'layouA_2', },
            {label:'测试2',icon:'Search',name:'layouA_2', },
            {label:'测试2',icon:'Search',name:'layouA_2', },
            {label:'测试2',icon:'Search',name:'layouA_2', },
            {label:'测试1',icon:'Search',name:'layouA',
              list:[
                {label:'测试1-1',icon:'Search',name:'pageA',},
                {label:'测试1-2',icon:'Female',name:'pageB',}]
            },
            {label:'测试1',icon:'Search',name:'layouA',
              list:[
                {label:'测试1-1',icon:'Search',name:'pageA',},
                {label:'测试1-2',icon:'Female',name:'pageB',}]
            },
          ]
        };
      },2000)
    },
    childClickFn(event){
      /* 添加keepAliveList数据到缓存 */
      let state_status = true
      store.state.keepAliveList.forEach((item)=>{
        if(item === event.index){ state_status = false }
      })
      if(state_status){ store.dispatch('keepAliveList_add',event.index) }

      /* 添加路由数据到二级页签 */
      let status = true
      store.state.subtab.forEach((item)=>{
        if(item.routerName === event.index){ status = false }
      })
      if(status){
        store.dispatch('subtab_add',{
          name:event.index,
          type:event.index ==='pageA' ? 'info':'success',
          routerName:event.index,
          path:arrayMethod.connectListFn(event.indexPath,{ start:'/',connect:'/' })
        })

      }
      if(event.index !== this.$route.name){ this.$router.push({ name:event.index }) }
    },
  },
})

</script>
<style scoped>
/* 滚动条美化 */
  .left_nav ::-webkit-scrollbar{ display:none }
  /*html body ::-webkit-scrollbar-button{ display:none }
  html body ::-webkit-scrollbar-track{ display:none }
  ::-webkit-scrollbar-track-piece{ display:none }
  ::-webkit-scrollbar-thumb{ display:none }
  ::-webkit-scrollbar-corner{ display:none }
  ::-webkit-resizer{ display:none }*/
</style>

右侧页签

<template>
  <div class="flex_S_C">
    <div v-if="state.length > 0">
      <el-tag
          v-for="tag in state"
          :key="tag.name"
          :class="abcdFn(tag)"
          closable
          :type="tag.type"
          @click="tagClickFn(tag)"
          @close="subtab_delete(tag)"
      >
        {{ tag.name }}
      </el-tag>
    </div>
  </div>
</template>
<script>
import { toRefs,defineComponent,ref,reactive} from 'vue';
import { useRouter } from 'vue-router'
import { useStore } from "vuex"
import store from '@/store'
import { Tag } from 'element-ui';
export default({
  components:{
    store,
    [Tag.name]:Tag,
  },
  props: {},
  data:()=>{
    return {
      state:store.state.subtab,
    }
  },
  mounted(){

  },
  methods:{
    abcdFn(tag){
      return tag.name === this.$route.name ? 'class1':'class2'
    },
    subtab_delete(tag){
      store.dispatch('subtab_delete',tag.routerName)
      store.dispatch('keepAliveList_delete',tag.routerName)
      if(tag.name === this.$route.name){ this.$router.go(-1); }
    },
    tagClickFn(tag){
      if(tag.name !== this.$route.name){ this.$router.push({ path:tag.path }) }
    },
  },
})

</script>
<style scoped>
.class1{ color: red; }
.class2{ color: blueviolet;}
</style>

vuex:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state(){
        return{
            keepAliveList:[], /*页签功能配套的缓存变化集*/
            subtab:[],/*三级页签集*/
            menuActive:'pageB',/*默认选中的menu标签*/
        }
    },
    mutations:{
        subtab_add(state,args){
            /* @ts-ignore*/
            state.subtab.push(args)
        },
        /* subtab_update_type(state,args){
             /!* @ts-ignore*!/
             state.subtab.forEach((item,index)=>{
                 item.type = 'warning'
             })
         },*/

        subtab_delete(state,routerName){
            /* @ts-ignore*/ /*注: forEach会改变原有长度 导致少循环一次*/
            state.subtab.forEach((item,index)=>{
                if(item.routerName === routerName){
                    /* @ts-ignore*/
                    state.subtab.splice(index,1)
                }
            })
        },

        /* 路由缓存的功能设置 */
        keepAliveList_add(state,args){
            /* @ts-ignore*/
            state.keepAliveList.push(args)
        },
        keepAliveList_delete(state,name){
            /* @ts-ignore*/ /*注: forEach会改变原有长度 导致少循环一次*/
            state.keepAliveList.forEach((item,index)=>{
                if(item === name){
                    /* @ts-ignore*/
                    state.keepAliveList.splice(index,1)
                }
            })
        }
    },
    actions:{
        subtab_add(context,args){ context.commit('subtab_add',args) },
        subtab_delete(context,routerName){
            if( routerName ){ context.commit('subtab_delete',routerName) }
            else { console.log('vuex删除路由功能缺少routerName属性') }
        },
        /* 路由缓存的功能设置 */
        keepAliveList_add(context,args){ context.commit('keepAliveList_add',args) },
        keepAliveList_delete(context,name){
            if( name ){ context.commit('keepAliveList_delete',name) }
            else { console.log('vuex删除路由功能2缺少name属性') }
        },
    },
    getters:{
        /*  doubleNum(state){
              // @ts-ignore
              return state.num*2
          }*/
    },
    modules:{}
})

环境配置 Node 下载地址http://nodejs.cn/ 安装文件下有一个绿色的图片交node.exe 点击运行 输入node -v进行检测是否安装成功 使用vue-cli(脚手架)搭建项目 vue-cli是vue官方提供的用域搭建基于vue+webpack_es6项目的脚手架工具 在线文档:https://github.com/vuejs/vue-cli 操作: 1.npm install -g vue-cli:全局下载工具 2.vue init webpack 项目名:下载基于webpack模板项目 3.cd 项目名:进入项目目录 4.npm install :下载项目依赖的所有模块 5.npm run dev :运行项目 6.访问项目:localhost:8080 项目目录结构 src assets:存放照片、css、js css js img components:存放组件 lib:存放模拟数据 router:配置路由 store:存放vuex vuex的安装:cd x项目目录 cnpm install vuex --save views:存放所有单面 配置访问端口号: 根目录下有一个config文件夹,看名字就知道与配置有关,打开config目录下的index.js dev: { env: require('./dev.env'), port: 8092, autoOpenBrowser: true, assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: {}, } 项目目录下:https://blog.csdn.net/weixin_39378691/article/details/83784403 1.安装elementUI:cd进入项目根目录,npm i element-ui -S 2.引入elementUI组件(main.js文件中) import Element from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(Element, { size: 'small' }) 项目目录下:https://blog.csdn.net/weixin_41432849/article/details/81988058 1.安装jquery:cd进入项目根目录, npm install jquery --save 2.在项目 build 里的webpack.base.conf.js 里加载webpack文件,注意,要放在配置文件第一行; const webpack = require('webpack') 3.在module.exports的最后加入 , plugins:[ new webpack.ProvidePlugin({ $:"jquery", jQuery:"jquery", jquery:"jquery", "window.jQuery":"jquery" }) ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值