您的当前位置:首页Vue集成Iframe页面的方法示例

Vue集成Iframe页面的方法示例

2020-11-27 来源:小侦探旅游网

1. 项目需求

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

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

系统页面截图

2. 实现思路

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

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

<template>
 <!--路由渲染的功能模块区域-->
 <div 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>
 </div>
</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页面展示区域-->
 <div 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>
 </div>
</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事件广播实现的

/*
 * 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>
 <!--三级菜单导航功能-->
 <div class="main-nav f14 clearfix" @mouseleave="funMenu.menuIsShow=false">
 <div 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>
 <div 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>
 <!--三级导航-->
 <!--存在四级导航-->
 <div class="last-menu f_l dl" v-show="funMenu.lastMenu.length">
 <div v-for="(item,index) in funMenu.lastMenu" class="dt">
 <div 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>
 </div>
 <!--三级导航可点击-->
 <div 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>
 </div>

 </div>
 </div>
 </div>
 </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>
 </div>
 </div>
</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: 124px;
 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>
 <div v-if="isCache">
 <span>{{src}}</span>
 </div>
</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. 广播并不是不推荐,而是要使用对场景,这点其实用广播确实不太好,不利于扩展,谁能猜出来会有哪些扩展?

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

显示全文