# 前言

git仓库 (opens new window)

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-layoutsingle-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模板。

一旦你定义布局,你应该 constructRoutesconstructApplicationsconstructLayoutEngine

# 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 自定义属性 可以在 routeapplication 元素上定义。任何路由属性都将与应用程序属性合并在一起,以创建最终的属性,并传递到 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>
阅读全文