vue中如何通过iframe方式加载本地的vue页面
作者:tianyue_yuan
通过iframe方式加载本地的vue页面
也是在实际的项目中碰到一个奇葩的需求,用vue,居然还要用到iframe,真是脑壳大,试了好多次最后才找到了正确的方法。
总共有三种方法吧
iframe方式加载本地的vue页面的第一种方法
就是直接使用具体的页面地址:http://127.0.0.1:8080/Index
<iframe src="http://127.0.0.1:8080/Index" id="frames" frameborder="0" sandbox="allow-forms allow-scripts allow-same-origin allow-popups" style="height: 100%; width: 100%" ></iframe>
iframe方式加载本地的vue页面的第二种方法
跟第一种方法类似,就是将127改为了localhost
<iframe src="http://localhost:8080/Index" id="frames" frameborder="0" sandbox="allow-forms allow-scripts allow-same-origin allow-popups" style="height: 100%; width: 100%" ></iframe>
不过,注意一下,第一种和第二种方法只能在本地访问时生效,当打包部署到线上后,就会出现页面找不到的问题,不能部署那用处少了太多,这时要用第三种方法
iframe方式加载本地的vue页面的第三种方法
第三种方法跟页面中用相对路径引用图片的方式差不多,就是:…/index,这里的路径的路由中的路径
<iframe src="../index" id="frames" frameborder="0" sandbox="allow-forms allow-scripts allow-same-origin allow-popups" style="height: 100%; width: 100%" ></iframe> // 或者是像这样的路径 <iframe src="../#/index" id="frames" frameborder="0" sandbox="allow-forms allow-scripts allow-same-origin allow-popups" style="height: 100%; width: 100%" ></iframe>
像第三种方法,就可以实现在打包部署在线上时,正确访问到相应的页面。
不过注意一下,当在本地打包成功后,在本地进行测试时,会出现嵌入的页面不是你想要的页面,而是自己项目的树形文件结构。
这是正常的,当部署到线上后,就是正常的页面啦
关于iframe在vue中应用问题
背景是一个vue3.0的个人博客,由于没有支持vue3.0的md展示手段(具体是vue-template-compiler版本太低目前最高2.6.12,而要求vue必须与其版本相同),所以我的解决方法是先将md文件转换成html文件然后由iframe直接导入页面。
iframe的宽高无法根据内容撑开
网上查阅了许多解决方法(其中多数是讲iframe自适应页面而非自适应内容),但基本思路都是***获取到iframe 内容的body宽高,重新赋值给iframe本身,但问题就出在***什么时候获取iframe宽高,vue的生命周期在iframe中完全失效,于是我的解决思路如下
首先利用点击文章列表这一过程,在每次点击后获取iframe body的宽高赋值给iframe本身
<iframe style="width: 100%; height: 100%" scrolling="no" class="iframe" :src="item.path" frameborder="0" ></iframe>
要强调的是一定是点击结束后,即新文章已经显示后才能后去到body的宽高
如果你也用了ui组件提供的click回调函数,并在其中做这件事,一定要使用this.$nextTick{}将你要做的事放到回调的最后执行
methods: { //ui组件给的回调 handleClick(tab, event) { //参数详见elemntui的tabs,这里只用到了tab.index获取点击文章的序号 const oIframe = document.getElementsByClassName("el-tabs__content")[0] .children; const iframe = oIframe[tab.index].children[0].children[1].children[0]; //以上都是找元素节点iframe的过程可忽略(因为用了v-for所以找起来会有点麻烦) this.$nextTick(function () { iframe.style.height = iframe.contentWindow.document.body.offsetHeight + "px"; //contentWindow中有iframe对应网页的全部信息,包括windows、document等 }); }, },
现在,点击文章列表的单个文章,文章的大小应该已经正常了,但页面首次加载时默认文章大小怎么办呢(我曾想过调用一次点击函数来模拟点击一次默认文章,但ui组件让我没有这个机会,后来想想这也确实不是什么好方法)
为了解决这个问题,我又重新回到vue的mounted的函数,但无论如何也获取不到body正确的高度,用this.$nextTick{}只会获取到最终iframe默认的宽高,这时vue的生命周期又失效了,为了找到这个时间点,只能再次求助原生的dom了
mounted() { const oIframe = document.getElementsByClassName("el-tabs__content")[0] .children; //该处dom操作的耦合性较高,待优化 const iframe = oIframe[0].children[0].children[1].children[0]; //以上都是找元素节点iframe的过程可忽略(因为用了v-for所以找起来会有点麻烦) this.$nextTick(function () { iframe.contentWindow.window.onload = () => { if (iframe.contentWindow.document.readyState == "complete") { iframe.style.height = iframe.contentWindow.document.body.offsetHeight + "px"; } }; }); },
这个时间点很玄学,所以确切的说是点击文章列表后iframe完全加载完成后,才能获取到body的宽高,否则即使能够获取到body标签而且body内容都已加载完成,body的offsetHeight依然是0,最后我找到了iframe.contentWindow.document.readyState == "complete"这个代表iframe页面加载完成的标志,在其为”complete“后马上获取body的宽高,赋值,即可
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。