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

vue实现单页面多标签页

程序员文章站 2024-03-17 17:37:04
...

不废话先上效果图


vue实现单页面多标签页
vue实现单页面多标签页
vue实现单页面多标签页

实现上面的效果,主要是通过改变vue的路由机制实现的

  1. 在router目录文件下新建TabRouter.js文件,添加以下内容
const route = Object.create(null)
route.install = function (vue) {
  // 第一个字符串是 组件名,第二个是组件路径,第三个是包名(如果不指定则已1.js,2.js....n.js命名)
	vue.component('home', (resolve) => {require.ensure([], ()=>resolve(require('@/Views/index/adminIndex.vue')), 'home')})
	vue.component('userscreate', (resolve) => {require.ensure([], ()=>resolve(require('@/Views/demo/Sitecreate.vue')), 'userscreate')})
	vue.component('userslist', (resolve) => {require.ensure([], ()=>resolve(require('@/Views/demo/Sitelists.vue')), 'userslist')})
}


export default route
  1. 在router目录文件下新建MainConf.js文件,添加如下内容
export default {
	// 列表配置
	// 菜单列表
	menu: [
		{
			title: '主菜单1',            // 一级菜单名称
			icon: 'el-icon-location',   // 一级菜单 icon
			menuId: '1',                // 索引(必须唯一,是字符串)
			sub: [                      // 子菜单(二级菜单)
				{
					title: '站点列表',      // 菜单名称
					component: 'userslist',    // 点击菜单打开的组件名称
					menuId: '1-1'           // 索引 (用于识别当前打开的tab,必须唯一,是字符串)
				},
				{title: '新增站点', component: 'userscreate', menuId: '1-2'}
			]
		}
	],

	// 主页 tab 配置
	homeTab: {
		title: '首页',                     //  tab 显示标题
		menuId: 'home',                   //  tab 内部名称(用来识别当前打开的tab)
		components: [{path: 'home'}],     //  tab 对应的组件
	}
}
  1. 引入store文件
import Vue from 'vue'
import Vuex from  'vuex'
import MainStore from '@/router/MainStore'
Vue.use(Vuex)

export default new Vuex.Store({
  //  模块化 store, 把需要 store 的数据导入到这里即可
  // store 格式参考 /src/Frame/MainStore.js
  modules: {
    MainStore,
  }
})

4.在MainStore中追加一下tab标签实现方法

import store from "@/Store";
import conf from './MainConf'
import {Base64} from 'js-base64'

export default {
	state: {
		/* page: [], */
		currentTabIndex: conf.homeTab.menuId, // 当前显示的 tab
		homeTabMenuId: conf.homeTab.menuId,   // 主页 tab 的 menuId
		openedTabs: [                         // 当前打开的 tab 列表
			conf.homeTab
		],
	},
	getters: {
		// 获取 当前显示的 tab name
		GetCurrentTabIndex (state) {
			return state.currentTabIndex
		},
		// 获取 主页 tab 的 menuId
		GetHomeTabMenuId (state) {
			return state.homeTabMenuId
		},
		// 获取 当前打开的 tab 列表
		GetOpenedTabs (state) {
			return state.openedTabs
		},
		// 获取查询参数
		GetQuery (state) {
			let res = Object.create(null)
			state.openedTabs.map(i => {
				if (i.menuId === state.currentTabIndex) {
					let end = i.components.length - 1
					res = i.components[end].query || {}
					return
				}
			})
			return res
		},
		// 获取当前**的 tab
		GetCurrentTab (state) {
			return state.openedTabs.find(i => i.menuId === state.currentTabIndex)
		}
	},
	mutations: {
		// 设置 hash
		SetHash (state) {
			let cur = state.openedTabs.find(i => i.menuId === state.currentTabIndex)
			location.hash =  Base64.encode(JSON.stringify(cur))
		},
		// 设置 主页 tab
		SetHomeTab (state,item) {
			state.homeTabMenuId = item.menuId
			state.openedTabs[0] = item
		},
		// 回显 tab
		reShowHash (state) {
			let url = location.href
			let indexOfSharp = url.indexOf('#')
			if (indexOfSharp > 0) {
				let hash = url.substr(indexOfSharp + 1)
				let tab = JSON.parse(Base64.decode(hash))
				// let tab = JSON.parse(hash)
				if (tab.menuId === state.homeTabMenuId) {
					state.openedTabs = state.openedTabs.filter(i => i.menuId !== state.homeTabMenuId)
				}
				state.openedTabs.push(tab)
				state.currentTabIndex = tab.menuId
			}
		},
		// 设置 当前显示的 tab name
		SetCurrentTabIndex (state, data) {
			state.currentTabIndex = data
			store.commit('SetHash')
		},
		// 添加 tab 到 tab 列表
		OpenedTabsPush (state, item) {
			// 设置当前要显示的 tab name
			state.currentTabIndex = item.menuId

			// 判断 tab 项是否已存在
			let tabExsit = state.openedTabs.find(i => i.menuId === item.menuId)
			/* if (tabExsit == null) {
				state.openedTabs.push(item)
			} */
			if (!tabExsit) {
				state.openedTabs.push({
					title: item.title,                      // 显示标题
					menuId: item.menuId,                    // 用于标记当前打开 tab 的 name
					components: [{path: item.component}],   //  tab 对应的组件
				})
			} else if(item.fromHistory) {               // 点击前进后退按钮
				state.openedTabs.map(i => {
					if(i.menuId === item.menuId) {
						i.components = item.components
					}
				})
			}

			if (!item.fromHash) store.commit('SetHash')
		},
		// 当前 tab 内部的跳转
		OpenedSubTabsPush (state, item) {
			state.openedTabs.map(i => {
				if (i.menuId === state.currentTabIndex) {
					i.components.push(item)
				}
			})
			store.commit('SetHash')
		},
		// 返回
		OpenedSubTabsBack (state, num = 1) {
			if (num < 1) num = 1
			state.openedTabs.map(i => {
				if (i.menuId === state.currentTabIndex) {
					let newLength = i.components.length - ~~num
					if (newLength > 0) {
						i.components = i.components.slice(0, newLength)
					}
				}
			})
			store.commit('SetHash')
		},
		// 替换当前组件
		OpenedSubTabsReplace (state, item) {
			let index = state.openedTabs.length - 2
			state.openedTabs.map(i => {
				if (i.menuId === state.currentTabIndex) {
					i.components.splice(index, 1, item)
				}
			})
			store.commit('SetHash')
		},
		// 从 tab 列表 移除 tab
		OpenedTabsRemove (state, menuId) {
			state.openedTabs = state.openedTabs.filter(item => {
				return item.menuId === state.homeTabMenuId || item.menuId !== menuId
			})

			// 查询当前标签是否被关闭,如果被关闭,则打开主页标签
			let tab = state.openedTabs.find(item => item.menuId === menuId)
			if (!tab) state.currentTabIndex = state.homeTabMenuId

			store.commit('SetHash')
		},
		// 关闭 其他的 tab
		CloseOthersTabs (state) {
			state.openedTabs = state.openedTabs.filter(item => {
				return item.menuId === state.homeTabMenuId || item.menuId === state.currentTabIndex
			})
			store.commit('SetHash')
		},
		// 关闭所有 tab
		CloseAllTabs (state) {
			state.openedTabs.length = 1
			state.currentTabIndex = state.homeTabMenuId
			store.commit('SetHash')
		},
	},
	actions: {},
}

5.创建RouterMethods.js用来做具体的跳转实现

import store from '@/Store/index'

const RouterMethods = Object.create(null)

// 处理 push 和 replace 2个接口的附带参数
function processData (item, payload) {
	let newItem = {}
	if(typeof item === 'string') {
		// 参数是字符串,并且带查询参数
		if(item.indexOf('?') > -1) {
			let qIndex = item.indexOf('?')
			let componentName = item.substr(0,qIndex)
			let querySring = item.substr(qIndex + 1)
			let queryArray = querySring.split('&')
			let query = Object.create(null)
			queryArray.map(i => {
				let eIndex = i.indexOf('=')
				let qKey = i.substr(0,eIndex)
				let qValue = i.substr(eIndex + 1)
				query[qKey] = qValue
			})
			newItem.path = componentName
			newItem.query = query
		}
		// 参数是字符串,不带查询参数
		else {
			newItem.path = item
		}
	}
	// 参数是 JSON 对象
	else {
		newItem = item
	}
	// 如果有第二个参数,则会覆盖原本的 query
	if(payload) newItem.query = Object.assign(newItem.query,payload)
  return newItem
}


RouterMethods.install = function (Vue, options) {
  Vue.prototype.$tab = {
    // 设置当前显示的 tab name
    showTab(data) {
      store.commit('SetCurrentTabIndex', data)
    },
    // 打开新的 tab  项
    open (item) {
      store.commit('OpenedTabsPush', item)
    },
    // 删除 tab 项
    close (menuId) {
      store.commit('OpenedTabsRemove',menuId)
    },
    // 跳转
    push(item,payload) {
      let newItem = processData(item,payload)
      store.commit('OpenedSubTabsPush',newItem)
    },
    // 后退
    back(num) {
      store.commit('OpenedSubTabsBack',num)
    },
    // 替换
    replace(item,payload) {
	    let newItem = processData(item,payload)
      store.commit('OpenedSubTabsReplace',newItem)
    },
    // 关闭所有 tab
    closeAll () {
      store.commit('CloseAllTabs')
    },
    // 关闭其他标签
    closeOthers () {
      store.commit('CloseOthersTabs')
    },
    // 根据浏览器的 url 回显 tab
    reShow() {
      store.commit('reShowHash')
    },
    // 获取当前组件的查询参数
    query () {
      return store.getters.GetQuery
    },
	  // 获取当前**的 tab
	  info () {
		  return store.getters.GetCurrentTab
	  },

  }
}

export default RouterMethods

6.在main.js中引入TabRoute.js以及store

/* import  "babel-polyfill";  */  // 兼容IE

import Vue from 'vue'
import store from '@/Store/index'
import index from './views/MainFrame.vue'
import TabRoute from '@/Router/TabRoute'
import RouterMethods from '@/Router/RouterMethods'

Vue.use(TabRoute)
Vue.use(RouterMethods)

new Vue({
    el: '#app',
    store,
    render: v => v(index)
})

7.在MainFrame.vue中追加tab显示就可以了

<el-menu :default-active="currentTabIndex" :default-openeds="spreadedMenus">

            <el-submenu v-for="(item,index) in menuList" :key="index" :index="item.menuId">
              <template slot="title">
                <i :class="item.icon"></i>
                <span>{{item.title}}</span>
              </template>
              <el-menu-item-group>
                <el-menu-item v-for="(subItem,subIndex) in item.sub"
                              :key="subIndex"
                              @click="openTab(subItem)"
                              :index="subItem.menuId">
                  {{subItem.title}}
                </el-menu-item>

具体的源码请参照:
https://download.csdn.net/download/ying940718/11085546