Vue集成Iframe页面

简介:

1. 项目需求

  • 我们切换为vue框架是后面的事情,之前还有一些功能页面是用jsp页面写的,而我们的管理系统需要既支持Vue的url,又要支持这些发布之后的jsp页面
  • 还有一个就是切换tab回来的时候之前输入的东西还要存在
  • 系统页面截图

d965369d30e357a0f3ba1e28a67eea021d8cefb3

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事件广播实现的

7b84960ccbdf6c7b512f7c7257c9d7c9ae37ae53

/*
 * 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>
  • 还要添加一个没用的路由,因为我们的锚记还要发生变化


/*
 * 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事件总线的广播和监听
    • 其实这点我们是可以仔细思考的,因为大量的使用广播不可控,我们可以完全用vuex去实现,这点用了广播,确实偷懒了
    • 广播并不是不推荐,而是要使用对场景,这点其实用广播确实不太好,不利于扩展,谁能猜出来会有哪些扩展?
  • 大家不用关心具体的代码,如果你们遇到类似的问题,了解这个思路就可以了

4. 参考和引用

5. 特别感谢

  • 公司的小伙伴

6. 免责说明

  • 本文档中的部分内容摘自网上的众多博客,仅作为自己知识的补充和整理,并分享给其他需要的coder,不会用于商用。
  • 因为很多博客的地址看完没有及时做保存,所以很多不会在这里标明出处,非常感谢各位大牛的分享,也希望大家理解。
  • 如果原文作者感觉不适,可以及时联系我shiguoqing999@163.com,我将及时删除争议部分内容

原文发布时间:2017年12月10日

作者:石国庆-朱庇特

本文来源:开源博客  如需转载请联系原作者

目录
相关文章
|
3月前
|
存储 JavaScript
vue页面跳转取消上一个页面请求
本文介绍了在Vue中如何取消上一个页面的请求,以避免页面跳转时请求未完成导致的数据错误。核心方法是使用axios的请求拦截器设置请求的取消令牌(cancelToken),并在vuex中存储这些取消令牌的引用。当进行路由跳转时,通过路由守卫清除这些请求,达到取消上一个页面请求的目的。
192 2
|
29天前
|
缓存 资源调度 JavaScript
Vue集成Excalidraw实现在线画板功能
Excalidraw是一款开源在线绘图工具,适用于白板、思维导图、原型设计等场景。支持手绘风格、多种图形元素、导出功能及多人协作,深受开发者喜爱。本文档介绍了如何在Vue项目中集成Excalidraw,包括安装依赖、配置文件修改、页面添加等步骤,帮助开发者快速上手。
140 0
Vue集成Excalidraw实现在线画板功能
|
2月前
|
JavaScript API
vue尚品汇商城项目-day04【24.点击搜索按钮跳转后的页面商品列表、平台售卖属性动态展示(开发Search组件)】
vue尚品汇商城项目-day04【24.点击搜索按钮跳转后的页面商品列表、平台售卖属性动态展示(开发Search组件)】
63 1
vue尚品汇商城项目-day04【24.点击搜索按钮跳转后的页面商品列表、平台售卖属性动态展示(开发Search组件)】
|
1月前
|
JavaScript UED
"Vue实战技巧大揭秘:一招解决路由跳转页面不回顶部难题,让你的单页面应用用户体验飙升!"
【10月更文挑战第23天】在Vue单页面应用中,点击路由跳转时,默认情况下页面不会自动滚动到顶部,这可能影响用户体验。本文通过一个新闻网站的案例,介绍了如何使用Vue-router的全局前置守卫和`scrollBehavior`方法,实现路由跳转时页面自动滚动到顶部的功能,提升用户浏览体验。
92 0
|
2月前
|
JavaScript 前端开发 API
vue尚品汇商城项目-day04【28.详情页面Detail】
vue尚品汇商城项目-day04【28.详情页面Detail】
24 1
|
2月前
|
JavaScript 前端开发 安全
如何在 Vue 页面中禁止选择、右键、复制及 F12 开发者工具
【10月更文挑战第3天】 在前端开发中,保护页面内容不被随意复制或查看是一个常见需求。本文介绍了如何在 Vue 应用中实现禁止文本选择、右键菜单、复制操作以及 F12 开发者工具的方法。通过结合 CSS 和 JavaScript 事件监听,我们可以增加用户查看和复制内容的难度,尽管无法完全阻止高级用户。适当的防护措施可以为内容提供一层额外的保护,帮助开发者提升页面安全性。
503 0
|
3月前
|
前端开发 JavaScript 开发者
Express.js与前端框架的集成:React、Vue和Angular的示例与技巧
本文介绍了如何将简洁灵活的Node.js后端框架Express.js与三大流行前端框架——React、Vue及Angular进行集成,以提升开发效率与代码可维护性。文中提供了详细的示例代码和实用技巧,展示了如何利用Express.js处理路由和静态文件服务,同时在React、Vue和Angular中构建用户界面,帮助开发者快速掌握前后端分离的开发方法,实现高效、灵活的Web应用构建。
73 3
|
2月前
|
JavaScript API
vue尚品汇商城项目-day06【37.获取交易数据+38.用户地址信息展示+39.交易信息展示及交易页面完成+40.提交订单+41.支付组件内获取订单号与展示支付信息】
vue尚品汇商城项目-day06【37.获取交易数据+38.用户地址信息展示+39.交易信息展示及交易页面完成+40.提交订单+41.支付组件内获取订单号与展示支付信息】
47 0
|
2月前
|
JavaScript 前端开发
vue尚品汇商城项目-day06【vue插件-42.支付页面中使用ElementUI以及按需引入】
vue尚品汇商城项目-day06【vue插件-42.支付页面中使用ElementUI以及按需引入】
28 0
|
4月前
|
存储 JavaScript 前端开发
Vue中通过集成Quill富文本编辑器实现公告的发布。Vue项目中vue-quill-editor的安装与使用【实战开发应用】
文章展示了在Vue项目中通过集成Quill富文本编辑器实现公告功能的完整开发过程,包括前端的公告发布、修改、删除操作以及后端的数据存储和处理逻辑。
Vue中通过集成Quill富文本编辑器实现公告的发布。Vue项目中vue-quill-editor的安装与使用【实战开发应用】

热门文章

最新文章