Vue integrated Iframe page

1. Project Requirements

  • We switch to the vue framework is a later thing. Before, there were some functional pages written in jsp pages, and our management system needs to support both the url of Vue and the jsp pages after these publications.
  • Another is that when you switch the tab back, what you typed before still exists
  • screenshot of system page

2. Implementation ideas

  • In response to this problem, our initial implementation idea was to write a general component of iframe, and then pass in the url of different http pages to switch, but this does not satisfy the second point, we found that as long as the route of vue is switched, Then switch back to the http page, the page with the src attribute in the iframe will be refreshed again, there is no way to keep things, so there is the following implementation idea
  • We added an iframeTemp component at the same level of vue's router-view, which is actually a tab component of elementUI, and then hidden the style of the header of the tab component below our menu bar
<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>
  • The display and hiding and tab switching of the iframe components after that are all implemented by general vuex and bus event broadcasting.

/*
 * 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:;" 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:;" :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:;" :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:;">{{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:;">{{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:;" @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>
  • Also add a useless route because our anchors are going to change

/*
 * 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. Points to think about

  • Although it is a bit disgusting to combine this with iframe, it can realize our idea
  • In the implementation of this function, we use the broadcast and monitoring of the bus event bus
    • In fact, we can think carefully about this point, because a lot of use of broadcasting is uncontrollable, we can use Vuex to achieve this, and we are really lazy by using broadcasting.
    • Broadcasting is not not recommended, but should be used in the right scenario. In fact, broadcasting is not very good in practice, and it is not conducive to expansion. Who can guess what expansions will be available?
  • You don't need to care about the specific code. If you encounter similar problems, you can understand this idea.

4. References and citations

5. Special thanks

  • company's partners

6. Disclaimer

  • Some of the content in this document is taken from many blogs on the Internet, and is only used as a supplement and arrangement of my own knowledge, and is shared with other coders in need, and will not be used for commercial use.
  • Because the addresses of many blogs are not saved in time after reading, many of them will not indicate the source here. Thank you very much for your sharing, and I hope everyone understands.
  • If the original author feels uncomfortable, you can contact me in time at [email protected], and I will delete the content of the dispute in time

7. Statement of Accountability

  • If there is a large paragraph that quotes more than 50% of the full text, please indicate the source of the original text at the end of the document: Longma Xingkong - Shi Guoqing - Jupiter - https://my.oschina.net/u/1416844/blog , otherwise it will be regarded as For plagiarism, legal investigation, please respect your personal intellectual property rights.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325517338&siteId=291194637