# 前言
该 single-spa-layout NPM包是一个可选的附加单温泉。布局引擎提供了一个路由API,用于控制您的顶级路由,应用程序和dom元素。使用单spa布局可以更轻松地完成以下任务:
- DOM放置和应用程序排序。
- 下载应用程序时加载UI。
- 未找到/ 404页的默认路由。
- 路线之间的转换(执行中)。
布局引擎执行两项主要任务:
- 从HTML元素和/或JSON对象生成单温泉注册配置。
- 侦听路由事件,以确保在安装单spa应用程序之前正确布置所有DOM元素。
single-spa-layout 被压缩为3.2kb(未压缩为9kb)。
# 安装
您只需要将布局引擎安装到您的根配置中即可 (opens new window)(无需在任何其他应用程序中安装)。
npm install --save single-spa-layout@beta
# or
yarn add single-spa-layout@beta
# 项目状态
single-spa-layout 是新的,当前 beta 在npm的dist标签下发布。我们正在收集反馈并改进布局引擎,以准备发布稳定版本。尽管我们不希望版图引擎发生巨大变化,但是我们建议您在正式发布之前不要在生产环境中使用它。
# 浏览器支持
single-spa-layout 在 single-spa 支持的所有浏览器(包括IE11)中均可使用。
# 要求
您必须使用 single-spa @> == 5.4.0才能使布局引擎正常工作。此外,您可能不 domElementGetter 为任何 single-spa 应用程序提供自定义功能,因为这些功能会覆盖 single-spa 布局中的配置。
# 基本用法
在根html文件中,将
<template>元素添加到头部。它应具有<single-spa-router>包含<route>元素,<application>元素和任何其他dom元素的元素:
<html>
<head>
<template id="single-spa-layout">
<single-spa-router>
<nav class="topnav">
<application name="@organization/nav"></application>
</nav>
<div class="main-content">
<route path="settings">
<application name="@organization/settings"></application>
</route>
<route path="clients">
<application name="@organization/clients"></application>
</route>
</div>
<footer>
<application name="@organization/footer"></application>
</footer>
</single-spa-router>
</template>
</head>
</html>
然后在您的root-config的JavaScript代码中,添加以下内容:
import { registerApplication, start } from 'single-spa';
import {
constructApplications,
constructRoutes,
constructLayoutEngine,
} from 'single-spa-layout';
const routes = constructRoutes(document.querySelector('#single-spa-layout'));
const applications = constructApplications({
routes,
loadApp({ name }) {
return System.import(name);
},
});
const layoutEngine = constructLayoutEngine({ routes, applications });
applications.forEach(registerApplication);
start();
# 布局定义
布局是 HTMLElement ,路由 和 single-spa 应用程序的组合。在根配置中静态定义了布局,以处理顶级路由和dom元素。单个 single-spa 布局不应在根配置之外使用;相反,UI框架(React,Angular,Vue)应处理应用程序中的布局。
您可以将布局定义为HTML模板或JSON对象。对于喜欢将布局定义存储在数据库中而不是代码中的组织,支持JSON定义。HTML和JSON布局具有相同的功能集。但是,通常首选在代码中存储布局,并且默认情况下鼓励使用。如果您刚开始使用 single-spa 布局,我们建议您使用HTML模板。
一旦你定义布局,你应该 constructRoutes,constructApplications 和 constructLayoutEngine
# HTML布局
您可以在根配置的 index.html 文件中或在被解析为HTML的javascript字符串中定义HTML布局。我们通常鼓励在根配置的 index.html 文件中定义布局。
要在 index.html 文件中定义布局,请创建一个 <template id="single-spa-layout"> 包含布局的元素。在模板内,添加一个 <single-spa-router>元素以及所有路由,应用程序和dom元素。
请注意,在布局中定义的HTMLElement是静态的-无法强制重新呈现或更改它们。
<!-- index.ejs -->
<html>
<head>
<template>
<single-spa-router>
<div class="main-content">
<route path="settings">
<application name="settings"></application>
</route>
</div>
</single-spa-router>
</template>
</head>
</html>
// 不推荐使用,但是也可以用HTMLElements进行javascript构造
const doc = new DOMParser().parseFromString(`
<single-spa-router>
<div class="main-content">
<route path="settings">
<application name="settings"></application>
</route>
</div>
</single-spa-router>
`, "text/html").documentElement
# JSON布局
您可以将布局定义为JSON,包括路由,应用程序和任意dom元素。
const layout = {
"routes": [
{ "type": "route", "path": "settings", "routes": [
{ "type": "application", "name": "settings" }
]}
]
};
# 布局元素
布局元素是HTMLElement或JSON对象,代表dom节点,路由或应用程序。
# template
仅当将布局定义为HTML时才使用该 template 元素。它的目的是防止其内容被浏览器显示,因为布局定义对用户不可见。
<template>
<!-- 在这里定义您的布局 -->
<single-spa-router></single-spa-router>
</template>
请注意,<template> IE11中不完全支持元素。但是,您无需为了在 single-spa 布局中使用模板元素而对其进行填充。相反,只需添加 style="display: none;" 到模板即可防止其内容显示在IE11中。
<template style="display: none;">
<!-- 在这里定义您的布局 -->
<single-spa-router></single-spa-router>
</template>
# <single-spa-router>
该 single-spa-router 元素是必需的布局的顶层容器。所有属性都是可选的。
<single-spa-router mode="hash|history" base="/" disableWarnings></single-spa-router>
{
"mode": "hash|history",
"base": "/",
"disableWarnings": false,
"containerEl": "#container",
"routes": []
}
属性:
- mode(可选):必须为hash或history默认为的字符串history。这指示路由是否应与Location路径名或hash匹配。
- base (可选):匹配路由路径时将考虑的字符串URL前缀。
- disableWarnings (可选):一个布尔值,当提供的元素不正确时,该布尔值将打开单个spa布局的控制台警告。
- containerEl(可选):字符串CSS选择器或HTMLElement,用作所有单spa dom元素的容器。默认为body。
该
route元素用于控制为顶级URL路由显示哪些应用程序和dom元素。它可能包含HTMLElement,应用程序或其他路由。
<route path="clients">
<application name="clients"></application>
</route>
<route default>
<application name="clients"></application>
</route>
{
"type": "route",
"path": "clients",
"routes": [
{ "type": "application", "name": "clients" }
],
"default": false
}
属性:
路由必须具有路径或为默认路由。
- routes (必填):激活路线时将显示的子元素数组
- path(可选):将与浏览器的URL匹配的字符串路径。路径是相对于其父路径(或基本URL)的。开头和结尾/字符是不必要的,并且会自动应用。通过使用:字符("
clients/:id/reports"),路径可能包含“动态段” 。单spa布局使用单spa的pathToActiveWhen功能将路径字符串转换为活动功能。 - default(可选):一个布尔值,确定此路由是否将与同级路由未定义的所有其余URL匹配。这对于“ 404找不到页面”很有用。同级路由定义为具有相同最近父路由的任何路由。
- props:单spa自定义道具的对象,在安装时将提供给应用程序。请注意,对于不同路径上的同一应用程序,可以对它们进行不同的定义。您可以在下面的文档中阅读有关在HTML中定义道具的更多信息。
# application
该
application元素用于呈现single-spa应用程序。应用程序可以包含在路线元素中,也可以作为将始终呈现的应用程序存在于顶层。呈现应用程序时,将通过single-spa-layout创建一个容器HTMLElement。容器HTMLElement的创建id属性为single-spa-application:appName,以便框架助手在安装应用程序时自动使用它。
同一应用程序可能会在布局中以不同的路线出现多次。但是,每个应用程序只能为每个路由定义一次。
<!-基本用法->
<application name="appName"></application>
<!-使用在javascript中定义的命名加载程序->
<application name="appName" loader="mainContentLoader"></application>
<!-将单spa定制道具添加到应用程序中。prop的值在javascript->中定义
<application name="appName" props="myProp,authToken"></application>
// 基本用法
{
"type": "application",
"name": "appName"
}
// 使用单spa包裹作为加载UI,也可以使用Angular,Vue等。
const parcelConfig = singleSpaReact({...})
{
"type": "application",
"name": "appName",
"loader": parcelConfig
}
// 使用HTML字符串作为加载UI
{
"type": "application",
"name": "appName",
"loader": "<img src='loading.gif'>"
}
// 添加 single-spa 自定义属性
{
"type": "application",
"name": "appName",
"props": {
"myProp": "some-value"
}
}
属性:
name(必需):字符串应用程序名称。loader(可选):HTML字符串或单spa包裹配置对象。在等待应用程序的加载功能解析时,加载程序将安装到DOM 。您可以在下面的文档中阅读有关定义加载程序的更多信息props:单spa自定义道具的对象,在安装时将提供给应用程序。请注意,对于不同路径上的同一应用程序,可以对它们进行不同的定义。您可以在下面的文档中阅读有关在HTML中定义道具的更多信息。
# DOM元素
可以将任意HTMLElement放置在布局中的任何位置。要在HTML中执行此操作,只需像通常一样添加HTMLElemet。目前尚不支持在JSON中定义HTMLElements,但很快就会 跟踪issue (opens new window)。
<nav class="topnav"></nav>
<div class="main-content">
<button>A button</button>
</div>
single-spa-layout 仅在路由转换期间支持更新DOM元素。不支持任意重新渲染和更新。
路由中定义的DOM元素将在路由变为活动/非活动状态时进行安装/卸载。如果在不同的路线下两次定义相同的DOM元素,则在路线之间导航时将销毁并重新创建该DOM元素。
# 属性
single-spa 自定义属性 可以在 route 和 application 元素上定义。任何路由属性都将与应用程序属性合并在一起,以创建最终的属性,并传递到 single-spa 生命周期功能。
# JSON格式
在JSON布局定义中,您可以使用props应用程序和路由上的属性来定义props :
import { constructRoutes } from 'single-spa-layout';
constructRoutes({
routes: [
{ type: "application", name: "nav" props: { title: "Title" } },
{ type: "route", path: "settings" props: { otherProp: "Some value" } },
]
})
# HTML
在JSON对象上定义属性很简单,因为它们可以包含字符串,数字,布尔值,对象,数组等。但是,在HTML中定义复杂的数据类型并不是那么简单,因为HTML属性始终是字符串。要解决此问题,单一spa布局允许您在HTML中命名道具,但可以在javascript中定义其值。
<application name="settings" props="authToken,loggedInUser"></application>
import { constructRoutes } from 'single-spa-layout';
const data = {
props: {
authToken: "fds789dsfyuiosodusfd",
loggedInUser: fetch('/api/logged-in-user').then(r => r.json())
}
}
const routes = constructRoutes(document.querySelector('#single-spa-template'), data)
API的完整API文档详细 constructRoutes 说明了该data对象。
# 加载UI
在等待应用程序的代码下载和执行时,通常希望显示一个加载UI。Single-spa-layout 允许您定义每个应用程序的加载程序,这些加载程序将在应用程序的加载函数 (opens new window)挂起时安装到DOM 。可以为多个应用程序共享相同的加载UI。
加载的UI定义为HTML字符串或 parcel 配置对象 (opens new window)。HTML字符串最适合用于静态,非交互式的加载器,而当您想使用框架(Vue,React,Angular等)动态呈现加载器时, parcels 最适合。
通过javascript对象定义加载程序非常简单,因为它们是一个可以包含字符串,数字,布尔值,对象,数组等的对象。但是,在HTML中定义复杂的数据类型并不是那么简单,因为HTML属性始终是字符串。要解决此问题,单spa布局允许您在HTML中命名加载程序,但可以在javascript中定义其值。
<application name="topnav" loader="topNav"></application>
<application name="topnav" loader="settings"></application>
import { constructRoutes } from 'single-spa-layout';
// 你也可以使用 Angular, Vue, etc.
const settingsLoader = singleSpaReact({...})
const data = {
loaders: {
topNav: `<nav class="placeholder"></nav>`,
settings: settingsLoader
}
}
const routes = constructRoutes(document.querySelector('#single-spa-template'), data)
API的完整API文档详细constructRoutes说明了该data对象。
# 转场
已计划支持路线转换,但尚未实施。如果您对此功能感兴趣,请在此 issue (opens new window) 中提供用例,支持和反馈。
# 默认路由(找不到404)
默认路由是当没有其他同级路由与当前URL匹配时激活的路由。它们没有URL路径,并且可以包含DOM元素和单spa应用程序的任意组合。
<single-spa-router>
<route path="cart"></route>
<route path="product-detail"></route>
<route default>
<h1>404 Not Found</h1>
</route>
</single-spa-router>
默认路由与其同级路由匹配,从而可以嵌套:
<single-spa-router>
<route path="cart"></route>
<route path="product-detail/:productId">
<route path="reviews"></route>
<route path="images"></route>
<route default>
<h1>Unknown product page</h1>
</route>
</route>
<route default>
<h1>404 Not Found</h1>
</route>
</single-spa-router>
兄弟路由定义为共享“最近的父路由”的路由。这意味着它们不必是您的HTML / JSON中的直接同级,而是可以嵌套在DOM元素中:
<single-spa-router>
<route path="product-detail/:productId">
<div class="product-content">
<route path="reviews"></route>
<route path="images"></route>
</div>
<!-- 评论和图片路线是同级,因为它们共享最近的父路线 -->
<!-- 当URL与评论或图片不匹配时,默认路由将激活 -->
<route default>
<h1>Unknown product page</h1>
</route>
</route>
</single-spa-router>