diff --git a/docs/docs/specs/lowcode-spec.md b/docs/docs/specs/lowcode-spec.md index 297381fe6..59ff85586 100644 --- a/docs/docs/specs/lowcode-spec.md +++ b/docs/docs/specs/lowcode-spec.md @@ -25,7 +25,7 @@ sidebar_position: 0 ### 1.3 版本号 -1.0.0 +1.1.0 ### 1.4 协议版本号规范(A) @@ -124,7 +124,8 @@ sidebar_position: 0 - config: { Object } 当前应用配置信息 - meta: { Object } 当前应用元数据信息 - dataSource: { Array } 当前应用的公共数据源 - +- router: { Object } 当前应用的路由配置信息 +- pages: { Array } 当前应用的所有页面信息 描述举例: @@ -163,6 +164,7 @@ sidebar_position: 0 } }], "componentsTree": [{ // 描述内容,值类型 Array + "id": "page1", "componentName": "Page", // 单个页面,枚举类型 Page|Block|Component "fileName": "Page1", "props": {}, @@ -213,7 +215,7 @@ sidebar_position: 0 "css": "body {font-size: 12px;} .table { width: 100px;}", "config": { // 当前应用配置信息 "sdkVersion": "1.0.3", // 渲染模块版本 - "historyMode": "hash", // 浏览器路由:browser 哈希路由:hash + "historyMode": "hash", // 不推荐,推荐在 router 字段中配置 "targetRootID": "J_Container", "layout": { "componentName": "BasicLayout", @@ -250,7 +252,23 @@ sidebar_position: 0 "i18n-jwg27yo4": "Hello", "i18n-jwg27yo3": "China" } - } + }, + "router": { + "baseUrl": "/", + "historyMode": "hash", // 浏览器路由:browser 哈希路由:hash + "routes": [ + { + "path": "home", + "page": "page1" + } + ] + }, + "pages": [ + { + "id": "page1", + "treeId": "page1" + } + ] } ``` @@ -1252,7 +1270,7 @@ export const recordEvent = function(logkey, gmkey, gokey, reqMethod) { ### 2.8 当前应用配置信息(AA) -用于描述当前应用的配置信息,比如当前应用的路由模式、Shell/Layout、主题等。 +用于描述当前应用的配置信息,比如当前应用的 Shell/Layout、主题等。 > 注意:该字段为扩展字段,消费方式由各自场景自己决定,包括运行时和出码。 @@ -1267,6 +1285,192 @@ export const recordEvent = function(logkey, gmkey, gokey, reqMethod) { 用于描述当前应用的公共数据源,数据结构跟容器结构里的 ComponentDataSource 保持一致。 在运行时 / 出码使用时,API 和应用级数据源 API 保持一致,都是 `this.dataSourceMap['globalDSName'].load()` +### 2.11 当前应用的路由信息(AA) + +用于描述当前应用的路径 - 页面的关系。通过声明路由信息,应用能够在不同的路径里显示对应的页面。 + +##### 2.11.1 Router (应用路由配置)结构描述 + +路由配置的结构说明: + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | 备注 | +| ----------- | ---------------------- | ------------------------------- | ------ | --------- | ------ | +| baseName | 应用根路径 | String | - | '/' | 选填| | +| historyMode | history 模式 | 枚举类型,包括'browser'、'hash' | - | 'browser' | 选填| | +| routes | 路由对象组,路径与页面的关系对照组 | Route[] | - | - | 必填| | + + +##### 2.11.2 Route (路由记录)结构描述 + +路由记录,路径与页面的关系对照。Route 的结构说明: + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | 备注 | +| -------- | ---------------------------- | ---------------------------- | ------ | ------ | ---------------------------------------------------------------------- | +| name | 该路径项的名称 | String | - | - | 选填 | +| path | 路径 | String | - | - | 必填,路径规则详见下面说明 | +| query | 路径的 query 参数 | Object | - | - | 选填 | +| page | 路径对应的页面 ID | String | - | - | 选填,page 与 redirect 字段中必须要有有一个存在 | +| redirect | 此路径需要重定向到的路由信息 | String \| Object \| Function | - | - | 选填,page 与 redirect 字段中必须要有有一个存在,详见下文 **redirect** | +| meta | 路由元数据 | Object | - | - | 选填 | +| children | 子路由 | Route[] | - | - | 选填 | + +以上结构仅说明了路由记录需要的必需字段,如果需要更多的信息字段可以自行实现。 + +关于 **path** 字段的详细说明: + +路由记录通常通过声明 path 字段来匹配对应的浏览器 URL 来确认是否满足匹配条件,如 `path=abc` 能匹配到 `/abc` 这个 URL。 + +> 在声明 path 字段的时候,可省略 `/`,只声明后面的字符,如 `/abc` 可声明为 `abc`。 + +path(页面路径)是浏览器URL的组成部分,同时大部分网站的 URL 也都受到了 Restful 思想的影响,所以我们也是用类似的形式作为路径的规则基底。 +路径规则是路由配置的重要组成部分,我们希望一个路径配置的基本能力需要支持具体的路径(/xxx)与路径参数 (/:abc)。 + +以一个 `/one/:two?/three/:four?/:five?` 路径为例,它能够解析以下路径: +- `/one/three` +- `/one/:two/three` +- `/one/three/:four` +- `/one/three/:five` +- `/one/:two/three/:four` +- `/one/:two/three/:five` +- `/one/three/:four/:five` +- `/one/:two/three/:four/:five` + +更多的路径规则,如路径中的通配符、多次匹配等能力如有需要可自行实现。 + +关于 **redirect** 字段的详细说明: + +**redirect** 字段有三种填入类型,分别是 `String`、`Object`、`Function`: +1. 字符串(`String`)格式下默认处理为重定向到路径,支持传入 '/xxx'、'/xxx?ab=c'。 +2. 对象(`String`)格式下可传入路由对象,如 { name: 'xxx' }、{ path: '/xxx' },可重定向到对应的路由对象。 +3. 函数`Function`格式为`(to) => Route`,它的入参为当前路由项信息,支持返回一个 Route 对象或者字符串,存在一些特殊情况,在重定向的时候需要对重定向之后的路径进行处理的情况下,需要使用函数声明。 + +```json +{ + "redirect": { + "type": "JSFunction", + "value": "(to) => { return { path: '/a', query: { fromPath: to.path } } }", + } +} +``` + +##### 完整描述示例 + +``` json +{ + "router": { + "baseName": "/", + "historyMode": "hash", + "routes": [ + { + "path": "home", + "page": "home" + }, + { + "path": "/*", + "redirect": "notFound" + } + ] + }, + "componentsTree": [ + { + "id": "home", + ... + }, + { + "id": "notFound", + ... + } + ] +} +``` + +### 2.12 当前应用的页面信息(AA) + +用于描述当前应用的页面信息,比如页面对应的低代码搭建内容、页面标题、页面配置等。 +在一些比较复杂的场景下,允许声明一层页面映射关系,以支持页面声明更多信息与配置,同时能够支持不同类型的产物。 + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | 备注 | +| ------- | --------------------- | ------ | ------ | ------ | -------------------------------------------------------- | +| id | 页面 id | String | - | - | 必填 | +| type | 页面类型 | String | - | - | 选填,可用来区分页面的类型 | +| treeId | 对应的低代码树中的 id | String | - | - | 选填,页面对应的 componentsTree 中的子项 id | +| packageId | 对应的资产包对象 | String | - | - | 选填,页面对应的资产包对象,一般用于微应用场景下,当路由匹配到当前页面的时候,会加载 `packageId` 对应的微应用进行渲染。 | +| meta | 页面元信息 | Object | - | - | 选填,用于描述当前应用的配置信息 | +| config | 页面配置 | Object | - | - | 选填,用于描述当前应用的元数据信息 | + + +#### 2.12.1 微应用(低代码+)相关说明 + +在开发过程中,我们经常会遇到一些特殊的情况,比如一个低代码应用想要集成一些别的系统的页面或者系统中的一些页面只能是源码开发(与低代码相对的纯工程代码形式),为了满足更多的使用场景,应用级渲染引擎引入了微应用(微前端)的概念,使低代码页面与其他的页面结合成为可能。 + +微应用对象通过资产包加载,需要暴露两个生命周期方法: +- mount(container: HTMLElement, props: any) + - 说明:微应用挂载到 container(dom 节点)的调用方法,会在渲染微应用时调用 +- unmout(container: HTMLElement, props: any) + - 说明:微应用从容器节点(container)卸载的调用方法,会在卸载微应用时调用 + +> 在微应用的场景下,可能会存在多个页面路由到同一个应用,应用可通过资产包加载,所以需要将对应的页面配置指向对应的微应用(资产包)对象。 + +**描述示例** + +```json +{ + "router": { + "baseName": "/", + "historyMode": "hash", + "routes": [ + { + "path": "home", + "page": "home" + }, + { + "page": "guide", + "page": "guide" + }, + { + "path": "/*", + "redirect": "notFound" + } + ] + }, + "pages": [ + { + "id": "home", + "treeId": "home", + "meta": { + "title": "首页" + } + }, + { + "id": "notFound", + "treeId": "notFound", + "meta": { + "title": "404页面" + } + }, + { + "id": "guide", + "packagId": "microApp" + } + ] +} + +// 资产包 +[ + { + "id": "microApp", + "package": "microApp", + "version": "1.23.0", + "urls": [ + "https://g.alicdn.com/code/lib/microApp.min.css", + "https://g.alicdn.com/code/lib/microApp.min.js" + ], + "library": "microApp" + }, +] +``` + + ## 3 应用描述 ### 3.1 文件目录 @@ -1320,9 +1524,78 @@ export const recordEvent = function(logkey, gmkey, gokey, reqMethod) { ### 3.2 应用级别 APIs > 下文中 `xxx` 代指任意 API #### 3.2.1 路由 Router API - - this.location.`xxx` - - this.history.`xxx` - - this.match.`xxx` + - this.location.`xxx` 「不推荐,推荐统一通过 this.router api」 + - this.history.`xxx` 「不推荐,推荐统一通过 this.router api」 + - this.match.`xxx` 「不推荐,推荐统一通过 this.router api」 + - this.router.`xxx` + +##### Router 结构说明 + +| API | 函数签名 | 说明 | +| -------------- | ---------------------------------------------------------- | -------------------------------------------------------------- | +| getCurrentRoute | () => RouteLocation | 获取当前解析后的路由信息,RouteLocation 结构详见下面说明 | +| push | (target: string \| Route) => void | 路由跳转方法,跳转到指定的路径或者 Route | +| replace | (target: string \| Route) => void | 路由跳转方法,与 `push` 的区别在于不会增加一条历史记录而是替换当前的历史记录 | +| beforeRouteLeave | (guard: (to: RouteLocation, from: RouteLocation) => boolean \| Route) => void | 路由跳转前的守卫方法,详见下面说明 | +| afterRouteChange | (fn: (to: RouteLocation, from: RouteLocation) => void) => void | 路由跳转后的钩子函数,会在每次路由改变后执行 | + +##### 3.2.1.1 RouteLocation(路由信息)结构说明 + +**RouteLocation** 是路由控制器匹配到对应的路由记录后进行解析产生的对象,它的结构如下: + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | 备注 | +| -------------- | ---------------------- | ------ | ------ | ------ | ------ | +| path | 当前解析后的路径 | String | - | - | 必填 | +| hash | 当前路径的 hash 值,以 # 开头 | String | - | - | 必填 | +| href | 当前的全部路径 | String | - | - | 必填 | +| params | 匹配到的路径参数 | Object | - | - | 必填 | +| query | 当前的路径 query 对象 | Object | - | - | 必填,代表当前地址的 search 属性的对象 | +| name | 匹配到的路由记录名 | String | - | - | 选填 | +| meta | 匹配到的路由记录元数据 | Object | - | - | 选填 | +| redirectedFrom | 原本指向向的路由记录 | Route | - | - | 选填,在重定向到当前地址之前,原先想访问的地址 | +| fullPath | 包括 search 和 hash 在内的完整地址 | String | - | - | 选填 | + + +##### beforeRouteLeave +通过 beforeRouteLeave 注册的路由守卫方法会在每次路由跳转前执行。该方法一般会在应用鉴权,路由重定向等场景下使用。 + +> `beforeRouteLeave` 只在 `router.push/replace` 的方法调用时生效。 + +传入守卫的入参为: +* to: 即将要进入的目标路由(RouteLocation) +* from: 当前导航正要离开的路由(RouteLocation) + +该守卫返回一个 `boolean` 或者路由对象来告知路由控制器接下来的行为。 +* 如果返回 `false`, 则停止跳转 +* 如果返回 `true`,则继续跳转 +* 如果返回路由对象,则重定向至对应的路由 + +**使用范例:** + +```json +{ + "componentsTree": [{ + "componentName": "Page", + "fileName": "Page1", + "props": {}, + "children": [{ + "componentName": "Div", + "props": {}, + "children": [{ + "componentName": "Button", + "props": { + "text": "跳转到首页", + "onClick": { + "type": "JSFunction", + "value": "function () { this.router.push('/home'); }" + } + }, + }] + }], + }] +} +``` + #### 3.2.2 应用级别的公共函数或第三方扩展 - this.utils.`xxx`