vue 后台系统中多页面标签

        在后台开发中,常用一种页面标签工具,每次点击菜单栏时,会在页面区域上方增加一个【标签页】如下图,可关闭,可切换页面等功能,常见于后台管理系统中。

        以前,我以为这个是利用tabs组件开发的,但是后来看了一些文章才发现,它实际上跟tabs组件没有任何关系(当然你可以用tabs做,实现过程不限于任何技术)

原理:

1 点击菜单栏时,将【菜单项】数据记录在vuex中,或者你存本地的storage中,怎么做都行,但你得保存下来

2 上方标签,通过读取我的路由链,然后用ant vue 【tag】标签渲染(当然你可以用自己方式做)

3 关闭,点击关闭后,要删除路由链,并且要做跳转,当然这里要做判断,如果关闭当前页,则往后面的跳,如果是最后一项,则跳转至开头第一项(路由链中,首页默认设置第一项)

目前,我只简单说到以上的功能,至于其它功能,你可以自己加。

实现:只做实现,质量暂时先不看中

1 vuex中设置路由链,打开你的store/index.js

 

import Vue from 'vue'
import router from '@/router'
import Vuex from 'vuex'
Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    tagsRouter: [],
  },
  getters: {
    
    getTagsRouter(state) {
      //获取标签路由信息
      return state.tagsRouter
    },
  },
  mutations: {
   
    setRouterTagActive(state, routeItem) {
      //设置当前的tag页为活动页
      for (let i = 0; i < state.tagsRouter.length; i++) {
        let item = state.tagsRouter[i]
        state.tagsRouter[i].isActive = false
        if (state.tagsRouter[i].name === routeItem.name) {
          state.tagsRouter[i].isActive = true
        }
      }

      console.log(state.tagsRouter)
    },
    addRoute(state, routeItem) {
      //选择菜单后,添加至本地路由信息中
      let flog = false
      for (let i = 0; i < state.tagsRouter.length; i++) {
        let item = state.tagsRouter[i]
        if (state.tagsRouter[i].name === routeItem.name) {
          flog = true
          break
        }
      }
      if (!flog) {
        state.tagsRouter.push({
          path: routeItem.path,
          name: routeItem.name,
          meta: routeItem.meta,
        })
      }
    },
    delRoute(state, params) {
      //删除tags路由项
      if (state.tagsRouter.length != 0) {
        let itemIndex = 0
        for (let i = 0; i < state.tagsRouter.length; i++) {
          let item = state.tagsRouter[i]
          if (state.tagsRouter[i].meta.menuKey === params.item.meta.menuKey) {
            //
            itemIndex = i
            state.tagsRouter.splice(i, 1)
            break
          }
        }

        //跳除后的跳转
      }
    },
  },
  actions: {
    doSomething(context, val) {
      //应用:this.$store.dispatch("doSomething",{})
      //提交mutations内的方法:context.commit("setUser",val)
    },
  },
  modules: {},
})

2 设置下路由信息,打开router/index.js

路由信息可跟据你的来,我只是截取了一下自己的实验内容,meta中可添加自己的信息

import Vue from 'vue'
import VueRouter from 'vue-router'

import store from '@/store/index'
Vue.use(VueRouter)

// 页面跳转时的进度条
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

NProgress.configure({
  easing: 'ease', // 动画方式
  speed: 500, // 递增进度条的速度
  showSpinner: false, // 是否显示加载icon
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3, // 初始化时的最小百分比
})


// routes设置根据你的项目来即可,我截取了一部分,可能会有错
const routes = [
  {
    path: '/',
    name: 'index',
    meta: { title: '首页', icon: 'home', menuKey: '1', menu: true },
    redirect: '/Dashboard/DashboardIndex',
    component: () =>
      import(/* webpackChunkName: "about" */ '../views/HomeView.vue'),
  },
  {
    path: '/Dashboard',
    name: 'Dashboard',
    meta: { title: 'Dashboard', icon: 'bar-chart', menuKey: '2' },
    component: () => import('../views/HomeView.vue'),
    children: [
      {
        path: 'DashboardIndex',
        name: 'DashboardIndex',
        meta: { title: 'DashboardIndex', icon: '', menuKey: '2.1' },
        component: () => import('@/views/dashboard/Dashboard.vue'),
      },
    ],
  },
  {
    path: '/block',
    name: 'block',
    meta: { title: '链基础网络', icon: 'apartment', menuKey: '3' },
    component: () => import('../views/HomeView.vue'),
    children: [
      {
        path: 'BlockChainSetting',
        name: 'BlockChainSetting',
        meta: { title: '链配置', icon: '', menuKey: '3.1' },
        component: () => import('@/views/blockchain/BlockChainSetting.vue'),
      },
      {
        path: 'BlockChainSetUp',
        name: 'BlockChainSetUp',
        meta: { title: '链搭建', icon: '', menuKey: '3.2' },
        component: () => import('@/views/blockchain/BlockChainSetUp.vue'),
      },
      {
        path: 'BlockChainNetInfo',
        name: 'BlockChainNetInfo',
        meta: { title: '网络状态', icon: '', menuKey: '3.3' },
        component: () => import('@/views/blockchain/BlockChainNetInfo.vue'),
      },
    ],
  }
]


//NProgress 该组件是页面跳转时,页面上方出现的一条进度条,要安装下,npm install --save nprogress

const router = new VueRouter({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes,
})

router.beforeEach((to, from, next) => {
  // 每次切换页面时,调用进度条
  NProgress.start()
  if (to.meta.menuKey != undefined) {
    store.commit('addRoute', to)
    store.commit('setRouterTagActive', to)
  }

  next()
})

//当路由进入后:关闭进度条
router.afterEach(() => {
  // 在即将进入新的页面组件前,关闭掉进度条
  NProgress.done()
})

export default router

3 开发tags组件

<template>
  <div class="menu-tags">
    <a-tag
      :class="['menu-tags_item', item.isActive ? 'item_active' : '']"
      closable
      v-for="(item, index) in data"
      :key="item.name + index"
      @close="handleClose(item)"
      @click="handleSelect(item)"
    >
      <span :class="item.isActive ? 'item_active' : ''">{{
        item.meta.title
      }}</span>
    </a-tag>
  </div>
</template>

<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'

export default {
  name: 'MenuTags',
  props: {},
  data() {
    return {
      data: [],
    }
  },
  computed: {
    ...mapState({
      tagData() {
        return this.$store.state.tagsRouter
      },
    }),
    ...mapGetters({
      getTagsRouterData: 'getTagsRouter', // 获取标签路由信息
    }),
  },
  // 定义引入的组件
  components: {},
  //变量监听
  watch: {},
  // 页面初始化
  created() {},
  // 页面DOM加载完成
  mounted() {
    let _this = this
    _this.init()
  },
  //离开页面时执行
  destroyed() {},
  watch: {},
  // 页面方法
  methods: {
    ...mapMutations({
      mySetRouterTagActive: 'setRouterTagActive', // clickTotal 是mutation 里的方法,totalAlise是重新定义的一个别名方法,本组件直接调用这个方法
    }),
    init() {
      let _this = this
      _this.$set(_this, 'data', [])
      _this.$nextTick(() => {
        _this.$set(_this, 'data', _this.$store.state.tagsRouter)
      })
    },
    handleClose(item) {
      let _this = this
      //
      item.isActive = true

      let tempData = [..._this.data]
      _this.$store.commit('delRoute', {
        item,
        isSameRoute: _this.$route.path == item.path,
      })

      if (tempData.length != 0 && _this.$route.path == item.path) {
        //跳转
        let gotoPath = ''
        for (let i = 0; i < tempData.length; i++) {
          if (tempData[i].path == item.path) {
            if (tempData[i + 1] != undefined) {
              gotoPath = tempData[i + 1].path
            } else if (tempData.length != 0) {
              gotoPath = tempData[0].path
            }
            break
          }
        }

        if (gotoPath != '') {
          _this.handleGoto(gotoPath)
        }
      }
    },
    handleSelect(item) {
      let _this = this

      //如果是当前页,则不跳
      if (item.name != _this.$route.name) {
        _this.$router.push({
          path: item.path,
        })
        _this.mySetRouterTagActive(item)
        _this.$nextTick(() => {
          _this.init()
        })
      }
    },
    handleGoto(path) {
      let _this = this
      if (_this.$common.isNull(path)) {
        return false
      }
      _this.$router.push({
        path: path,
      })
    },
  },
}
</script>

<style lang="less" scoped>
.menu-tags {
  margin-left: 16px;

  .menu-tags_item {
    padding: 2px 10px;
    cursor: pointer;
  }

  .menu-tags_item:hover {
    color: #63d5ce;
  }

  .item_active {
    color: #63d5ce;
  }
}
</style>

 4 引入到你的页面中,具体我不写了,你自己引

5 结果

 其实,这个组件稍微有点麻烦,但原理就是,你如何处理每次点击的菜单项,把它存在哪,然后再渲染出来就行了。

 

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值