mirror of https://github.com/msgbyte/tailchat
feat: 增加KeepAliveOverlay组件用于缓存iframe
parent
fcc2684a34
commit
373e424e6a
@ -0,0 +1,33 @@
|
|||||||
|
import React, { FC } from 'react';
|
||||||
|
import { useKeepAliveStore } from './store';
|
||||||
|
|
||||||
|
export const KeepAliveOverlayHost: FC<React.PropsWithChildren> = (props) => {
|
||||||
|
const cachedComponents = useKeepAliveStore((state) => state.cachedComponents);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{props.children}
|
||||||
|
|
||||||
|
<div className="keep-alive-overlay-host">
|
||||||
|
{Object.entries(cachedComponents).map(([cacheId, cacheItem]) => {
|
||||||
|
const { visible, element, rect } = cacheItem;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id={`cache-${cacheId}`}
|
||||||
|
style={{
|
||||||
|
display: visible ? 'block' : 'none',
|
||||||
|
...rect,
|
||||||
|
position: 'fixed',
|
||||||
|
}}
|
||||||
|
key={cacheId}
|
||||||
|
>
|
||||||
|
{element}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
KeepAliveOverlayHost.displayName = 'KeepAliveOverlayHost';
|
@ -0,0 +1,3 @@
|
|||||||
|
组件状态缓存, 使用覆盖层的方式来保持存活(类似小程序叠加原生程序的感觉)
|
||||||
|
|
||||||
|
支持`iframe`的渲染缓存.
|
@ -0,0 +1,2 @@
|
|||||||
|
export { KeepAliveOverlayHost } from './KeepAliveOverlayHost';
|
||||||
|
export { withKeepAliveOverlay } from './withKeepAliveOverlay';
|
@ -0,0 +1,79 @@
|
|||||||
|
import type React from 'react';
|
||||||
|
import create from 'zustand';
|
||||||
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
|
interface ElementDisplayRect {
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KeepAliveState {
|
||||||
|
cachedComponents: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
visible: boolean;
|
||||||
|
element: React.ReactElement;
|
||||||
|
rect: ElementDisplayRect;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
mount: (cacheId: string, element: React.ReactElement) => void;
|
||||||
|
show: (cacheId: string) => void;
|
||||||
|
hide: (cacheId: string) => void;
|
||||||
|
updateRect: (cacheId: string, rect: ElementDisplayRect) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useKeepAliveStore = create<KeepAliveState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
cachedComponents: {},
|
||||||
|
mount: (cacheId, element) => {
|
||||||
|
set((state) => {
|
||||||
|
const cachedComponents = state.cachedComponents;
|
||||||
|
if (cachedComponents[cacheId]) {
|
||||||
|
// 已经挂载过
|
||||||
|
state.cachedComponents[cacheId].visible = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedComponents[cacheId] = {
|
||||||
|
visible: true,
|
||||||
|
element,
|
||||||
|
rect: {
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
show: (cacheId) => {
|
||||||
|
set((state) => {
|
||||||
|
if (!state.cachedComponents[cacheId]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.cachedComponents[cacheId].visible = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
hide: (cacheId) => {
|
||||||
|
set((state) => {
|
||||||
|
if (!state.cachedComponents[cacheId]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.cachedComponents[cacheId].visible = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateRect: (cacheId: string, rect: ElementDisplayRect) => {
|
||||||
|
set((state) => {
|
||||||
|
if (!state.cachedComponents[cacheId]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.cachedComponents[cacheId].rect = rect;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
@ -1,17 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { withKeepAliveOverlay } from './KeepAliveOverlay';
|
||||||
|
|
||||||
interface WebviewProps {
|
interface WebviewProps {
|
||||||
url: string;
|
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网页渲染容器
|
* 网页渲染容器
|
||||||
*/
|
*/
|
||||||
export const Webview: React.FC<WebviewProps> = React.memo((props) => {
|
export const Webview: React.FC<WebviewProps> =
|
||||||
return (
|
withKeepAliveOverlay<WebviewProps>(
|
||||||
<iframe className={props.className} style={props.style} src={props.url} />
|
(props) => {
|
||||||
|
return <iframe className="w-full h-full bg-white" src={props.url} />;
|
||||||
|
},
|
||||||
|
{ cacheId: (props) => props.url }
|
||||||
);
|
);
|
||||||
});
|
|
||||||
Webview.displayName = 'Webview';
|
Webview.displayName = 'Webview';
|
||||||
|
Loading…
Reference in New Issue