vue+ element 导航菜单加载iframe实现外链内嵌效果
需求如下:
在项目里点击不同的菜单 针对项目内的路由直接在页面上切换路由进行跳转,嵌套的外部链接直接用iframe的url来加载。
部分代码如下:
左侧导航代码示例
<el-menu :default-active="onRoute" class="el-menu-list" @open="handleOpen" :unique-opened="true" @close="handleClose" :collapse="isCollapse"> <el-submenu :index="item.code" v-for="(item,index) in menuList" :key="index"> <template slot="title"> <i :class="item.icon"></i> <span slot="title">{{item.name}}</span> </template> <el-menu-item-group> <el-menu-item @click="handleClick(options)" :index="options.url" v-for="(options,opindex) in item.portalMenuList" :key="opindex">{{options.name}}</el-menu-item> </el-menu-item-group> </el-submenu> </el-menu> <!-- 折叠按钮 --> <div class="click_btn" v-bind:class="{'unfold_class':isCollapse,'pack_up_class':!isCollapse}" @click="change"> <img v-bind:class="{'unfold_btn':isCollapse,'pack_up_btn':!isCollapse}" :src="picture + (isCollapse?'/appointment/zhankai.png':'/appointment/shouqi.png')" alt=""> </div> <!-- 折叠按钮end -->
右侧展示路由内容页或者被嵌套的网页 部分代码示例:
<div class="content-box" :class="{'content-collapse':isCollapse}"> <div class="content"> <transition name="move" mode="out-in"> <router-view v-show="!showIframe" ></router-view> </transition> <transition name="move" mode="out-in"> <iframe v-show="showIframe" height="100%" width="100%" :src="iframeUrl" frameborder="0"></iframe> </transition> </div> </div>
计算属性 监听当前导航菜单权限展示默认页面(首页):
computed:{ onRoute(){ let path = ''; let that = this; that.menuList.forEach(item=>{ if(item.portalMenuList.length>0){ item.portalMenuList.forEach(ops=>{ if(ops.hasOwnProperty('homePage') && ops.homePage == 'true'){ that.showIframe = true; that.iframeUrl = ops.url; path = ops.url } }) } }) console.log(path) return path } },
监听事件是否有message参数,如果有直接当页面参数获取,方法如下:
receiveMessage(event) { let vm = this; // For Chrome, the origin property is in the event.originalEvent // object. // 这里不准确,chrome没有这个属性 // var origin = event.origin || event.originalEvent.origin; var origin = event.origin if (origin !== "https://www.xxx.com") { return; } else { if (event.data.officeId) { console.log(event.data.officeId) vm.officeId = event.data.officeId; } if (event.data.providerId) { vm.personInfoHisId = event.data.providerId } if (event.data.tenantId) { vm.tenantId = event.data.tenantId; } this.getListData(); } },
//在mounted 监听
mounted(){
window.addEventListener("message", this.receiveMessage, false);
},
获取导航菜单列表方法,并自定义菜单:
// 获取菜单列表 getListData(){ let params = { officeId: this.officeId,//门店hisid tenantId: this.tenantId,//租户ID personInfoHisId: this.personInfoHisId,//医生hisId } this.$post('/getPortalmenu',params,{contentType:'json'}).then(res=>{ if(res.code == '200'){ this.menuList = res.data; this.menuList.forEach(item=>{ this.iconList.forEach(ops=>{ if(item.code == ops.code){ this.$set(item,'icon',ops.icon) } }) }) } }) }, // 菜单展开 handleOpen(key, keyPath){ console.log(key, keyPath); }, // 折叠 handleClose(key, keyPath){ console.log('guanb',key, keyPath); } //icon 列表如下所示 iconList:[ { code:'home', icon:'el-icon-pie-chart' }, { code:'BIll', icon:'el-icon-s-operation' }, { code:'MATERIAL', icon:'el-icon-cloudy' }, { code:'Commission', icon:'el-icon-data-analysis' }, { code:'CRM', icon:'el-icon-s-comment' }, { code:'a1', icon:'el-icon-s-order' }, { code:'a2', icon:'el-icon-folder' }, { code:'a3', icon:'el-icon-s-marketing' } ],
后台接口返回的json格式如下:
[{ "id":3, "isAvailability":1, "version":1, "name":"核心指标报表", "code":"home", "parentId":1, "url":null, "type":1, "menuIndex":1, "menuType":1, "remark":null, "portalMenuList":[ { "id":18, "name":"首页", "code":"homepage", "parentId":3, "url":"https://www.baidu.com", "type":2, "menuIndex":1, "menuType":2, "remark":"首页", "portalMenuList":[{ "id":5, "isAvailability":1, "version":1, "name":"数据报表", "code":"BI1", "parentId":2, "url":"https://www.baidu.com", "type":2, "menuIndex":1, "menuType":2, "remark":null, "portalMenuList":null, "officeId":null, "tenantId":null, "personInfoHisId":null, "homePage":null }, ], "officeId":null, "tenantId":null, "personInfoHisId":null, "homePage":"true" } ], "officeId":null, "tenantId":null, "personInfoHisId":null, "homePage":null }, }]
样式部分代码示例:
<style scoped> .etoothMenuMain >>> .el-menu-list:not(.el-menu--collapse) { width: 200px; height: 100%; } .etoothMenuMain >>> .el-menu-list{ margin:10px; border:none; box-shadow: 1px 3px 5px 3px rgb(221, 218, 218); } .etoothMenuMain >>> .el-menu-item.is-active{ background: #409EFF; color: #fff; } /* 折叠按钮样式 */ .etoothMenuMain .click_btn{ position: absolute; width: 16px; height: 52px; top: 10px; left:-100px; z-index: 100; -webkit-transition: left .3s ease-in-out; transition: left .3s ease-in-out; } .etoothMenuMain .click_btn img{ width: 16px; height: 52px; } .etoothMenuMain .unfold_class{ left: 74px; } .etoothMenuMain .pack_up_class{ left: 210px; } .etoothMenuMain >>> .content-box{ position: absolute; top:0; background: #fff; } .etoothMenuMain >>> .content-collapse{ left: 91px; } </style>
以上即可
新增知识点:
当被嵌套页面有媒体权限时,iframe 也要增加属性 allow
<transition name="move" mode="out-in"> <iframe height="100%" width="100%" v-show="showIframe" :src="iframeUrl" frameborder="0" ref="lookLive"></iframe> </transition>
mounted(){ let vm = this; window.addEventListener("message", this.receiveMessage, false); // vm.officeId = vm.$route.query.officeId; // vm.personInfoHisId = vm.$route.query.personInfoHisId; // vm.tenantId = vm.$route.query.tenantId; // this.getListData(); this.$nextTick(()=>{ var iframeElment = this.$refs.lookLive; if (iframeElment) { console.log(iframeElment,'111') iframeElment.allow = 'camera;microphone;' } }) },
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本