一、 vueiframe跨域
在项目中,有时会需要引入外部的无关联组件或页面,此时可以通过iframe来实现。但是vue中的iframe涉及到跨域问题,如何解决呢?
一般来说,如果父页面和子页面不同源,则会出现跨域问题。所以我们可以在后台设置响应头中的Access-Control-Allow-Origin,将源地址设置为'*',即可允许所有外域请求。
后台代码示例(node.js):
``` app.use(function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Content-Type"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); next(); }); ```二、vueiframe只需载一次
每次切换路由或者重新加载页面时,vue会重新创建组件和iframe,这会造成很大的性能浪费。如何避免重复载入呢?
我们可以通过keep-alive来缓存组件,避免重新渲染。同时,设置一个变量checked来标记iframe是否已经载入,如果已经载入则不需要重新载入。
<template> <keep-alive> <div> <iframe id="my-iframe" v-if="!checked" :src="url" @load="frameOnload"> </iframe> </div> </keep-alive> </template> <script> export default { data: () => ({ checked: false, }), methods: { frameOnload() { this.checked = true } } } </script>
三、vueiframe路径
iframe路径可以直接使用src属性指定。但是如果需要动态修改路径,可以使用Vue的响应式特性。
下面是vue中设置iframe路径的代码示例:
<template> <div> <iframe :src="iframeSrc"></iframe> </div> </template> <script> export default { data () { return { src: "https://example.com" } }, computed: { iframeSrc () { return this.src + "?time=" + (new Date()).getTime() } } } </script>
四、vueiframe 传参
在vue中,可以使用props来给iframe传递参数。我们可以通过监听变化,再把变化传至iframe中。
下面是一个vue传递至iframe中的示例:
<template> <iframe ref="iframe" @load="loaded" :src="src" :width="width + 'px'" :height="height + 'px'" ></iframe> </template> <script> export default { props: ['src', 'width', 'height'], methods: { loaded() { this.$refs.iframe.contentWindow.postMessage( { type: 'init', data: { parentId: this.$route.query.parentId || '' } }, '*' ) } } } </script>
五、vueiframe嵌套跨域
实现父子组件之间的通信,可以使用postMessage,它可以跨域传输数据。
父页面: <template> <div> <iframe :src="frameUrl"></iframe> </div> </template> <script> export default { data() { return { frameUrl: "" } }, mounted(){ this.$nextTick(() =>{ const iframeWindow = this.$el.querySelector('iframe').contentWindow; iframeWindow.onload = () => { iframeWindow.postMessage({ type: 'test-message' },config.targeturl) } }) } } </script> 子页面: <template> <div>承载页</div> </template> <script> export default { created(){ window.addEventListener('message', this.messageHandler) }, destroyed(){ window.removeEventListener('message', this.messageHandler) }, methods: { messageHandler(event) { if(event.source !== parent) return; let message = event.data; if(message.type === 'test-message') { console.log('test-message') } } } } </script>
六、vueiframe页面切换
子页面中的iframe通过postMessage把数据传给父页面,并进行组件切换。
父页面: <template> <div> <h2>父页面</h2> <router-view :key="$route.fullPath"></router-view> </div> </template> <script> export default { data: () => ({ data: "" }), methods: { changeRoute(data) { this.$router.push(data.path) this.data = data } } } </script> 子页面: <template> <div> <h2>iframe中子页面</h2> <button @click="changeRoute">切换</button> </div> </template> <script> export default { created() { window.addEventListener('message', this.messageHandler) }, destroyed() { window.removeEventListener('message', this.messageHandler) }, methods: { changeRoute() { this.$router.push('/') window.parent.postMessage({ path: '/' }, '*') }, messageHandler(event) { const message = event.data if (message.path) { this.$router.push(message.path) } } } } </script>
七、vueiframe只需在一次
如何使iframe只需加载一次,涉及到Vue的$once方法。
<template> <iframe v-once :src="url"></iframe> </template> <script> export default { data () { return { url: 'https://example.com' } } } </script>
八、vueiframe加载不了外部URL
有时候vue中的iframe会因为加载的外部网址存在x-frame-options保护机制而失败。但是我们可以使用其他的方案,比如使用fetch或者axios获取网址内容,再渲染到自己的页面中。
<template> <div> <h2>外部网址:{{url}}</h2> <div v-html="html"></div> </div> </template> <script> export default { data () { return { url: "https://example.com", html: "" } }, created(){ fetch(this.url, {mode: "no-cors"}) .then(resp => resp.text()) .then(html => this.html = html) } } </script>
九、vueiframe跨域传值修改里面的样式
有时候我们需要修改iframe中的样式,可以使用postMessage进行通信。
父页面: <template> <div> <h2>父页面</h2> <iframe :src="frameUrl"></iframe> </div> </template> <script> export default { data() { return { frameUrl: "" } }, mounted(){ this.$nextTick(() =>{ const iframeWindow = this.$el.querySelector('iframe').contentWindow; iframeWindow.onload = () => { iframeWindow.postMessage({ type: 'change-style', data: { backgroundColor: '#f5f5f5' } },config.targeturl) } }) } } </script> 子页面: <template> <div>承载页</div> </template> <script> export default { created(){ window.addEventListener('message', this.messageHandler) }, destroyed(){ window.removeEventListener('message', this.messageHandler) }, methods: { messageHandler(event) { if(event.source !== parent) return; let message = event.data; if(message.type === 'change-style') { let ele = document.body for(let key in message.data){ ele.style[key] = message.data[key] } } } } } </script>