0

0

使用Vue如何实现集成Iframe页面

亚连

亚连

发布时间:2018-06-21 11:43:08

|

3761人浏览过

|

来源于php中文网

原创

这篇文章主要介绍了vue集成iframe页面的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

1. 项目需求

我们切换为vue框架是后面的事情,之前还有一些功能页面是用jsp页面写的,而我们的管理系统需要既支持Vue的url,又要支持这些发布之后的jsp页面

还有一个就是切换tab回来的时候之前输入的东西还要存在

系统页面截图

立即学习前端免费学习笔记(深入)”;

2. 实现思路

针对这个问题,我们最开始的实现思路是写了一个iframe的通用组件,然后把不同的http的页面的url传递进来进行切换,但是这样不满足第二条,我们发现只要切换了vue的路由,然后再切回http的页面,iframe中的src属性的页面就会从新刷新,没有办法保留住东西,于是就有了下面的实现思路

我们在vue的router-view同级别添加了一个iframeTemp组件,其实就是一个elementUI的tab组件,然后把tab组件的头的样式隐藏在我们菜单栏的下面

<template>
 <!--路由渲染的功能模块区域-->
 <p class="router-out-content">
  <!--缓存部分页面的写法-->
  <keep-alive>
   <router-view v-show="!showIframe" class="position router-content" v-if="$route.meta.keepAlive"></router-view>
  </keep-alive>
  <router-view v-show="!showIframe" class="position router-content" v-if="!$route.meta.keepAlive"></router-view>
  <!--兼容系统外部页面-->
  <iframe-temp v-show="showIframe"></iframe-temp>
 </p>
</template>
<style scoped lang="scss">
 .position {
  position: relative
 }

 .router-out-content {
  position: static;
 }
</style>
<script>
import { mapState } from 'vuex'
import iframeTemp from '@/containers/main/IframeTemplate.vue'
export default {
 data() {
  return {}
 },
 components: {
  iframeTemp
 },
 computed: {
  ...mapState([
   'showIframe'
  ])
 }
}
</script>
/*
 * IframeTemplate.vue组件的内部
 **/

 <template>
 <!--iframe页面展示区域-->
 <p id="fwIframe">
  <!--<Tabs class="full temporary-tabs" v-model="store.state.iframeSelectTab" type="card">-->
  <Tabs class="full temporary-tabs" :value="iframeSelectTab" type="card">
   <TabPane
    v-for="(item, index) in iframeTabData"
    :key="item.tag"
    :label="item.name"
    :name="item.tag"
   >
    <iframe :key="item.tag" v-once :src="item.url" frameborder="0"></iframe>
   </TabPane>
  </Tabs>
 </p>
</template>
<style lang="scss">
 #fwIframe {
  /*测试位置的时候显示这段--开始*/
  /*width: 100%;*/
  /*height: 100%;*/
  /*background-color: red;*/
  /*display: block !important;*/
  /*测试位置的时候显示这段--结束*/
  position: absolute;
  left: 0;
  right: 0;
  top: 45px;
  bottom: 0;
  z-index: 5000 !important;
  .el-tab-pane {
   height: 100%;
   width: 100%;
   iframe {
    /*height: auto;*/
    min-height: 600px;
    /*height: calc(100% - 45px);*/
    width: 100%;
   }

  }
  .full {
   position: relative;
   left: 0;
   right: 0;
   top: 0;
   bottom: 0;
  }
 }
</style>
<script>

 // selectTabCode=>iframeSelectTab
 // tabsList=>iframeTabData
 import {mapState} from 'vuex'
 import * as mainConst from '@/store/mainConst.js'
 export default{
  data(){
   return {
//    tabsList: [],
//    selectTabCode: ''
   }
  },
  computed: {
   ...mapState([
    'iframeTabData',
    'iframeSelectTab',
    'navTabData',
    'systemName'
   ])
  },
  mounted(){
   const _this = this

   // 1、监听添加iframe中tab的广播
   this.$root.bus.$on('addIframeTab', function (item) {

    // _this.tabsList.push(item)
    // _this.selectTabCode = item.tag
    _this.$store.commit(mainConst.M_IFRAME_PUSH_TAB, item)
    _this.$store.commit(mainConst.M_IFRAME_CHANGE_SELECTCODE, item.tag)
   })

   // 2、监听切换iframe中tab的广播
   this.$root.bus.$on('changeIframeTab', function (tag) {
    _this.$store.commit(mainConst.M_IFRAME_CHANGE_SELECTCODE, tag)

   })
   // 3、监听删除iframe中tab的广播
   this.$root.bus.$on('deleteIframeTab', function (obj) {
    // 1、删除iframe中的指定tab页面
    _this.$store.commit(mainConst.M_IFRAME_DELETE_TAB, obj)
    // _this.tabsList = _this.tabsList.filter(tab => tab.tag !== obj.tag)

    // 2、如果删除的一级tab不是当前激活的一级tab,TabsTemeplate中的一级tab删除事件已经在vuex中删除了,不需要做路由跳转操作了
    let index = obj.index
    for (let i = 0; i < _this.navTabData.length; i++) {
     if (_this.navTabData[i].active) {
      return
     }
    }

    // 3、如果删除的一级tab是当前激活的一级tab,
    const con = _this.navTabData[index - 1] || _this.navTabData[index]
    let url = `/${_this.systemName}`
    if (con) {
     // 还有其他的一级tab,就赋值其他的一级tab的url,探后跳转
     url = con.url
     con.active = true

     // 如果还有其他一级的tab,那么还要判断跳转的页面是不是iframe
     if (url.toLowerCase().indexOf("/iframe") == 0) {
      // 如果是iframe页面,显示iframe,广播iframe的切换tab切换事件,路由进行跳转
      _this.$store.commit(mainConst.M_SHOW_IFRAME)
      _this.$root.bus.$emit("changeIframeTab", url.slice(8))

     } else {
      // 如果不是iframe页面,隐藏iframe,路由进行跳转
      _this.$store.commit(mainConst.M_HIDE_IFRAME)
      // _this.$store.commit(mainConst.M_UPDATE_NAVTABDATA, {navIndex: index})
     }
    }
    else {
     // 没有其他的一级tab,直接隐藏iframe,跳首页
     _this.$store.commit(mainConst.M_HIDE_IFRAME)
    }

    _this.$router.push(url)
   })
  }
 }
</script>

之后的ifram组件的显示隐藏和tab切换,都是通用vuex和bus事件广播实现的

B2S商城系统
B2S商城系统

B2S商城系统B2S商城系统是由佳弗网络工作室凭借专业的技术、丰富的电子商务经验在第一时刻为最流行的分享式购物(或体验式购物)推出的开源程序。开发采用PHP+MYSQL数据库,独立编译模板、代码简洁、自由修改、安全高效、数据缓存等技术的应用,使其能在大浏览量的环境下快速稳定运行,切实节约网站成本,提升形象。注意:如果安装后页面打开出现找不到数据库等错误,请删除admin下的runtime文件夹和a

下载

/*
 * mainConst.js
 **/


/*****************************getter常量****************************************/
export const G_GET_NAVTABDATA = 'G_GET_NAVTABDATA'

/*****************************mutations常量*************************************/
// 一级tab处理
export const M_PUSH_NAVTABDATA = 'M_PUSH_NAVTABDATA'
export const M_DELETE_NAVTABDATA = 'M_DELETE_NAVTABDATA'
export const M_UPDATE_NAVTABDATA = 'M_UPDATE_NAVTABDATA'

// iframe切换处理
export const M_SHOW_IFRAME = 'M_SHOW_IFRAME'
export const M_HIDE_IFRAME = 'M_HIDE_IFRAME'

// iframe添加,删除,选择处理
export const M_IFRAME_PUSH_TAB='M_IFRAME_PUSH_TAB'
export const M_IFRAME_DELETE_TAB='M_IFRAME_DELETE_TAB'
export const M_IFRAME_CHANGE_SELECTCODE='M_IFRAME_CHANGE_SELECTCODE'

// 设置全局系统变量
export const M_SET_SYSTEMNAME = 'M_SET_SYSTEMNAME'

/*****************************actions常量***************************************/
// export const A_REQUEST_DATA = 'A_REQUEST_DATA'
/*
 * mainModule.js
 **/

import * as mainConst from './mainConst.js'

export default {
 state: {
  // 一级Tab导航数据集合
  navTabData: [],
  // 进入的主系统前缀
  systemName:'',
  // 控制路由同级的Iframe的显示隐藏
  showIframe: false,
  // iframe页面中的选中页签的code值
  iframeSelectTab:'',
  // iframe页面的tab数据集合
  iframeTabData:[]

 },
 getters: {
  [mainConst.G_GET_NAVTABDATA](state, getters){
   return state.navTabData
  }
 },
 mutations: {
  // 一级tab处理
  [mainConst.M_UPDATE_NAVTABDATA](state, payload){
   const index = payload.navIndex
   state.navTabData.forEach((item)=> {
    item.active = false
   })

   // 当你利用索引直接设置一个项时是不能触发视图的从新渲染的,下面是老方法和解决办法
   // state.navTabData[index].active=true
   let newItem = Object.assign({}, state.navTabData[index], {active: true})
   // console.log(newItem, 'store newItem')
   state.navTabData.splice(index, 1, newItem)
  },
  [mainConst.M_PUSH_NAVTABDATA] (state, payload) {
   state.navTabData.push(payload)
  },
  [mainConst.M_DELETE_NAVTABDATA] (state, payload) {
   state.navTabData.splice(payload.navIndex, 1)
  },
  // Iframe显示隐藏切换处理
  [mainConst.M_SHOW_IFRAME] (state, payload) {
   state.showIframe = true
  },
  [mainConst.M_HIDE_IFRAME] (state, payload) {
   state.showIframe = false
  },
  // Iframe添加,删除,选中处理
  [mainConst.M_IFRAME_PUSH_TAB] (state, payload) {
   state.iframeTabData.push(payload)
  },
  [mainConst.M_IFRAME_DELETE_TAB] (state, payload) {
   state.iframeTabData = state.iframeTabData.filter(tab => tab.tag !== payload.tag)
  },
  [mainConst.M_IFRAME_CHANGE_SELECTCODE] (state, payload) {
   state.iframeSelectTab=payload
  },
  // 设置全局system变量
  [mainConst.M_SET_SYSTEMNAME] (state, payload) {
   state.systemName=payload
  }
 },
 actions: {
  // actions的最终功能是修改state,但是它不直接修改state,而是调用mutations
  // async [aboutConst.A_REQUEST_DATA]({dispatch,commit}) {
  //  commit(aboutMutations.REQUEST_LOADING)
  //  await service.getMovieListData('{"movieType":"in_theaters","pageIndex":2,"start":0,"count":10}')
  //  console.log(333333)
  //  await function(){setTimeout(function () {
  //   commit(aboutMutations.REQUEST_FAILD)
  //  },6000)}()
  //  console.log(66666)
  // }

  // actions的最终功能是修改state,但是它不直接修改state,而是调用mutations
  // async [aboutConst.A_REQUEST_DATA]({dispatch,commit}) {
  //  commit(aboutMutations.REQUEST_LOADING)
  //  await service.getMovieListData('{"movieType":"in_theaters","pageIndex":2,"start":0,"count":10}')
  //  console.log(333333)
  //  await function(){setTimeout(function () {
  //   commit(aboutMutations.REQUEST_FAILD)
  //  },6000)}()
  //  console.log(66666)
  // }
 }
}
/*
 * 三级菜单的点击处理
 **/
<template>
 <!--三级菜单导航功能-->
 <p class="main-nav f14 clearfix" @mouseleave="funMenu.menuIsShow=false">
  <p class="f_l lt-tab">
   <ul class="l-nav clearfix">
    <li class="main f_l">
     <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="f16 fun" @click="getMainMenu">功能导航</a>
     <p class="more-menu clearfix" v-show="funMenu.firstMenu.length&&funMenu.menuIsShow">
      <!--一级导航-->
      <ul class="first-menu f_l">
       <li v-for="(item,index) in funMenu.firstMenu" @mouseover="clickByMenu($event,item,'firstMenu')">
        <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" :class="{active:item.active}" :index="index">{{item.resourceName}}</a>
       </li>
      </ul>
      <!--二级导航-->
      <ul class="next-menu f_l" v-show="funMenu.nextMenu.length">
       <li
        v-for="(item,index) in funMenu.nextMenu"
        @mouseover="clickByMenu($event,item,'nextMenu')"
        @click="clickMenuJump(funMenu.nextMenu, item)"
       >
        <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" :class="{active:item.active}" :index="index">{{item.resourceName}}</a>
       </li>
      </ul>
      <!--三级导航-->
      <!--存在四级导航-->
      <p class="last-menu f_l dl" v-show="funMenu.lastMenu.length">
       <p v-for="(item,index) in funMenu.lastMenu" class="dt">
        <p v-if="item.childFuncs.length">
         <span>{{item.resourceName }}</span>
         <ul class="dd">
          <li v-for="(item,index) in item.childFuncs"
           @click="clickByMenu($event,item,'lastMenu')">
           <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >{{item.resourceName}}</a>
           <!--:class="{active:item.active}"-->
          </li>
         </ul>
        </p>
        <!--三级导航可点击-->
        <p v-else>
         <ul class="dd">
          <li @click="clickByMenu($event,item,'lastMenu')">
           <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >{{item.resourceName}}</a>
           <!--:class="{active:item.active}"-->
          </li>
         </ul>
        </p>

       </p>
      </p>
     </p>
    </li>
    <li class="nav-index f_l">
     <!--<router-link :to="'/'+$store.state.systemName">首页</router-link>-->
     <a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" @click="goHome">首页</a>
    </li>
   </ul>
  </p>
 </p>
</template>
<style scoped lang="scss">
 .main-nav {
  position: relative;
  height: 42px;
  line-height: 42px;
  background: #eee;
  border-bottom: 1px solid #ddd;
 }

 .main-nav a {
  color: #303e51;
  text-decoration: none;
 }

 .main-nav a:hover {
  color: #438eb9;
 }

 .main-nav .main {
  /*padding: 0 16px;*/
  text-align: center;
  border-right: 1px solid #ddd;
  position: relative;
  background: #eee;
  width: 122px;
 }

 .main-nav .main.active, .main-nav .main:hover {
  background: white;
 }

 .main-nav .more-menu {
  position: fixed;
  top: 84px;
  left: 0;
  max-height: 500px;
  bottom: 124124px;
  z-index: 998;
  background: #fff;
  border: 1px solid #ddd;
  border-left: none;
  border-top: 0;
  overflow: hidden;
  box-shadow: 1px 1px 10px #ddd;
 }

 .main-nav .more-menu ul, .main-nav .more-menu .dl {
  text-align: left;
  overflow: auto;
 }

 .main-nav .more-menu a {
  font-size: 14px;
  color: #303e51;
  text-decoration: none;
 }

 .main-nav .more-menu a:hover, .main-nav .more-menu a.active {
  color: rgb(46, 167, 224);
 }

 .main-nav .more-menu .first-menu {
  height: 100%;
  border-right: 1px solid #ddd;
  box-shadow: -1px 0px 5px #ddd inset;
  /*width: 138px;*/
 }

 .main-nav .more-menu .first-menu li {
  height: 36px;
  line-height: 36px;
  margin: 0 15px 0 6px;
  min-width: 94px;
 }

 .main-nav .more-menu .first-menu a {
  display: block;
  background: url(../../asserts/images/home/main/icon_1.png) no-repeat 5px center;
  width: 100%;
  height: 100%;
  border-bottom: 1px solid #dddddd;
  padding-left: 20px;
  box-sizing: border-box;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
  text-indent: 5px;
 }

 .main-nav .more-menu .first-menu a.active, .main-nav .more-menu .first-menu a:hover {
  background: url(../../asserts/images/home/main/icon_2.png) no-repeat 5px center rgb(46, 167, 224);
  color: white;
  border: 0;
 }

 .main-nav .more-menu .next-menu {
  height: 100%;
  border-right: 1px solid #ddd;
  box-shadow: -1px 0px 5px #ddd inset;
  /*width: 138px;*/
  line-height: 14px;
 }

 .main-nav .more-menu .next-menu li:first-child {
  margin-top: 10px;
 }

 .main-nav .more-menu .next-menu li {
  margin-bottom: 16px;
  margin-left: 16px;
 }

 .main-nav .more-menu .next-menu li a {
  border-left: 2px solid transparent;
  padding-left: 10px;
  margin-right: 24px;
 }

 .main-nav .more-menu .next-menu li a:hover, .main-nav .more-menu .next-menu li a.active {
  border-left: 2px solid rgb(46, 167, 224);
 }

 .main-nav .more-menu .last-menu {
  height: 100%;
  min-width: 288px;
  line-height: 14px;
 }

 .main-nav .more-menu .last-menu .dt {
  margin-left: 16px;
  margin-top: 10px;
  span {
   color: #566678;
  }
 }

 .main-nav .more-menu .last-menu .dd {
  color: #7a8897;
  margin-top: 16px;
  margin-left: 4px;
  > li {
   margin-bottom: 16px;
   a {
    border-left: 2px solid transparent;
    padding-left: 6px;
    margin-right: 16px;
    &:hover, &.active {
     border-color: #2ea7e0;
    }
   }
  }
 }

 /*.main-nav .more-menu .last-menu dd a:hover,.main-nav .more-menu .last-menu dd a.active{*/
 /*border-left: 2px solid rgb(46,167,224);*/
 /*}*/
 .main-nav .main .fun {
  width: 100%;
  height: 100%;
  display: block;
 }

 .main-nav .main .fun:before {
  content: "";
  width: 18px;
  height: 18px;
  background: url("../../asserts/images/home/main/icon-all.png");
  background-position: -89px -7px;
  display: inline-block;
  margin-right: 10px;
  margin-top: 2px;
  vertical-align: text-top;
 }

 .main-nav .l-nav {
  z-index: 2;
 }

 .main-nav .nav-index {
  width: 90px;
  text-align: center;
  position: relative;
  background: #eee;
 }

 .main-nav .nav-index:after {
  content: "";
  width: 8px;
  height: 40px;
  background: url(../../asserts/images/home/main/shadow-l.png);
  position: absolute;
  top: 2px;
  left: 90px;
 }

 .main-nav .lt-tab {
  position: absolute;
  left: 0;
  z-index: 2;
  border-bottom: 1px solid #ddd;
 }

 /*tab--------*/
 .main-nav .ct-tab {
  position: absolute;
  z-index: 1;
  left: 213px;
  width: 10000000px;
 }

 .main-nav .ct-tab .ct-ul {

 }

 .main-nav .ct-tab .ct-ul li {
  position: relative;
  float: left;
 }

 .main-nav .ct-tab .ct-ul li a {
  height: 24px;
  line-height: 24px;
  margin: 9px 0;
  min-width: 90px;
  /*max-width: 190px;*/
  border-right: 1px solid #ddd;
  display: block;
  text-align: center;
  position: relative;
 }

 .main-nav .ct-tab .ct-ul li a i {
  display: none;
 }

 .main-nav .ct-tab .ct-ul li a i {
  display: none;
 }

 .main-nav .ct-tab .ct-ul li a .content {
  display: block;
  max-width: 190px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
 }

 .main-nav .ct-tab .ct-ul li a:hover {
  z-index: 1;
 }

 .main-nav .ct-tab .ct-ul li:first-child a:hover, .main-nav .ct-tab li:first-child a.active {
  margin-left: 0;
  margin-right: 0;
 }

 .main-nav .ct-tab .ct-ul li a:hover, .main-nav .ct-tab li a.active {
  max-width: 250px;
  display: block;
  text-align: center;
  position: relative;
  border: 0;
  margin: 0 -20px;
  margin-top: 4px;
  color: black;
  padding: 0;
 }

 .main-nav .ct-tab .padding {
  width: auto;
  padding: 0 16px;
 }

 .main-nav .ct-tab .ct-ul li a:hover > i, .main-nav .ct-tab .ct-ul li a.active > i {
  display: inline-block;
  width: 34px;
  height: 37px;
  float: left;
 }

 .main-nav .ct-tab .ct-ul li a:hover .line-l {
  background: url(../../asserts/images/home/main/line_left.png) no-repeat;
 }

 .main-nav .ct-tab .ct-ul li a:hover .line-r {
  background: url(../../asserts/images/home/main/line_right.png) no-repeat;
 }

 .main-nav .ct-tab .ct-ul li a.active .line-l {
  background: url(../../asserts/images/home/main/line_sel_left.png) no-repeat;
 }

 .main-nav .ct-tab .ct-ul li a.active .line-r {
  background: url(../../asserts/images/home/main/line_sel_right.png) no-repeat;
 }

 .main-nav .ct-tab .ct-ul li a:hover .content, .main-nav .ct-tab li a.active .content {
  border-top: 1px solid #ddd;
  float: left;
  line-height: 36px;
  min-width: 60px;
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  background: rgb(245, 245, 245);
 }

 .main-nav .ct-tab .ct-ul li a:hover .cha, .main-nav .ct-tab .ct-ul li a.active .cha {
  background: rgb(245, 245, 245);
  width: 20px;
  height: 36px;
  line-height: 36px;
  border-top: 1px solid #ddd;
  padding-left: 7px;
  color: #303e51;
 }

 .main-nav .ct-tab .ct-ul li a.active .content, .main-nav .ct-tab .ct-ul li a.active .cha {
  background: white;
 }

 .main-nav .ct-tab .ct-ul li a .cha {
  color: #eee;
 }

 .main-nav .ct-tab .ct-ul li a .cha:hover {
  color: black;
 }

 .main-nav .ct-tab .ct-ul li a.active {
  z-index: 2;
 }
</style>
<script>
 import axios from 'axios'
 import { mapState} from 'vuex'
 import * as mainConst from '@/store/mainConst.js'
 import config from '@/config/index.js'
 import storage from '@/utils/storage.js'
 export default{
  data(){
   return {
    funMenu: {
     // 一级菜单
     firstMenu: [],
     // 二级菜单
     nextMenu: [],
     // 三级菜单
     lastMenu: [],
     // 是否显示
     menuIsShow: true
    }
   }
  },
  computed: mapState({
   // 箭头函数可使代码更简练
   funcMenuList: state => state.funcMenuList,
  }),
  methods: {
   // 跳转首页
   goHome(){
    // 跳转首页就关闭iframe
    this.$store.commit(mainConst.M_HIDE_IFRAME)
    this.$router.push(`/${this.$store.state.systemName}`)
   },
   // ★★★★★调用方法获取三级菜单列表★★★★★
   getMainMenu(){
    var _this = this
    if (this.funMenu.firstMenu.length) {
     this.funMenu.menuIsShow = true
    } else {
     if (config.setting.funcMenu) {
      _this.funMenu.firstMenu = storage.getItem('hivescm.userAuthor').menus.funcs
     } else {
      axios.get("data/menu_json.json")
       .then(function (res) {
        _this.funMenu.firstMenu = res.data.result.funcs
       })
     }
    }
   },
   // 点击菜单展开下一级别列表事件
   clickByMenu(e, menuItem, level){
    let menuList = this.funMenu[level]
    switch (level) {
     case "firstMenu": {
      this.funMenu.nextMenu = this.getFirstAndNextVal(menuList, menuItem)
      this.funMenu.lastMenu = []
     }
      break
     case "nextMenu": {
      if (!menuItem.url.length) this.funMenu.lastMenu = this.getFirstAndNextVal(menuList, menuItem)
//      menuItem.url.length ? this.clickMenuJump(menuList, menuItem) : this.funMenu.lastMenu = this.getFirstAndNextVal(menuList, menuItem)
     }
      break
     case "lastMenu": {
      this.clickMenuJump(menuList, menuItem)
     }
      break
    }
   },
   // ★★★★★点击有url的菜单,跳转事件★★★★★
   clickMenuJump(menuList, menuItem){
    if (!menuItem.url.length) return
    this.funMenu.menuIsShow = false
    this.lastmenuChange(menuList, menuItem)
    let iframeTabItem = {}
    // 1、路由跳转和iframe的显示隐藏
    if (menuItem.url.toLowerCase().indexOf("/") != 0 || menuItem.url.toLowerCase().indexOf("/iframe") == 0) {
     // 判断如果是iframe的url,显示iframe
     // 定义一个新的item对象,防止对象的引用
     iframeTabItem = Object.assign({}, menuItem)
     this.$store.commit(mainConst.M_SHOW_IFRAME)
     // 待优化:应该有优化为手动赋值样式
     // (1)、此处利用router-view的特性,让一级tab变颜色
     // (2)、这个还是控制一级tab点击切换tab标签的重要因素
     // 因为原始的iframe的url已经改变,所以要保存到一个新的变量里面,如果已经有了就不需要在放了
     if (!menuItem.iframeUrl) {
      menuItem.iframeUrl = menuItem.url
      let userId = storage.getItem('hivescm.userAuthor').id
      let token = storage.getItem('hivescm.userAuthor').token
      iframeTabItem.url = `${menuItem.url}?userId=${userId}&token=${token}`
     } else {
      let userId = storage.getItem('hivescm.userAuthor').id
      let token = storage.getItem('hivescm.userAuthor').token
      iframeTabItem.url = `${menuItem.iframeUrl}?userId=${userId}&token=${token}`
      console.log(iframeTabItem.url)
//      iframeTabItem.url = menuItem.iframeUrl
     }
     menuItem.url = `/iframe/${menuItem.tag}`
     this.$router.push(`/iframe/${menuItem.tag}`)

    } else {
     // 判断如果是spa的url,隐藏iframe
     this.$store.commit(mainConst.M_HIDE_IFRAME)
     menuItem.url=`${menuItem.url}?permissionId=${menuItem.permissionId}`
     this.$router.push({path:menuItem.url,query:{permissionId:menuItem.permissionId}})
    }

    // 2、判断vuex中是否有重复的tab标签
    let navTabData = this.$store.state.navTabData
    for (let i = 0; i < navTabData.length; i++) {
     if (navTabData[i].url == menuItem.url) {
      // 已经有页签了,一级tab内容不重新渲染
      // 切换一级tab页签的激活样式
      this.$store.commit(mainConst.M_UPDATE_NAVTABDATA, {navIndex: i})
      // 从新计算一级tab位置
      this.$root.bus.$emit("clickLastMenu", menuItem)

      if (menuItem.url.toLowerCase().indexOf("/iframe") == 0) {
       // 如果已经iframe中的tab已经存在,那么触发iframe中的切换事件
//       this.$store.commit(mainConst.M_SHOW_IFRAME)
       this.$root.bus.$emit("changeIframeTab", menuItem.url.slice(8))
      }
      return
     }
    }

    // 3、向vuex中添加一级tab
    // 默认是否选中
    menuItem.active = true
    // 向一级tab中添加新的tab标签
    this.$store.commit(mainConst.M_PUSH_NAVTABDATA, menuItem)
    this.$store.commit(mainConst.M_UPDATE_NAVTABDATA, {navIndex: navTabData.length - 1})
    // 向iframe中的tab添加页签
    this.$root.bus.$emit("addIframeTab", iframeTabItem)
   },
   // 清空导航属性值,确保再次点击无选中样式及不匹配数据
   lastmenuChange(menuList, menuItem){
    this.funMenu.firstMenu.forEach(function (item) {
     item.active = false
    })
    this.funMenu.nextMenu.forEach(function (item) {
     item.active = false
    })
    this.funMenu.lastMenu.forEach(function (item) {
     item.active = false
    })
    this.funMenu.nextMenu = []
    this.funMenu.lastMenu = []
   },
   // 增加选中样式及赋值下级菜单
   getFirstAndNextVal(menuList, menuItem){
    var childFuncs = []
    for (let i = 0; i < menuList.length; i++) {
     if (menuList[i].permissionId == menuItem.permissionId) {
      menuList[i].active = true
      childFuncs = menuList[i].childFuncs || []
     } else {
      menuList[i].active = false
     }
    }
    return childFuncs
   }
  }
 }
</script>

还要添加一个没用的路由,因为我们的锚记还要发生变化

/*
 * iframe/router/index.js
 */
const systemNamePrefix = "iframe_"
import MainContainer from '@/containers/MainContainer.vue'
import IframeComponent from '@Iframe/containers/IframeComponent.vue'

export default [
 {
  path: '/iframe',
  component: MainContainer,
  children: [
   {path: ':tag', component: IframeComponent, meta: {requiresAuth: true, keepAlive: true}},
  ],
  meta: {requiresAuth: true}
 }
]
/*
 * iframeComponent.vue,一个没用的vue文件,只是为了让浏览器中的锚记发生变化
 */

<template>
 <p v-if="isCache">
  <span>{{src}}</span>
 </p>
</template>
<style scoped lang="scss">
</style>
<script>
 export default{
  data(){
   return {
    isCache: true,
    src: ''
   }
  },
  created(){
  },
  mounted(){
   // 1、这个页面存在的意义就是在iframe页面切换的时候,路由可以跳转过去用,没有实际大的作用,但是得有这个页面
   // 2、iframe的Tab页面的z-index比这个页面的高
   this.src=this.$route.params.tag
  }
 }
</script>

3. 思考点

虽然这样和iframe结合有点恶心,但是可以实现我们的思路

在这个功能的实现中我们用到了bus事件总线的广播和监听

  1. 其实这点我们是可以仔细思考的,因为大量的使用广播不可控,我们可以完全用vuex去实现,这点用了广播,确实偷懒了

  2. 广播并不是不推荐,而是要使用对场景,这点其实用广播确实不太好,不利于扩展,谁能猜出来会有哪些扩展?

大家不用关心具体的代码,如果你们遇到类似的问题,了解这个思路就可以了

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue.js中如何调用vuex储存接口数据

使用javascript如何实现数字配对游戏

在form表单中有关数据封装并提交的过程

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

23

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

25

2026.03.03

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

77

2026.02.28

Golang 工程化架构设计:可维护与可演进系统构建
Golang 工程化架构设计:可维护与可演进系统构建

Go语言工程化架构设计专注于构建高可维护性、可演进的企业级系统。本专题深入探讨Go项目的目录结构设计、模块划分、依赖管理等核心架构原则,涵盖微服务架构、领域驱动设计(DDD)在Go中的实践应用。通过实战案例解析接口抽象、错误处理、配置管理、日志监控等关键工程化技术,帮助开发者掌握构建稳定、可扩展Go应用的最佳实践方法。

60

2026.02.28

Golang 性能分析与运行时机制:构建高性能程序
Golang 性能分析与运行时机制:构建高性能程序

Go语言以其高效的并发模型和优异的性能表现广泛应用于高并发、高性能场景。其运行时机制包括 Goroutine 调度、内存管理、垃圾回收等方面,深入理解这些机制有助于编写更高效稳定的程序。本专题将系统讲解 Golang 的性能分析工具使用、常见性能瓶颈定位及优化策略,并结合实际案例剖析 Go 程序的运行时行为,帮助开发者掌握构建高性能应用的关键技能。

48

2026.02.28

Golang 并发编程模型与工程实践:从语言特性到系统性能
Golang 并发编程模型与工程实践:从语言特性到系统性能

本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。

26

2026.02.27

Golang 高级特性与最佳实践:提升代码艺术
Golang 高级特性与最佳实践:提升代码艺术

本专题深入剖析 Golang 的高级特性与工程级最佳实践,涵盖并发模型、内存管理、接口设计与错误处理策略。通过真实场景与代码对比,引导从“可运行”走向“高质量”,帮助构建高性能、可扩展、易维护的优雅 Go 代码体系。

20

2026.02.27

Golang 测试与调试专题:确保代码可靠性
Golang 测试与调试专题:确保代码可靠性

本专题聚焦 Golang 的测试与调试体系,系统讲解单元测试、表驱动测试、基准测试与覆盖率分析方法,并深入剖析调试工具与常见问题定位思路。通过实践示例,引导建立可验证、可回归的工程习惯,从而持续提升代码可靠性与可维护性。

4

2026.02.27

漫蛙app官网链接入口
漫蛙app官网链接入口

漫蛙App官网提供多条稳定入口,包括 https://manwa.me、https

388

2026.02.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号