|
| 1 | +/** |
| 2 | + * 用于父子页面路由监听 |
| 3 | + */ |
| 4 | +import React, { useEffect } from 'react'; |
| 5 | +import { useHistory, useLocation } from 'react-router-dom'; |
| 6 | +import { LogMgr } from '../../../util'; |
| 7 | +/** 跨页面通信消息状态码 */ |
| 8 | +export enum PostMessageCode { |
| 9 | + SUCCESS = 200, |
| 10 | +} |
| 11 | + |
| 12 | +/** 跨页面通信消息数据结构 */ |
| 13 | +export interface PostMessageData { |
| 14 | + code: number; |
| 15 | + type: string; |
| 16 | + data: string; |
| 17 | +} |
| 18 | + |
| 19 | +/** route接收消息数据结构 */ |
| 20 | +export interface RouteReceiveMessage { |
| 21 | + /** 接受消息来源 */ |
| 22 | + eventOrigin?: string; |
| 23 | + /** 接收消息类型 */ |
| 24 | + messageType?: string; |
| 25 | + /** history 路由跳转类型 */ |
| 26 | + jumpType?: 'push' | 'replace'; |
| 27 | + /** 路由前缀,接收路由时会增加路由前缀再执行跳转发送 */ |
| 28 | + prefix?: string; |
| 29 | + /** 自定义处理 */ |
| 30 | + customHandler?: (event: MessageEvent<PostMessageData>) => void; |
| 31 | +} |
| 32 | + |
| 33 | +/** route发送消息数据结构 */ |
| 34 | +export interface RoutePostMessage { |
| 35 | + /** 自定义操作 */ |
| 36 | + customHandler?: (urlPath: string) => void |
| 37 | + /** 发送消息目标源,不存在customHandler时必传 */ |
| 38 | + targetOrigin?: string; |
| 39 | + /** 发送消息类型,不存在customHandler时必传 */ |
| 40 | + messageType?: string; |
| 41 | + /** 是否处于 iframe 内 */ |
| 42 | + inIframe?: boolean; |
| 43 | + /** 路由前缀,发送路由时会替换路由前缀再发送 */ |
| 44 | + prefix?: string; |
| 45 | +} |
| 46 | + |
| 47 | +interface RouteListenerProps { |
| 48 | + postMessage?: RoutePostMessage; |
| 49 | + receiveMessage?: RouteReceiveMessage; |
| 50 | + children: React.ReactNode; |
| 51 | +} |
| 52 | + |
| 53 | +const RouteListener = ({ receiveMessage, postMessage, children }: RouteListenerProps) => { |
| 54 | + const history = useHistory(); |
| 55 | + |
| 56 | + const { pathname, search, hash } = useLocation(); |
| 57 | + // 获取url path |
| 58 | + const urlPath = `${pathname}${search}${hash}`; |
| 59 | + |
| 60 | + useEffect(() => { |
| 61 | + if (postMessage?.customHandler) { |
| 62 | + // 存在自定义操作 |
| 63 | + postMessage.customHandler(urlPath); |
| 64 | + } else if (postMessage?.targetOrigin && postMessage.messageType) { |
| 65 | + // 存在目标源以及消息类型 |
| 66 | + // 路由变更时发送消息 |
| 67 | + const msg: PostMessageData = { |
| 68 | + code: PostMessageCode.SUCCESS, |
| 69 | + type: postMessage.messageType, |
| 70 | + // 存在前缀则先替换前缀 |
| 71 | + data: postMessage.prefix ? urlPath.replace(postMessage.prefix, '') : urlPath, |
| 72 | + }; |
| 73 | + if (postMessage.inIframe && window.self !== window.top) { |
| 74 | + // 在iframe内,对iframe父页面发送路由变更消息 |
| 75 | + window.top?.postMessage(msg, postMessage.targetOrigin); |
| 76 | + } else { |
| 77 | + LogMgr.warn('route 路由变更,未发送消息'); |
| 78 | + } |
| 79 | + } |
| 80 | + }, [urlPath, postMessage]); |
| 81 | + |
| 82 | + useEffect(() => { |
| 83 | + const receiveRouteHandler = (event: MessageEvent<PostMessageData>) => { |
| 84 | + if (receiveMessage?.customHandler) { |
| 85 | + // 存在自定义操作 |
| 86 | + receiveMessage.customHandler(event); |
| 87 | + } else if ( |
| 88 | + receiveMessage?.eventOrigin && receiveMessage.messageType |
| 89 | + && receiveMessage.jumpType && event.origin === receiveMessage.eventOrigin) { |
| 90 | + // 存在发送源、消息类型、路由调整类型,且来自发送源消息 |
| 91 | + const { code, type, data } = event.data; |
| 92 | + if (code === PostMessageCode.SUCCESS && type === receiveMessage.messageType) { |
| 93 | + // 默认匹配 |
| 94 | + const urlPath = receiveMessage.prefix ? `${receiveMessage.prefix}${data}` : data; |
| 95 | + history[receiveMessage.jumpType](urlPath); |
| 96 | + } else { |
| 97 | + LogMgr.warn('接收到 route 消息,未匹配成功,未进行任何处理'); |
| 98 | + } |
| 99 | + } |
| 100 | + }; |
| 101 | + receiveMessage && window.addEventListener('message', receiveRouteHandler, false); |
| 102 | + return () => { |
| 103 | + receiveMessage && window.removeEventListener('message', receiveRouteHandler); |
| 104 | + }; |
| 105 | + }, [receiveMessage]); |
| 106 | + |
| 107 | + return <>{children}</>; |
| 108 | +}; |
| 109 | + |
| 110 | +export default RouteListener; |
0 commit comments