Skip to content

gentleman-org/keep-alive-iframe

Repository files navigation

Keep Alive iFrame

🚀 一个支持 keep-alive 功能的 Vue 3 iframe 组件库,解决 iframe 在路由切换时被销毁的问题。

npm version License: MIT Vue 3

🌟 在线预览

访问 https://keepaliveiframe.netlify.app/ 查看在线演示和使用示例。

✨ 核心特性

  • 🔄 Keep-Alive 支持 - iframe 在路由切换时保持状态不被销毁
  • 📱 响应式设计 - 自动适配容器尺寸变化
  • 🎯 智能缓存管理 - 支持最大缓存数量限制和 LRU 策略
  • 🎨 灵活样式 - 支持自定义加载和错误状态
  • 🛠️ TypeScript 支持 - 完整的类型定义
  • 🔧 编程式 API - 提供 FrameManager 用于手动管理
  • 轻量级 - gzip 后仅 3KB

📦 安装

# npm
npm install keep-alive-iframe @vueuse/core

# yarn
yarn add keep-alive-iframe @vueuse/core

# pnpm
pnpm add keep-alive-iframe @vueuse/core

📦 依赖说明:需要安装 @vueuse/core 作为 peer dependency。

🔧 使用方法

基础用法

<template>
  <div>
    <KeepAliveFrame 
      :src="currentSrc" 
      :keep-alive="true"
      @load="handleLoad"
      @error="handleError"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { KeepAliveFrame } from 'keep-alive-iframe'

// 自动导入样式(如果需要)
import 'keep-alive-iframe/style.css'

const currentSrc = ref('https://example.com')

const handleLoad = () => {
  console.log('iframe loaded')
}

const handleError = () => {
  console.log('iframe load error')
}
</script>

高级用法

<template>
  <KeepAliveFrame
    :src="dynamicUrl"
    :keep-alive="enableCache"
    :iframe-attrs="iframeAttributes"
    :max-cache-size="maxCache"
    :parent-container="scrollContainer"
    @load="handleLoad"
    @error="handleError"
    @activated="handleActivated"
    @deactivated="handleDeactivated"
    @resize="handleResize"
    @cache-hit="handleCacheHit"
    @cache-miss="handleCacheMiss"
  >
    <!-- 自定义加载状态 -->
    <template #loading>
      <div class="custom-loading">
        <span>正在加载...</span>
      </div>
    </template>
    
    <!-- 自定义错误状态 -->
    <template #error>
      <div class="custom-error">
        <span>加载失败,请重试</span>
      </div>
    </template>
    
    <!-- 自定义空状态 -->
    <template #empty>
      <div class="custom-empty">
        <span>请输入有效的 URL</span>
      </div>
    </template>
  </KeepAliveFrame>
</template>

<script setup>
import KeepAliveFrame, { FrameManager, generateId } from 'keep-alive-iframe'
import { ref } from 'vue'

const dynamicUrl = ref('https://example.com')
const enableCache = ref(true)
const maxCache = ref(5)
const scrollContainer = ref(null)

const iframeAttributes = {
  allow: 'camera; microphone; clipboard-read; clipboard-write',
  sandbox: 'allow-scripts allow-same-origin',
  referrerpolicy: 'strict-origin-when-cross-origin'
}

// 事件处理
const handleLoad = (event) => console.log('加载完成', event)
const handleError = (error) => console.error('加载错误', error)
const handleActivated = () => console.log('组件激活')
const handleDeactivated = () => console.log('组件停用')
const handleResize = (rect) => console.log('尺寸变化', rect)
const handleCacheHit = () => console.log('缓存命中')
const handleCacheMiss = () => console.log('缓存未命中')
</script>

编程式 API

import { FrameManager, generateId } from 'keep-alive-iframe'

// 创建 iframe
const frameId = generateId()
const frame = FrameManager.create({
  uid: frameId,
  src: 'https://example.com',
  width: 800,
  height: 600,
  top: 100,
  left: 100,
  keepAlive: true,
  attrs: { allow: 'clipboard-read' },
  onLoaded: (e) => console.log('加载完成'),
  onError: (e) => console.log('加载失败')
})

// 管理 iframe
FrameManager.show(frameId)        // 显示
FrameManager.hide(frameId)        // 隐藏
FrameManager.resize(frameId, {    // 调整大小
  width: 1000,
  height: 800,
  top: 50,
  left: 50
})
FrameManager.destroy(frameId)     // 销毁
FrameManager.clear()              // 清空所有缓存
FrameManager.setMaxCacheSize(20)  // 设置最大缓存数

📋 API 文档

Props

属性 类型 默认值 描述
src string - iframe 的 URL 地址
keepAlive boolean true 是否启用 keep-alive 缓存
iframeAttrs Record<string, any> {} iframe 元素的原生属性
maxCacheSize number 10 最大缓存 iframe 数量
parentContainer HTMLElement - 父级滚动容器(用于滚动同步)
zIndex number 1 iframe 的 z-index

Events

事件名 参数 描述
load (event: Event) iframe 加载完成
error (error: Event | string) iframe 加载失败
activated () 组件被激活(keep-alive)
deactivated () 组件被停用(keep-alive)
destroy () iframe 被销毁
resize (rect: DOMRect) 容器尺寸改变
cacheHit () 缓存命中
cacheMiss () 缓存未命中

Slots

插槽名 描述
loading 自定义加载状态
error 自定义错误状态
empty 自定义空状态(无 src 时)

Expose Methods

方法名 返回值 描述
getFrame() HTMLIFrameElement | null 获取当前 iframe 元素

🔧 TypeScript 支持

库提供完整的 TypeScript 类型定义:

import type { 
  HTMLElementRect,
  IFrameCreateOptions,
  IFrameInstance
} from 'keep-alive-iframe'

// 使用类型
const options: IFrameCreateOptions = {
  uid: 'my-frame',
  src: 'https://example.com',
  width: 800,
  height: 600,
  // ...其他配置
}

🎯 工作原理

  1. iframe 脱离组件 - iframe 实际挂载在 document.body 上,而不是组件内部
  2. 位置同步 - 使用绝对定位让 iframe 与组件容器位置同步
  3. 智能缓存 - 通过 FrameManager 管理 iframe 生命周期和缓存策略
  4. 响应式布局 - 监听容器尺寸变化,实时调整 iframe 大小

⚠️ 注意事项

跨域限制

  • iframe 内容需要允许跨域嵌入
  • 可能需要设置适当的 CSP 策略

滚动同步

当启用 keepAlive 时,如果父容器有滚动:

  • 传递 parentContainer 属性以启用滚动同步
  • 或考虑将 keepAlive 设为 false

性能考虑

  • 合理设置 maxCacheSize 避免内存过度占用
  • 及时清理不需要的 iframe 缓存

🔨 开发

# 克隆项目
git clone https://github.com/your-username/keep-alive-iframe.git

# 安装依赖
npm install

# 开发模式
npm run dev

# 构建库
npm run build:lib

# 构建演示站点
npm run build

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可证

MIT © 2024

🔗 相关链接

CSS 样式

此库包含了完整的 UnoCSS 样式,包括:

  • 所有基础工具类(定位、尺寸、颜色等)
  • 动画样式(loading spinner)
  • 组件专用样式

样式会自动打包到 keep-alive-iframe.css 中,您可以:

  1. 自动导入(推荐):导入组件时样式会自动加载
  2. 手动导入import 'keep-alive-iframe/style.css'

About

一个支持 KeepAlive 的 iframe 渲染组件

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors