在Vue中實(shí)現(xiàn)不刷新的iframe頁面的方案
引言
在Vue項(xiàng)目中,我們可能會(huì)遇到這樣的需求:需要在應(yīng)用中嵌入iframe頁面,并且要求在路由切換的過程中,iframe的內(nèi)容不會(huì)被刷新。實(shí)現(xiàn)這一需求時(shí),Vue自帶的keep-alive并不適用,因?yàn)樗墓ぷ髟聿⒉贿m用于iframe元素。本文將介紹如何解決這個(gè)問題,并給出具體的實(shí)現(xiàn)方案。
Vue的keep-alive原理
首先,我們需要理解為什么Vue的keep-alive對(duì)于iframe不起作用。keep-alive的工作原理是把組件的VNode(虛擬DOM節(jié)點(diǎn))緩存到內(nèi)存中,在需要渲染時(shí)直接從緩存中提取,而不是重新渲染組件。可是,iframe里的內(nèi)容并不屬于Vue的VNode的一部分,因此keep-alive無法保留iframe的狀態(tài)。當(dāng)頁面切換時(shí),iframe會(huì)被重新加載,導(dǎo)致其內(nèi)容被刷新。
為了實(shí)現(xiàn)iframe的內(nèi)容不刷新的效果,我們需要采取一種不同的方式,避免依賴keep-alive。
實(shí)現(xiàn)思路
考慮到iframe的狀態(tài)難以通過keep-alive保存,我想到了一種基于路由切換方式的解決方案??梢岳?code>v-show來切換iframe的顯示與隱藏,從而確保iframe始終在頁面中存在,而不被銷毀。具體思路如下:
- 非iframe頁面:使用Vue的路由切換機(jī)制來切換頁面內(nèi)容。
- iframe頁面:通過v-show來控制iframe組件的顯示與隱藏,而不讓其從DOM中刪除。這樣,當(dāng)路由切換時(shí),iframe頁面的內(nèi)容不會(huì)被重新加載。
解決方案
我們可以將iframe頁面的渲染與Vue的路由機(jī)制結(jié)合起來,并封裝成一個(gè)通用的組件。下面是具體的實(shí)現(xiàn)步驟。
1. 配置路由
首先,我們?cè)?code>main.js中配置路由,使用一個(gè)iframeComponent屬性來標(biāo)識(shí)哪些頁面是包含iframe的頁面。此屬性將存儲(chǔ)iframe組件的引用。
import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
// 引入需要展示的iframe組件
import F1 from './components/F1.vue';
import F2 from './components/F2.vue';
Vue.use(VueRouter);
// 配置路由
const routes = [
{
path: '/f1',
name: 'f1',
iframeComponent: F1, // 該頁面包含iframe
},
{
path: '/f2',
name: 'f2',
iframeComponent: F2, // 該頁面包含iframe
},
{
path: '/index',
component: { template: '<div>Index Page</div>' }
}
];
?
const router = new VueRouter({
routes
});
?
new Vue({
render: h => h(App),
router
}).$mount('#app');
2. 封裝iframe-router-view組件
我們需要一個(gè)新的組件來處理iframe頁面的顯示與隱藏。這個(gè)組件會(huì)監(jiān)聽路由變化,并根據(jù)路由路徑動(dòng)態(tài)決定哪些iframe頁面應(yīng)該渲染。
創(chuàng)建iframe-router-view.vue:
<template>
<div>
<!-- Vue的router-view -->
<keep-alive>
<router-view></router-view>
</keep-alive>
?
<!-- 動(dòng)態(tài)渲染iframe頁面 -->
<component
v-for="item in hasOpenComponentsArr"
:key="item.name"
:is="item.name"
v-show="$route.path === item.path"
></component>
</div>
</template>
?
<script>
import Vue from 'vue/dist/vue.js';
?
export default {
data() {
return {
componentsArr: [] // 存儲(chǔ)所有含有iframe的頁面
};
},
created() {
// 獲取路由配置中的iframe頁面,并注冊(cè)組件
const componentsArr = this.getComponentsArr();
componentsArr.forEach((item) => {
Vue.component(item.name, item.component);
});
this.componentsArr = componentsArr;
this.isOpenIframePage(); // 檢查當(dāng)前路由是否是iframe頁面
},
watch: {
$route() {
// 路由變化時(shí)更新顯示的iframe頁面
this.isOpenIframePage();
}
},
computed: {
// 實(shí)現(xiàn)懶加載,只渲染已打開過的iframe頁面
hasOpenComponentsArr() {
return this.componentsArr.filter(item => item.hasOpen);
}
},
methods: {
// 判斷當(dāng)前路由是否是iframe頁面,并設(shè)置`hasOpen`標(biāo)志
isOpenIframePage() {
const target = this.componentsArr.find(item => item.path === this.$route.path);
if (target && !target.hasOpen) {
target.hasOpen = true;
}
},
// 獲取所有路由配置中含有iframeComponent的頁面
getComponentsArr() {
const router = this.$router;
const routes = router.options.routes;
const iframeArr = routes.filter(item => item.iframeComponent);
return iframeArr.map((item) => {
const name = item.name || item.path.replace('/', '');
return {
name: name,
path: item.path,
hasOpen: false, // 是否已打開過
component: item.iframeComponent // iframe組件引用
};
});
}
}
};
</script>
3. 更新根組件
在根組件中,替換原本的router-view,使用我們封裝的iframe-router-view組件來替代。
<template>
<div id="app">
<div class="nav">
<router-link class="router" to="/f1">Go to F1</router-link>
<router-link class="router" to="/f2">Go to F2</router-link>
<router-link class="router" to="/index">Go to Index</router-link>
</div>
<!-- 使用新的iframe-router-view組件 -->
<iframe-router-view></iframe-router-view>
</div>
</template>
<script>
import F1 from './components/F1';
import F2 from './components/F2';
import IframeRouterView from './components/iframe-router-view.vue';
export default {
name: 'App',
components: {
F1,
F2,
IframeRouterView
}
};
</script>
4. 進(jìn)一步優(yōu)化
- 懶加載:通過hasOpen標(biāo)志,我們確保只有在用戶訪問過對(duì)應(yīng)的iframe頁面時(shí),iframe組件才會(huì)被渲染。這是一個(gè)簡易的懶加載機(jī)制,可以提升性能,避免不必要的資源浪費(fèi)。
- 動(dòng)態(tài)注冊(cè):我們通過動(dòng)態(tài)生成的組件數(shù)組來注冊(cè)iframe頁面,無需每次新增iframe頁面時(shí)都手動(dòng)修改根組件或main.js。
- 在關(guān)閉tab或其他業(yè)務(wù)場景下,移除對(duì)應(yīng)的iframe,防止內(nèi)存溢出。
動(dòng)態(tài)創(chuàng)建iframe的解決方案
class IframeManager {
constructor() {
if (IframeManager.instance) {
return IframeManager.instance;
}
this.iframes = new Map();
IframeManager.instance = this;
return this;
}
/**
* 創(chuàng)建 iframe
* @param {string} id - 唯一標(biāo)識(shí)符 必填
* @param {string} src - iframe 的 URL 必填
* @param {Object} styles - 自定義樣式 可選
*/
createIframe(id, src, styles = {}) {
if (this.iframes.has(id)) {
const iframe = this.iframes.get(id);
iframe.style.display = 'block';
return;
}
const iframe = document.createElement('iframe');
iframe.id = id;
iframe.src = src;
iframe.frameBorder = '0';
const defaultStyles = {
position: 'absolute',
top: '113px',
right: '0',
width: 'calc(100% - 210px)',
height: 'calc(100% - 113px)',
overflowY: 'auto',
borderRadius: '10px 0 0 10px',
zIndex: '1000',
display: 'block',
};
Object.assign(iframe.style, { ...defaultStyles, ...styles });
document.body.appendChild(iframe);
this.iframes.set(id, iframe);
}
/**
* 隱藏 iframe
* @param {string} id - iframe 的唯一標(biāo)識(shí)符 必填
*/
hideIframe(id) {
const iframe = this.iframes.get(id);
if (iframe) {
iframe.style.display = 'none';
}
}
/**
* 銷毀 iframe
* @param {string} id - iframe 的唯一標(biāo)識(shí)符
*/
destroyIframe(id) {
const iframe = this.iframes.get(id);
if (iframe) {
iframe.remove();
this.iframes.delete(id);
}
}
/**
* 銷毀所有 iframe
*/
destroyAllIframes() {
this.iframes.forEach((iframe, id) => {
iframe.remove();
this.iframes.delete(id);
});
}
}
const iframeManager = new IframeManager();
export default iframeManager;
上述代碼中,我們采用了單例模式來確保實(shí)例唯一,可在多個(gè)頁面進(jìn)行統(tǒng)一的管理,頁面中的使用不再過多贅述,調(diào)用上述方法即可。
結(jié)語
通過以上方法,我們實(shí)現(xiàn)了一個(gè)可以在路由切換時(shí)保持iframe內(nèi)容不刷新的解決方案。我們利用Vue的v-show來控制iframe的顯示和隱藏,而非通過重新渲染整個(gè)iframe元素來避免刷新。
這種方式不僅簡化了代碼,還能確保應(yīng)用的性能與體驗(yàn)不受影響。如果你有更好的優(yōu)化方法或遇到了其他問題,歡迎與我交流討論!
以上就是在Vue中實(shí)現(xiàn)不刷新的iframe頁面的方案的詳細(xì)內(nèi)容,更多關(guān)于Vue不刷新iframe頁面的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解vue中使用transition和animation的實(shí)例代碼
這篇文章主要介紹了詳解vue中使用transition和animation的實(shí)例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Vue.js進(jìn)階知識(shí)點(diǎn)總結(jié)
給大家分享了關(guān)于Vue.js想成為高手的5個(gè)總要知識(shí)點(diǎn),需要的朋友可以學(xué)習(xí)下。2018-04-04
大前端代碼重構(gòu)之事件攔截iOS?Flutter?Vue示例分析
這篇文章主要為大家介紹了大前端代碼重構(gòu)之事件攔截iOS?Flutter?Vue示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
vue3+vite+ts使用require.context問題
這篇文章主要介紹了vue3+vite+ts使用require.context問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
Vue3 響應(yīng)式 API 及 reactive 和 ref&
響應(yīng)式是一種允許以聲明式的方式去適應(yīng)變化的編程范例,這篇文章主要介紹了關(guān)于Vue3響應(yīng)式API及reactive和ref的用法,需要的朋友可以參考下2023-06-06
Vue中渲染系統(tǒng)模塊的實(shí)現(xiàn)詳解
想要實(shí)現(xiàn)一個(gè)簡潔版的Mini-Vue框架,應(yīng)該包含三個(gè)模塊:分別是:渲染系統(tǒng)模塊、可響應(yīng)式系統(tǒng)模塊、應(yīng)用程序入庫模塊,本文主要介紹的是渲染系統(tǒng)模塊的實(shí)現(xiàn),需要的可以參考一下2023-07-07
解析Vue2 dist 目錄下各個(gè)文件的區(qū)別
本篇文章主要介紹了解析Vue2 dist 目錄下各個(gè)文件的區(qū)別,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11

