HashNavigation 改名 Navigation(src/lib/navigation.js),接口不变,内部改用真实路径: parseUrlHash/composeUrlHash 改名 parseUrl/composeUrl;navigateTo/navigateReplace 改调 pushState/replaceState 后手动派发 popstate(pushState/replaceState 不会像赋值 location.hash 那样自动触发事件,这里复用 navigateReplace 早就在用的同一个手动 dispatch 手法);goBack() 不用改,history.back() 本来就是真实浏览器历史机制。新增 Navigation.currentUrl() 替代调用方 原本直接读的 window.location.hash(这个类从来没包装过这个读取)。 一处需要专门处理的边界情况:当 path[0] 是空字符串("不选中侧栏视图、只开一个会话"这个仓库里 的合法状态)时,拼出的真实路径开头会变成双斜杠,被浏览器当协议相对地址解析、试图跳到一个叫 会话id的host,pushState 直接抛 SecurityError。composeUrl/parseUrl 内部用占位 token "_" 处理 这种情况,对外的调用方(19个文件)完全无感。 tinode-web.jsx 的 handleHashRoute 改名 handleRouteChange,监听从 hashchange 换成 popstate; service-worker.js 的推送通知点击跳转手动改写成同样的路径格式(这个文件在打包之外单独执行, 没法 import Navigation)。index.html/index-dev.html 加了 <base href="/">——所有静态资源引用 都是相对路径,hash 路由下页面路径永远是 /,换真实路径后深层地址刷新会按当前目录解析出错误 资源地址导致白屏,这一行是标准修法。nginx.conf 的 try_files 兜底规则本来就适用两种路由,只 更新了注释。 实机验证:地址栏不再有 #;点击会话/设置等各类视图正常跳转;浏览器前进后退和应用内"返回" 按钮都正常;收藏页内部的类型 tab 切换(navigateReplace)确认不产生新的历史记录;在会话页/ 个人中心页刷新、直接用完整深层路径打开新标签页都能正确恢复到位,资源正常加载不白屏。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
49 lines
2.9 KiB
HTML
49 lines
2.9 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>MeetingIM</title>
|
|
<meta charset="utf-8" />
|
|
<!-- Real (History API) routing means the address bar can show a deep, multi-segment path like
|
|
/messages-home/grpXXX -- every asset reference below is a relative path (css/base.min.css,
|
|
umd/index.prod.js, etc.), which would otherwise resolve against that deep path instead of the
|
|
app's actual root on a deep-linked load or a refresh, 404ing everything. This pins relative
|
|
resolution to root regardless of the current path. -->
|
|
<base href="/" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta name="application-name" content="MeetingIM" />
|
|
<meta name="description" content="MeetingIM instant messenger in a browser" />
|
|
<meta name="application-url" content="https://web.118im.com/">
|
|
<meta name="theme-color" content="#3949AB" />
|
|
<meta name="google" value="notranslate" />
|
|
<meta name="format-detection" content="telephone=no" />
|
|
<meta name="og:url" content="https://web.118im.com/">
|
|
<meta name="og:title" content="MeetingIM">
|
|
<meta name="og:image" content="img/og-logo.jpeg">
|
|
<meta name="og:description" content="MeetingIM instant messenger in a browser" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<link rel="manifest" href="manifest.json" />
|
|
<link rel="shortcut icon" id="shortcut-icon" href="img/logo32x32.png" type="image/png" />
|
|
<link rel="apple-touch-icon" sizes="192x192" href="img/logo192.png" type="image/png" />
|
|
<link rel="canonical" href="https://web.118im.com/" />
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,500,700,700i" />
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
|
<link rel="stylesheet" href="css/base.min.css" />
|
|
<script crossorigin="anonymous" src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.Segmenter"></script>
|
|
<script crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/react@18.3.1/umd/react.production.min.js"></script>
|
|
<script crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/react-dom@18.3.1/umd/react-dom.production.min.js"></script>
|
|
<script crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/react-intl@7.1.6/react-intl.iife.min.js"></script>
|
|
<script crossorigin="anonymous" src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script>
|
|
</head>
|
|
<body>
|
|
<noscript><div id="noscript-message"><div id="noscript-title">Javascript support is required.</div>
|
|
<div id="noscript-content">It appears JavaScript is turned off or is not supported by your browser.
|
|
MeetingIM does not work without JavaScript. Please enable JavaScript by changing your browser options,
|
|
then <a href="">try again</a>.</div></div></noscript>
|
|
<div id="mountPoint"></div>
|
|
<script src="firebase-init.js"></script>
|
|
<script src="umd/tinode.prod.js"></script>
|
|
<script src="umd/index.prod.js"></script>
|
|
</body>
|
|
</html>
|