# @ecopages/browser-router 中文文档

规范地址：https://npmcn.com/package/%40ecopages/browser-router/

版本：0\.7\.1
npm 元数据更新时间：2026-11-12T23:40:43.377Z
中文译文更新时间：2026-11-13T06:16:46.147Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40ecopages/browser-router
原文对照：https://npmcn.com/package/%40ecopages/browser-router/?lang=original
源码仓库：https://github.com/ecopages/ecopages

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：87.2 kB，25 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：^24\.22\.0 \|\| \>=26\.0\.0
- 运行依赖：1 个
- peer 依赖：@ecopages/core 0\.7\.1
- 首次发布：2026-03-08T20:19:13.573Z
- 最新版本发布：2026-11-12T23:40:43.018Z
- 近 30 天下载量：3301（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：126（近 12 个月 126 个）

## 中文简介

支持视图过渡的 Ecopage 客户端路由器

## 安装

```sh
npm install @ecopages/browser-router
```

也可以使用：`pnpm add @ecopages/browser-router`、`yarn add @ecopages/browser-router`、`bun add @ecopages/browser-router`

## README

# 校对:soup

Ecopage的客户端导航和视图过渡. 它截取同源链接点击,以提供平滑的页面转换而无需全页重载.

## 特征

-   **客户端导航**: 拦截 `<a>` 点击以获得强大的,快速的导航.
-   **高效 DOM 分发**: 用途 [形态](https://github.com/patrick-steele-idem/morphdom) 仅更新更改的内容,保留滚动位置和内部状态.
-   **国家的持久性**键 `data-eco-persist` 永远不会重新创建, 保存 Web 组件状态, 事件听众, 并形成值 .
-   **查看过渡**: 与视图过渡API的可选集成.
-   **生命周期事件**: 钩入导航 `eco:before-swap`, (中文(简体) ), `eco:after-swap`, (中文(简体) ), `eco:page-load`。 。 。 .

核心导航管道共享文档获取、解析、头调和、样式表显示、脚本激活、命名视图过渡和生命周期事件 `@ecopages/react-router`。浏览器-路由器总是对即将到来的天体进行变形,无论视图-过渡设置或重运行脚本,都在整个导航中保留了恒定元素。 查看过渡只包入形态;滚动还原使用共享的后游钩.

浏览器-路由器保留了自己预留和访问页面的缓存:一次重访会让缓存的HTML立即被刷新,而缓存副本在背景中不被刷新. 设定 `prefetch: false` 以关闭缓存,所以每个导航都会获取新的 HTML. `@ecopages/react-router` 不读取此缓存, 并总是获取新的 HTML .

## 兼容性

这个软件包是为MPA风格的渲染而设计的,服务器返回了完整的HTML页面(如KitaJS,Lit,vanilla JS,或组件级反应岛).

> \[尖叫声\] **不兼容完整 React 应用程序 .** 如果您正在构建反应应用程序, 请使用 [@ ecopages/ react- routter](https://npmcn.com/package/%40ecopages/react-router/README.md) 相反,由于React管理着自己的虚拟DOM和水分生命周期.

> \[注\] `@ecopages/browser-router` 仍然可以参与包含React-router页面和非React页面的混合站点. 在该设置中,浏览器-router仍然负责DOM- switching非React文档,React-router可以通过共享的导航协调器将已经触摸到的非React页面交给它.

## 安装

```bash
bun add @ecopages/browser-router
```

## 使用量

在 a 中创建并启动路由器 **全球** 客户端脚本( 例如 ), `src/layouts/base-layout.script.ts`) (中文(简体) ).

> \[大 确保路由器脚本注入到一个 **连续顺序** 内部 `<head>` 横跨所有页面。 顺序不一致的原因 `morphdom` 以重新装入样式,从而导致“未设定内容的闪烁”.

```ts
import { createRouter } from '@ecopages/browser-router/client';

// Creates and starts the router with default options
const router = createRouter();
```

带有自定义选项 :

```ts
import { createRouter } from '@ecopages/browser-router/client';

const router = createRouter({
    viewTransitions: true,
    scrollBehavior: 'auto',
    documentElementAttributesToSync: ['lang', 'dir', 'data-theme'],
});
```

默认情况下,当视图转换启用时,路由器会选择文档退出 UA 根组(在暗主题上没有更轻的闪光),只调用 `startViewTransition` 当页面使用时 `data-view-transition` 共有元素形态。 设定 `viewTransitions: false` 以禁用.

默认情况下, 浏览器路由器只同步 root `<html>` 它拥有的元数据。 客户端管理的属性以及主题状态等类被保留,除非您明确将其包含在 `documentElementAttributesToSync`。 。 。 .

对于高级案例,浏览器-路由器也会导出低等文档同步工具而不改变路由器实例 API:

```ts
import {
    createRouter,
    DEFAULT_DOCUMENT_ELEMENT_ATTRIBUTES_TO_SYNC,
    syncDocumentElementAttributes,
} from '@ecopages/browser-router';

const router = createRouter();

document.addEventListener('eco:before-swap', (event) => {
    syncDocumentElementAttributes(document, event.detail.newDocument, [
        ...DEFAULT_DOCUMENT_ELEMENT_ATTRIBUTES_TO_SYNC,
        'data-theme',
    ]);
});
```

装入路由器脚本是该页外壳上浏览器-路由器管理的导航的选入点. 没有路由器脚本的页面继续使用普通文档导航.

## 路由器单子

`createRouter()` 返回每个浏览器标签的单个活动路由器。 第一个呼叫创建、启动和存储实例 `window.__ecopages_browser_router__`。以后会调回同一实例,而忽略新的选项.

打电话 `router.stop()` 在长寿会话中替换路由器脚本之前(例如之后) `data-eco-rerun` 重新装入),如果需要新实例,有不同的选项.

## 配置

| 选项 | 类型 | 默认 | 说明 |
| :-- | :-- | :-- | :-- |
| `linkSelector` | `string` | `'a[href]'` | 要截取的链接选择器 |
| `documentElementAttributesToSync` | `string[]` | `['lang', 'dir', 'data-eco-document-owner']` | `<html>` 属性以同步; 保留其他根属性 |
| `persistAttribute` | `string` | `'data-eco-persist'` | 标记 DOM 持久性元素的属性 |
| `reloadAttribute` | `string` | `'data-eco-reload'` | 强制重新装入完整页面的属性 |
| `updateHistory` | `boolean` | `true` | 是否更新浏览器历史 |
| `scrollBehavior` | `'top' | 'preserve' | 'auto'` | `'top'` | 导航后滚动行为 |
| `viewTransitions` | `boolean` | `true` | 查看过渡 API; 默认情况下禁用 UA root 交叉 . `false` 禁用 . |
| `smoothScroll` | `boolean` | `false` | 导航时使用平滑滚动 |
| `reloadDocument` | `(href: string) => void` | `(href) => window.location.assign(href)` | 当路由器将导航递回浏览器时, 将 URL 装入为完整文档 |

## 持久性

在每个页面上标记具有相同持久性密钥的元素,以在整个导航中保存. 当接入的页面将元素保存在一个相容的祖先结构下时,它会保持连接,并且永远不会被再创建;形态会完全跳过. 当视图过渡被禁用时, 以及进入的页面已关闭时, 此选项将保留 `data-eco-rerun` 剧本. 改变元素的祖先标记可能要求更换其所包含路径,因此在连接连续性重要时保持该结构的稳定.

在导航到另一个 URL 时, 当进入的页面有一个 `data-eco-rerun` 脚本,浏览器-路由器在运行前会刷新匹配非已存在的元素,除了正体,坚持元素,其祖先路径,以及该路径上自定义元素的后人. 这些定制的后人留在原地,因为连接的东道主可能附靠他们。 保持处理器捆绑的儿童标记在结构上跨页相容,或者当其儿童标记改变时其组件被重新组合;替换一个儿童不会重新连接主机. 安装在刷新元素上的事件处理器附加到新的节点上,而不是堆放在由形态保留下来的节点上. 一个在任何保留节点上安装处理器的再运行脚本必须使该注册同位素,因为这些节点仍然连接在通航上.

```html
<!-- This counter keeps its internal state across all navigations -->
<radiant-counter data-eco-persist="counter"></radiant-counter>
```

## 重新装入当前页面

`reloadCurrentPage()` 在导航运行时间上,当服务器发送的模板如页面、版式、包含或视图被保存,当模块更新重新加载活动页面时,HMR将调用(`clearCache: false`),再次获取当前 URL,并将上个文档中每个正文元素的服务器标记与新文档中的标记比较,而不是与活文元素比较. 一个其服务器标记没有改变的元素会停留在它的状态,子,阴影根和运行时间属性;一个已改变的自定义元素被替换,一个已改变的平原元素被变形,当自己的服务器属性没有改变时会保留活的属性. 重放脚本不会刷新重装时的元素, 所以 a `data-eco-rerun` 脚本必须在重装不替换的每个元素上登记处理器,这些元素只是更改了的自定义元素. 导航到上文所述的另一种URL形态. 路由器仅在开发 HMR 调用后才记录服务器标记 `enableReloadStatePreservation()` 在导航运行时间, 所以生产导航 复制什么.

已知限制 :

-   在全页负载后的第一个保存比作正文,因为路由器在开始录制时找到了它,所以一个在之前在客户端上渲染出或改变其属性的组件被替换一次.
-   状态跟随树形位置,因此当插入或去除较早的兄弟姐妹时,相同的兄弟姐妹主机可以互换状态.

## 导航脚本

互换后,一头脚本只在上页头没有的情况下运行,而身体脚本运行在每个导航上,如"涡轮":即使上页脚本相同,身体也是新内容. 这涵盖了内置脚本和外部经典脚本;一个外部模块脚本只在标签中每个URL运行一次,因为浏览器对每个模块URL进行一次评价. 经典剧本的顶级 `const`, (中文(简体) ), `let` 财务报告和审定财务报表 `class` 声明活在页面的全球范围,所以当一个经典的正文脚本再次运行时,声明两次并扔出 `SyntaxError: Identifier '…' has already been declared`。不写脚本(使用 `var` 或功能,或将代码包裹在一个块或一个IIFE中,或使其成为模块脚本,每个 URL 运行一次,然后听 `eco:page-load` 每次访问都必须执行的代码 标记元素内的脚本 `data-eco-persist` 保持原样,不再运行。 脚本按一个顺序运行:新头脚本,然后 `data-eco-rerun` 脚本,然后是正文脚本,每组按文档顺序排列. 每个都等待到较早的封禁脚本( 外部经典脚本没有 `async`, (中文(简体) ), `defer`,或 `nomodule`) 已经装入, 如在页面解析时一样, 因此一个内置的脚本会使用一个库, 页面加载在它之后运行 。 外部 `defer` 和模块脚本也保留该插入顺序;只有脚本页标记 `async` 他们一上膛就马上跑 如果下一个导航在脚本仍在装入时互换页面,则前作序列的其余部分不运行.

## 脚本重执行

要强制一个头脚本在每个导航上重新执行(例如分析),请添加 `data-eco-rerun`数字 :

```html
<script data-eco-rerun="true">
    trackPageview();
</script>
```

> \[注\] `data-eco-script-id` 是可选的。 重运行脚本需要明确稳定身份时使用. 没有它,一个HTML `id` 优先;否则路由器按正本匹配 `src` 或内含内容。 相对匹配时 `src`,不同身份的身份保持不变 `<base>` URL,同时一个外部模块从接入的页面解析的URL中重新运行.

## 强制全部重装

使用 `data-eco-reload` 在锁定标签上绕过路由器并强制重新装入完整页面:

```html
<a href="/logout" data-eco-reload>Logout</a>
```

## 活动

收听导航周期事件 `document`。事件细节类型 `@ecopages/core/client`。 。 。 .

```ts
document.addEventListener('eco:before-swap', (e) => {
    console.log('Navigating to:', e.detail.url);
    // Call e.detail.reload() to abort client-side navigation and do a full reload
});

document.addEventListener('eco:after-swap', (e) => {
    console.log('Swapped to:', e.detail.url);
});

document.addEventListener('eco:page-load', (e) => {
    console.log('Page loaded:', e.detail.url);
});
```

`e.detail.newDocument` 是解析后收到的文档,一个听众可能会更改它。 自定义路由器所插入或替换的元素是文档本身的节点,所以您在它们上设置的属性,以及它们的嵌入节点,当浏览器升级和连接时仍然在那里:

```ts
document.addEventListener('eco:before-swap', (e) => {
    const host = e.detail.newDocument.querySelector('my-host');
    if (host) host.engine = engine;
});
```

路由器所保存的元素,例如恒定元素,忽略其来对应方设置的属性. 一个元素升级前设置的属性阴影了同名的类存取器,被该名称的类域所重置:该组件应当读取自有值,删除并通过其构造器中的存取器进行分配.

## 程序导航

使用路由器实例在程序上导航 :

```ts
import { createRouter } from '@ecopages/browser-router/client';

const router = createRouter();

// Navigate with pushState
await router.navigate('/new-page');

// Navigate with replaceState
await router.navigate('/new-page', { replace: true });
```

## 常见问题

### @ecopages/browser-router 是什么？

支持视图过渡的 Ecopage 客户端路由器

### 如何安装 @ecopages/browser-router？

在项目目录运行 npm install @ecopages/browser-router，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@ecopages/core（0\.7\.1）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @ecopages/browser-router 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @ecopages/browser-router 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @ecopages/browser-router 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js ^24\.22\.0 \|\| \>=26\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @ecopages/browser-router 可以商用吗？

@ecopages/browser-router 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @ecopages/browser-router 的下载量有多少？

根据 npm 官方下载统计，@ecopages/browser-router 在 2026/10/13 – 2026/11/11 这 30 天内被下载 3,301 次，日均约 110 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @ecopages/browser-router 还在维护吗？

最新版本 0\.7\.1 发布于 2026/11/13（今天）；至今共发布 126 个版本，其中过去 12 个月发布了 126 个；首次发布于 2026/03/09。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

