最近在使用vue-element-admin版本开发项目,由于新旧交替历史原因,不得不使用iframe嵌套旧版本的页面,这么一来旧版本里面比如某个页面会有新开页面,那么我们需要动态监听这个新开的页面,把它添加到tagView上面:
下面来看我的效果:
其中前一个页面是同iframe打开的
框架修改涉及到的代码如下:
1. src/layout/components/AppMain.vue代码修改为:
<template>
<section class="app-main">
<transition
name="fade-transform"
mode="out-in"
>
<keep-alive :include="cachedViews">
<router-view :key="key" />
</keep-alive>
</transition>
<Iframes v-if="iframesEnable" />
</section>
</template>
<script>
import { IFRAMES_ENABLE } from '@/utils/iframes/iframes-config'
export default {
name: 'AppMain',
components: {
Iframes: () => import('./Iframes')
},
data() {
return {
iframesEnable: IFRAMES_ENABLE
}
},
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews
},
key() {
return this.$route.path
}
}
}
</script>
<style lang="scss" scoped>
.app-main {
/* 50= navbar 50 */
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: hidden;
}
.fixed-header + .app-main {
padding-top: 50px;
}
.hasTagsView {
.app-main {
/* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px);
}
.fixed-header + .app-main {
padding-top: 84px;
}
}
</style>
<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
.fixed-header {
padding-right: 15px;
}
}
</style>
2. src/layout/components/lframes/index.vue代码修改为:
<template>
<div
v-show="iframeBoxState"
class="iframe-box"
>
<iframe
v-for="( value ) in iframeArr"
v-show="value.show"
:key="value.name"
:src="value.src + value.params"
:name="value.name"
frameborder="0"
width="100%"
height="100%"
/>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import { COMMON_ROUTER_PREFIX, findIsExistTagView, IFRAME_COUNT, read, save } from '@/utils'
import { constantRoutes } from '@/router'
export default {
name: 'IframeBox',
data() {
return {}
},
created() {
},
computed: {
...mapGetters({
iframeArr: 'iframes/iframeArr',
iframeBoxState: 'iframes/iframeBoxState'
})
},
mounted() {
// 监听iframe变化
window.addEventListener('message', (eve) => {
if (eve.data && (eve.data instanceof Array) && eve.data[0] && eve.data[1]) {
const title = eve.data[0]
const url = eve.data[1]
var num = read(IFRAME_COUNT)
var openCurrentIframe = []
var openCurrentIframeNum = 1
if (!num) {
num = 1
}
if (num > 15) {
this.$message({
message: '你打开的标签太多了,请关闭后再打开',
type: 'error'
})
return
}
const isExistTagView = findIsExistTagView(title)
const iframeId = title + '__' + url
if (!isExistTagView) {
// 获取当前可以跳转的page
openCurrentIframe = this.getRemainFirstIframeSeq()
openCurrentIframeNum = openCurrentIframe[0]
localSave(IFRAME_COUNT, parseInt(openCurrentIframe[1]) + 1)
// 更新iframePage列表
this.$store.dispatch('iframes/updatePage', iframeId)
const path = COMMON_ROUTER_PREFIX + openCurrentIframeNum
// 设置左边菜单高亮和面包屑
this.setMetaTitle(title, path, this.$route.path)
// 新开tagsView
const route = Object.assign({}, this.$route, { meta: { title }, path })
this.$store.dispatch('tagsView/addView', route)
this.$router.push({ path: path, query: { url: iframeId }})
} else {
// 更新iframePage列表
this.$store.dispatch('iframes/updatePage', iframeId)
const visitedViews = this.$store.getters.visitedViews
if (visitedViews) {
var refushPath = ''
var isaddTagview = false
visitedViews.forEach(item => {
if (item.meta.title === title) {
refushPath = item.path
this.$store.dispatch('tagsView/delView', item)
isaddTagview = true
}
})
openCurrentIframe = this.getRemainFirstIframeSeq()
openCurrentIframeNum = openCurrentIframe[0]
const path = COMMON_ROUTER_PREFIX + openCurrentIframeNum
// 设置左边菜单高亮和面包屑
this.setMetaTitle(title, refushPath, this.$route.path)
const openRoute = Object.assign({}, this.$route, { meta: { title }, path })
if (isaddTagview === false) {
// 没找到就要新增
save(IFRAME_COUNT, openCurrentIframe[1] + 1)
}
// 新开tagview
this.$store.dispatch('tagsView/addView', openRoute)
this.$router.push({ path: path, query: { url: iframeId }})
}
}
}
})
},
methods: {
setMetaTitle(title, path, currentPath) {
constantRoutes.forEach(route => {
if (route.path === '/omsiframes') {
route.children.forEach(item => {
if (item.path === path) {
item.meta.title = title
item.meta.activeMenu = currentPath
}
})
}
})
},
getRemainFirstIframeSeq() { // 从设置的页面找可以打开的页面
const visitedViews = this.$store.getters.visitedViews
var openCurrentIframeNum = 1
if (visitedViews) {
var haveOpenIframeList = []
visitedViews.forEach(item => {
if (item.path.indexOf(COMMON_ROUTER_PREFIX) > -1) {
var seqNum = item.path.slice(17)
if (seqNum && parseInt(seqNum) > 0) {
haveOpenIframeList.push(parseInt(seqNum))
}
}
})
// 去重
haveOpenIframeList = [...new Set(haveOpenIframeList)]
if (haveOpenIframeList.length > 0) {
const originList = []
for (var i = 1; i <= 15; i++) {
originList.push(i)
}
const diff = originList.filter(function(val) {
return haveOpenIframeList.indexOf(val) === -1
})
// 排序
diff.sort(function(a, b) {
return a - b
})
openCurrentIframeNum = diff[0] ? diff[0] : 1
return [openCurrentIframeNum, parseInt(haveOpenIframeList.length)]
}
}
return [openCurrentIframeNum, 0]
}
}
}
</script>
<style>
.iframe-box {
/*position: absolute;*/
top: 0;
left: 0;
width: 100%;
padding: 0 15px;
z-index: 100;
/*height: calc(100% - 32px);*/
height: 810px;
overflow-x: scroll;
overflow-y: scroll;
}
</style>
3. src/router/index.js代码修改为:
export const constantRoutes = [
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index')
}
]
},
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/auth-redirect',
component: () => import('@/views/login/auth-redirect'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error-page/404'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error-page/401'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
name: 'Dashboard',
meta: { title: 'dashboard', icon: 'dashboard', affix: true }
}
]
},
{
path: '/lassIframes',
component: Layout,
redirect: '/iframe',
hidden: true,
children: [
{
path: 'lassIndex1',
component: () => import('@/views/lass/iframe/index1'),
name: 'iframeDashboard1',
meta: { title: '', icon: 'dashboard', noCache: true }
},
{
path: 'lassIndex2',
component: () => import('@/views/lass/iframe/index2'),
name: 'iframeDashboard2',
meta: { title: '', icon: 'dashboard', noCache: true }
},
。。。。。。。。。。。。。。。。。此处省略,建立15个空白路由,根据情况而定
{
path: 'lassIndex15',
component: () => import('@/views/lass/iframe/index15'),
name: 'iframeDashboard15',
meta: { title: '', icon: 'dashboard', noCache: true }
}
]
}
]
4. src/store/modules/iframes.js 代码修改为:
import { PAGE_LIST } from '@/utils/iframes/iframes-config'
import Vue from 'vue'
import { decrypt, IFRAME_PAGES, read, save } from '@/utils'
import config from '@/config'
const state = PAGE_LIST()
for (const key in state) {
// eslint-disable-next-line
if (state.hasOwnProperty(key)) {
state[key].id = key
state[key].params = ''
state[key].enable = false
state[key].show = false
}
}
state['IFRAME_BOX_STATE'] = false
const getters = {
iframeArr: state => {
const arr = []
for (const key in state) {
// eslint-disable-next-line
if (state.hasOwnProperty(key)) {
if (state[key].enable) {
arr.push(state[key])
}
}
}
return arr
},
iframeBoxState: state => {
return state['IFRAME_BOX_STATE']
}
}
const mutations = {
ADD_IFRAME(state, id) {
Vue.set(state[id], 'enable', true)
},
DELETE_IFRAME(state, id) {
Vue.set(state[id], 'enable', false)
},
SHOW_IFRAME(state, id) {
Vue.set(state[id], 'show', true)
},
HIDE_IFRAME(state, id) {
Vue.set(state[id], 'show', false)
},
SHOW_IFRAME_BOX(state) {
state['IFRAME_BOX_STATE'] = true
},
HIDE_IFRAME_BOX(state) {
state['IFRAME_BOX_STATE'] = false
},
CHANGE_PARAMS(state, obj) {
Vue.set(state[obj.id], 'params', obj.params)
},
updateState(state) {
for (const key in state) {
// eslint-disable-next-line
if (state.hasOwnProperty(key)) {
state[key].id = key
state[key].params = ''
state[key].enable = false
state[key].show = false
}
}
},
setIframeIds(state, iframePages) {
if (typeof iframePages !== 'string' && iframePages) {
state.iframePages = JSON.stringify(iframePages)
} else {
state.iframePages = iframePages
}
save(IFRAME_PAGES, state.iframePages)
}
}
const actions = {
createdPage({ commit }, obj) {
if (obj.params) {
commit('CHANGE_PARAMS', obj)
}
commit('ADD_IFRAME', obj.id)
commit('SHOW_IFRAME', obj.id)
commit('SHOW_IFRAME_BOX')
},
beforeDestroyPage({ commit }, id) {
commit('HIDE_IFRAME_BOX')
commit('DELETE_IFRAME', id)
},
activatedPage({ state, commit }, id) {
if (state[id].show) return
commit('SHOW_IFRAME', id)
commit('SHOW_IFRAME_BOX')
},
deactivatedPage({ state, commit }, id) {
if (!state[id].show) return
commit('HIDE_IFRAME_BOX')
commit('HIDE_IFRAME', id)
},
changeParams({ commit }, obj) {
commit('CHANGE_PARAMS', obj)
},
setPage({ state, commit }, iframesid) {
Object.assign(state, iframesid)
for (const key in iframesid) {
if (state.hasOwnProperty(key)) {
state[key].id = key
state[key].params = ''
state[key].enable = false
state[key].show = false
}
}
},
updatePage({ state, commit, dispatch }, iframeId) {
const autoKey = iframeId
var iframes = iframeId.split('__')
const sessionId = read('sessionId')
const saltSecrets = read('saltSecrets')
const sid = decrypt(sessionId, saltSecrets)
const iframAddId = {}
var uri = ''
if (iframes[1].indexOf('?') > -1) {
uri = iframes[1] + '&sid=' + sid
} else {
uri = iframes[1] + '?sid=' + sid
}
iframAddId[autoKey] = {
name: iframes[0],
src: config.lassUrl + uri
}
var delKey = ''
for (const key in state) {
if (state.hasOwnProperty(key)) {
if (key.indexOf('__') > -1) {
var keyNames = key.split('__')
if (keyNames[0] && keyNames[0] === iframes[0]) {
delKey = key
break
}
}
}
}
if (delKey) {
dispatch('beforeDestroyPage', iframeId)
Vue.delete(state, delKey)
}
const iframIds = {}
Object.assign(state, iframAddId)
for (const key in state) {
if (state.hasOwnProperty(key)) {
if (key === autoKey) {
state[key].id = key
state[key].params = ''
state[key].enable = true
state[key].show = false
}
}
}
for (const key in state) {
if (state.hasOwnProperty(key) && key !== 'IFRAME_BOX_STATE') {
iframIds[key] = {
name: state[key].name,
src: state[key].src
}
}
}
save(IFRAME_PAGES, JSON.stringify(iframIds))
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
5. src/utils/iframes/iframes-config.js 代码修改为:
import { iframePageList } from '@/utils'
/**
* 是否启用全局iframes缓存组件
*/
export const IFRAMES_ENABLE = true
const IFRAMES_PAGE = { ...iframePageList() }
export function PAGE_LIST() {
return IFRAMES_PAGE
}
6. src/utils/iframes/iframes-mixin.js代码修改为:
import { mapActions, mapState } from 'vuex'
import { PAGE_LIST } from '@/utils/iframes/iframes-config'
export default {
data() {
return { MISSING_ID: false }
},
computed: {
...mapState({
iframes: state => state.iframes
})
},
// 页面创建时新建对应 iframe
created() {
const pageList = PAGE_LIST()
if (this.PAGE_ID === null || pageList[this.PAGE_ID] === null) {
this.MISSING_ID = false
console.error('缺少 PAGE_ID 参数')
return
}
const obj = { id: this.PAGE_ID }
if (this.PARAMS) obj.params = this.PARAMS
this.createdPage(obj)
},
// 切换进入页面时显示对应 iframe
activated() {
if (this.MISSING_ID) return
const params = this.iframes[this.PAGE_ID].params
if (params != null && this.PARAMS != null && params !== this.PARAMS) {
this.changeParams({ id: this.PAGE_ID, params: this.PARAMS })
}
this.activatedPage(this.PAGE_ID)
},
// 切换离开页面时隐藏对应 iframe
deactivated() {
if (this.MISSING_ID) return
this.deactivatedPage(this.PAGE_ID)
},
// 切换离开页面时销毁对应 iframe
beforeDestroy() {
if (this.MISSING_ID) return
this.beforeDestroyPage(this.PAGE_ID)
},
methods: {
...mapActions({
createdPage: 'iframes/createdPage',
activatedPage: 'iframes/activatedPage',
deactivatedPage: 'iframes/deactivatedPage',
beforeDestroyPage: 'iframes/beforeDestroyPage',
changeParams: 'iframes/changeParams',
setPage: 'iframes/setPage'
})
}
}
7. src/views/iframes/xxx1/index.vue 代码修改为:
<template>
<div> </div>
</template>
<script>
import iframeMixin from '@/utils/iframes/iframes-mixin'
export default {
name: 'Supplier',
mixins: [iframeMixin],
data() {
return { PAGE_ID: 'supplier_Supplier' }
}
}
</script>
注意上面有个判断tagview是否重复的地方:
/**
* 查询所有tagview中是否已经存在和当前一样的view
* @param routes
* @param data
*/
export function findIsExistTagView(title) {
let iframePages = read(IFRAME_PAGES) || ''
if (iframePages) {
iframePages = JSON.parse(iframePages)
}
let isExistTagView = false
if (iframePages) {
for (const key in iframePages) {
if (iframePages.hasOwnProperty(key)) {
if (key.indexOf('__') > -1) {
const iframes = key.split('__')
if (iframes[0] && iframes[0] === title) {
isExistTagView = true
}
}
}
}
}
return isExistTagView
}
动态路由根据后台查询的数据写入iframePagelist
/**
* 后台查询的菜单数据iframe设置成列表
* @param routes
* @param data
*/
export function getIframeIdList(routes, data, iframIds) {
const sessionId = read('sessionId')
const saltSecrets = read('saltSecrets')
const sid = decrypt(sessionId, saltSecrets)
data.forEach(item => {
const menu = {
children: [],
name: item.name,
src: item.url
}
if (item.type && item.type === 4) {
iframIds[item.path + '_' + item.name] = {
name: item.name,
src: OMS_DOMAIN + '/' + item.url + '?sid=' + sid
}
}
if (item.children) {
getIframeIdList(menu.children, item.children, iframIds)
}
})
return iframIds
}
之后一个,在你的老系统里面,新开页面的地方加上
window.parent.postMessage([title, uri], '*');让父页面监听,然后在iframe 里面就可以新开一个页面放在tagview上了,另外还要在你的tagview上去重,以免开很多重复的页面在tagview上。