上下文导航插件( E)@equinor/fusion-framework-plugin-context-navigation(中文(简体) )
Fusion Framework门户网站由事件驱动的上下文到URL调节器插件. 它通过对上下文变化和app开关的反应,将上下文编码入URL,以及可选地防范手动URL编辑来降低上下文来保持活性上下文与浏览器URL同步.
何时使用
当您的插件 门户 需要:
- 自动反映浏览器 URL 中的活性上下文( 项目、 设施等)
- 支持多个 URL 编码策略( 路径段、 查询参数, 或 app自定义自定义编码)
- 在整个应用程序开关和页面重载中保留上下文
- 通过手动编辑 URL 防止用户意外丢失上下文
[注] 此插件用于 门户主机,而不是个人申请. 应用程序通过应用程序的显示表来声明其首选的路由策略
build.options.contextRouting字段——门户的上下文导航插件 抓取该声明并自动应用正确的 URL 编码 .
对于应用程序开发者
您不需要安装或配置此插件 。 门户能处理. 你唯一的责任是 声明上下文应如何出现在您的 URL。 。 。 .
宣布路线战略
设定 contextRouting 在你的应用清单 build.options数字 :
// app.manifest.config.ts
export default defineAppManifest((env) => ({
// ...
build: {
options: {
contextRouting: 'query', // or 'path', or omit for default path behavior
},
},
}));
| 数值 | URL 形状 | 何时使用 |
|---|---|---|
'path' (或省略) | /apps/{appKey}/{contextId}/sub-route | 默认——没有复杂路由的简单应用程序 |
'query' | /apps/{appKey}/route?$contextId={id} | 与上下文段相冲突的基于路径的子路由应用程序 |
有自定义 URL 形状的应用程序应当省略 contextRouting 并登记自定义钩(见下文).
[注] 何时
contextRouting未设定( 或设定为null),门户默认为 路径适配器 将上下文编码为应用程序键后的一个路径段. 如果应用程序注册自定义钩( I)setContextPathExtractor编号 :setContextPathGenerator),自定义适配器优先于路径 路径/默认路由的适配器 。 明确contextRouting: 'query'选择 查询适配器,即使已注册自定义路径钩.
自定义URL形状
如果您的应用程序将上下文编码为非标准位置( 例如 ) . /route-a/{contextId}
改为 /{contextId}/route-a),在应用程序上下文中注册自定义钩
配置 :
// app config
builder.setContextPathExtractor((pathname) => {
// Extract context id from your custom URL position
const segments = pathname.split('/').filter(Boolean);
return segments[1]; // e.g. /route-a/{contextId} → contextId
});
builder.setContextPathGenerator((context, pathname) => {
// Generate a URL with context in your custom position
const segments = pathname.split('/').filter(Boolean);
const route = segments[0] ?? '';
return `/${route}/${context.id}`;
});
当这些钩子注册后, 插件的自定义适配器会将其取出
自动——无显示 contextRouting 需要声明.
应用程序拥有其 URL 形状, 因此 URL 是 URL 守护的真实来源 :
- 提取器未返回上下文的路由( 例如列表页, 如
/categories)是一条路线 无 上下文。 URL 守护器没有设置 积极的背景 回到它. - 提取器返回不活动上下文的路由(例如链接)
从列表页到
/app/{key})在推动和 替换模式,并在无上下文活动时替换. - 在无上下文的路由中清除上下文使用户保持在那里. 在有上下文导航到应用根的路径上清除上下文 .
- 在没有上下文的路由中选择上下文仍然导航到
路径从
generatePathFromContext。 。 。 .
提取值不一定是上下文 ID。 如果这是一把钥匙或一发子弹,
uRL 守护器将 URL 视为同步 generatePathFromContext 写入
对当前环境的同样价值。 所以在同一个背景中航行
不会再解决了 返回路径不变的生成器不会
来证明什么,所以守护者从 URL 中解析值.
在不相干的路由片段中重复的密钥不会触发另一个查询.
当 URL 守护从 URL 中解析上下文时, 查找属于此 URL (中文(简体) ). 如果用户在搜索完成前在别处导航, 守卫 取消它:迟到的结果既不改变上下文,也不改变用户的方向. 应用软件解职、应用开关和模块装入也取消了等待检查, 甚至在下一个导航事件之前,或者当目的地没有上下文模块时.
用于门户开发者
本README的其余部分涵盖门户级设置和配置.
关键概念
| 概念 | 说明 |
|---|---|
| 适配器 | 自选URL编码器/解码器. 每个适配器宣布 canHandle() 提供 encode() 编号 : decode() 方法。 。 . |
| 调试器 | 监视上下文+应用程序变化并触发URL出同步后导航的被动循环. |
| URL 守护 | 如果外部导航将上下文从 URL 掉出, 可选的二次订阅会重新应用上下文编码 . |
| 来源 | 驱动调和器的可观察工厂——决定是应用开关还是上下文变化优先. |
如何运作
- 观察 ——调节器通过可配置源厂来监视当前应用和当前上下文.
- 解析适配器 - 对于每个应用程序,第一个适配器
canHandle()返回时true已选定. - 编码 ——所选适配器将上下文编码为目标URL.
- 比较 ——如果目标URL与当前URL不同,则导航会继续.
- 调度 - 可取消的
onContextNavigationNavigate事件火灾。 听者可以打电话preventDefault()以中止. - 导航 ——框架导航模块实现URL更新.
- 确认 - 一个
onContextNavigationNavigated导航完成后发生事件起火.
安装
pnpm add @equinor/fusion-framework-plugin-context-navigation
快速启动
端口(应用程序开关铅)
一个应用门户网站一次显示一个应用. 当用户切换应用时, 调节器 取出新应用程序的上下文并将其编码入URL. 这是默认行为.
import { enableContextNavigation } from '@equinor/fusion-framework-plugin-context-navigation';
export const configure = (configurator) => {
enableContextNavigation(configurator, (builder) => {
builder.setPortalName('app-portal');
builder.setDebug(true);
});
};
默认源厂( E)createAppFirstSource手表( 手表 ) app.current$ 财务报告和审定财务报表
在向调和器发送前先解决应用程序的上下文模块。 当应用程序
切换发生,新应用程序的活性上下文驱动URL更新.
上下文门户( 文本更改铅)
环绕一个共同的环境(例如一个项目)组织一个上下文门户。 当 用户选择上下文,导航立即更新 URL ——无论 该应用程序已激活。 清除上下文可返回门户根 .
import { enableContextNavigation } from '@equinor/fusion-framework-plugin-context-navigation';
import { createContextFirstSource } from '@equinor/fusion-framework-plugin-context-navigation/sources';
export const configure = (configurator) => {
enableContextNavigation(configurator, (builder) => {
builder.setPortalName('context-portal');
builder.setSourceFactory(createContextFirstSource());
builder.setNullContextUrl('/');
builder.setDebug(true);
});
};
与app-portal的关键差异 :
createContextFirstSource()——上下文变化为主触发;应用模块作为依赖解决.setNullContextUrl('/')– 当上下文被清除后, 导航到出入口登陆页面, 而不是授权适配器 .
内建适应器
装有3个适配器的插件船按优先顺序评估:
| 适配器 | URL 形状 | 选中时 |
|---|---|---|
| 自定义 | App 定义( 通过 generatePathFromContext 编号 : extractContextIdFromPath 钩子) | App 提供自定义钩子, 不声明 contextRouting: 'query' |
| 查询 | /apps/{appKey}/route?$contextId={id} | 应用显示声明 build.options.contextRouting: 'query' |
| 路径 | /apps/{appKey}/{contextId}/sub-route | 默认倒计时——匹配 contextRouting 实值 'path', (中文(简体) ), null,或省略 |
当没有注册自定义适配器时,所有三个内置适配器都可以使用. 第一个 canHandle() 返回时 true 当前应用程序获胜.
注册自定义适配器
您可以为内置集未覆盖的 URL 形状注册自己的适配器 .
这个 canHandle 选择适配器时的上方控件——使用任何信号
备查 AdapterResolutionContext (app key, URL, 上下文提供者, 路由策略).
import type { ContextNavigationAdapter } from '@equinor/fusion-framework-plugin-context-navigation/adapters';
const hashAdapter: ContextNavigationAdapter = {
id: 'hash',
// Select this adapter for a specific app that uses hash-based context
canHandle: ({ appKey }) => appKey === 'my-hash-app',
encode: ({ context, currentURL }) => {
const url = new URL(currentURL.href);
url.hash = context ? `#ctx=${context.id}` : '';
return url;
},
decode: (url) => {
const match = url.hash.match(/^#ctx=(.+)$/);
return match?.[1] ?? null;
},
};
enableContextNavigation(configurator, (builder) => {
builder.registerAdapter(hashAdapter);
// NOTE: registering any adapter disables built-in defaults.
// Register all adapters you need explicitly.
});
配置
| 构建方法 | 默认 | 说明 |
|---|---|---|
registerAdapter(adapter) | 内置套装 | 登记导航适配器(对象或工厂)。 第一场比赛获胜. |
setPortalName(name) | 'Portal' | 调试日志输出中使用的名称 . |
setOrigin(origin) | window.location.origin | 构建绝对 URL 的出处 . |
setUrlGuard(enabled) | true | 如果外部导航从 URL 中掉入, 则重新同步上下文 。 与 replace: false,后向导航从 URL 更新上下文,而不是覆盖上下文。 带有自定义路径钩子的 Apps 总是将 URL 视为真理的来源(参见 自定义URL形状) (中文(简体) ). |
setDebug(enabled) | false | 启用动词 console.debug 输出. |
setNullContextUrl(urlOrFn) | —— 说 | 函数( 或静态字符串) , 将 URL 返回到上下文被清除时的导航 。 接收 { appKey, currentURL }。 。 。 . |
setRequireValidContext(enabled) | false | 对照 app 上下文模块验证上下文( )validateContext)通航前. 如果验证失败, 导航会被跳过 . |
setNavigationOptions(options) | { replace: true } | 转到 navigation.navigate() uRL更新期间。 设定 { replace: false } 来将历史条目推出 —— 然后从 URL 同步上下文, 而不是重新输入活动上下文 . |
setOnTransition(fn) | —— 说 | 副作用钩在每次成功导航后呼叫. |
setSourceFactory(factory) | createAppFirstSource() | 驱动调和器的可观察源厂. |
活动
该插件通过Fusion框架事件系统发送事件. 通过 framework.event.addEventListener()。 。 。 .
| 活动 | 何时 | 可取消 |
|---|---|---|
onContextNavigationNavigate | 在导航——适配器解决之前,目标 URL 计算 | 对 |
onContextNavigationNavigated | 导航完成后 | 没有 |
onContextNavigationAdapterResolved | 当为应用程序选择适配器时 | 没有 |
onContextNavigationSkipped | 当调节决定不导航时 | 没有 |
跳过原因
这个 onContextNavigationSkipped 事件包括a reason 字段 :
| 原因 | 含义 |
|---|---|
'url-matches' | 目标 URL 已经匹配当前 URL |
'no-context' | 上下文为 undefined (仍在初始化) |
'no-adapter' | 没有适配器能处理当前应用程序 |
'invalid-app-context' | setRequireValidContext(true) 设置, 且应用程序上下文模块拒绝上下文 |
'encode-returned-null' | 适应者 encode() 已返回 null |
'canceled' | 一个听众打电话 preventDefault() 导航事件 |
拦截导航
framework.event.addEventListener('onContextNavigationNavigate', (event) => {
console.log('About to navigate:', event.detail.targetURL.pathname);
// Cancel navigation conditionally
if (shouldBlock(event.detail)) {
event.preventDefault();
}
});
适配器接口
interface ContextNavigationAdapter {
/** Unique identifier for logging and diagnostics. */
id: string;
/** Return `true` if this adapter handles the given app/URL combination. */
canHandle(ctx: AdapterResolutionContext): boolean;
/** Encode context into a URL. Return `null` to skip navigation. */
encode(args: { context: ContextItem | null; currentURL: URL }): URL | null;
/** Decode a context ID from a URL. Return `null` if not present. */
decode(url: URL): string | null;
}
interface AdapterResolutionContext {
appKey: string;
appContext: IContextProvider;
routingStrategy?: 'path' | 'query' | null;
currentURL: URL;
}
出口
| 指定者 | 说明 |
|---|---|
@equinor/fusion-framework-plugin-context-navigation | 插件运行时间、 配置器、 启用助手、 类型、 事件 |
@equinor/fusion-framework-plugin-context-navigation/adapters | 内建适配工厂(createPathAdapter, (中文(简体) ), createQueryAdapter, (中文(简体) ), createCustomAdapter(中文(简体) ) |
@equinor/fusion-framework-plugin-context-navigation/sources | 来源工厂(createAppFirstSource, (中文(简体) ), createContextFirstSource)和调节器类型 |
@equinor/fusion-framework-plugin-context-navigation/utils | URL 工具函数 |
同伴依赖关系
| 软件包 | 目的 |
|---|---|
@equinor/fusion-framework-module | 基本单元合同 |
@equinor/fusion-framework-module-app | 应用程序切换和实例加载 |
@equinor/fusion-framework-module-context | 国家管理 |
@equinor/fusion-framework-module-navigation | URL 导航 |
@equinor/fusion-framework-module-event | 事件发送 |
rxjs | 反应流 |
另见
@equinor/fusion-framework-module-context查询、验证和解析的背景模块@equinor/fusion-framework-module-app——应用模块定义FrameworkOptions.contextRouting在建筑列表中