vue-element-admin iframes 组件操作 iframe状态保持,iframeli里面新开Tagview,切换tagview不刷新

45 篇文章 1 订阅
17 篇文章 0 订阅

最近在使用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上。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值