BeatlePro是一套轻量级前端框架,借助React、Redux实现应用界面构建流程。
特性
- 简单化Api,快速掌握开发技巧,只需掌握React框架。
- 轻量概念,React-like-Model 构建数据模型(state存储数据状态,setState变更数据状态)
- MVVM实现VM模块自动化,即自动化绑定数据和视图逻辑。
- 应用中间件,数据通信过程的设置中间件,方便应用接入外部扩展。
- 由简入繁,多应用嵌套构建复杂应用,方便管理应用之间的通用服务通信 以及 数据通信。
启动和打包
// 启动 honeypack start // 打包 honeypack build -c webpackbuildjs
BeatlePro-API
Class: BeatlePro
- BeatlePro支持多应用场景,每个应用都需要通过New BeatlePro来生成实例。
const app = options; app;
以下出现的 app
皆为 BeatlePro
的实例, 在初始化传入的配置options
:
属性 | 描述 | 默认 |
---|---|---|
name String |
应用实例名 | N/A |
store Object |
应用数据中心的初始化数据 | {} |
middlewares Array |
应用数据处理中间件,通过中间件可以变更数据结果 | [] |
ajax Object |
应用接口请求对象初始化依赖的配置项 | {} |
root DOM |
应用唯一挂载的DOM树节点 | document.body |
base String |
应用启动,路由访问的根路径 | / |
query Object |
设置路由全局参数 | N/A |
autoLoadModel Boolean |
是否自动加载数据模型,如果开启则加载assets/auto_models.js 文件 |
true |
autoLoadRoute Boolean |
是否自动加载路由,如果开启则加载assets/auto_routes.js 文件 |
false |
models Object︱Function︱Context |
需要注册的数据模型 | N/A |
routes Object︱Function︱Context |
需要注册的路由 | N/A |
routeType Boolean |
路由处理器类型,主要分为hash还是原生 | browserHistory , 参考:browserHistory 和 hashHistory |
subApp Boolean |
是否为子应用 | false |
应用实例app
有相应的方法来完成应用构建,包括注册数据模型
, 注册路由
, 应用启动
等。
BeatlePro.getApp(appName)
- return <
BeatlePro
> 返回指定的BeatlePro实例
多应用场景下通过选择指定应用实例,从而完成单个应用的构建。
Component { return <h5>Hello Worlld thispropslocationqueryappName!</h5> } // 创建应用A,输出Hello World A! const appA = name: 'appA' ... ; appA; appA; // 应用B,处处Hello Wolrd B! const appB = name: 'appB' ... ; appB; appB; // 通过指定应用名来获取应用A实例 BeatlePro;
BeatlePro.createModel(model, resource)
在BeatlePro中数据模型Model
是指一类数据的集合,一个数据模型包含了数据基础结构
, 改变数据的行为方法
以及跨数据模型的监听
。
resource是接口调用的封装对象,一般来说,我们会愿意把接口单独定义到业务逻辑之外的对象中。
- 来了解一下在BeatlePro中应用Model
// 1. 定义一个数据模型 const model = // 定义数据模型实例名(注意,以下通过实例名来获取到BeatlePro生成的model的实例 displayName: 'test' // 定义数据结构 state: value: 1 // 定义数据行为 actions: // model注册后,set会变成一个方法,出入的参数,会写到paylaod.arguments属性。 { // nextState是state的最新版本, set定义第一个参数值,赋值给value属性 nextStatevalue = payloadarguments0; return nextState; } // 2. 初始化BeatlePro应用 const app = name: 'main'; // 3. 注册model app; // 获取model实例 const modelInst = app // 打印输出 value: 1 console; // 调用行为,写入数据 modelInst; // 打印输出 value: 2 console; // 4. 定义组件,并挂在路由 Component { return <span>component props value :thispropstestvalue</span> } // 5. 把组件和数据模型进行绑定 const ConnectRoot = BeatlePro; // 路由响应时,组件输出 component props value :2 app; // 调用行为,写入数据 modelInst; // 组件自动更新,并输出 component props value :3 // 运行应用 app;
- 数据模型可以通过class来创建
// 1. 定义一个数据模型 BaseModel static displayName: 'test'; state = value: 1 { // this.setState(obj, ...args), 通过底部传入参数,通过payload.argumnets获取 return this; }
- model的数据行为异步时
// 1. 通过纯对象创建 const model = displayName: 'test' state: value: 1 actions: // set: callback 改为 set: {callback}, 异步行为包括数据预处理,都需要通过exec属性来返回。 set: // 通过exec返回的数据(获取promise,其接受的数据)。通过payload.data获取 { return { ; } } { nextStatevalue = payloaddata; return nextState; } // 2. 通过class创建 BaseModel static displayName: 'test'; state = value: 1 { return this; }
- 数据模型的异步行为通过接口获取数据
BaseModel static displayName: 'test'; state = value: 1 { return this; }
- 回到主题,createModel的目的就是抽象exec,独立维护在model之外
const resource = set: url: 'http://api.github.com' method: 'get' data: id: v // 以下是装饰器用法,也可以通过 Model = BeatlePro.createMode(resource)(Model); @BeatlePro BaseModel static displayName: 'test'; state = value: 1 { return this; // 更简洁的写法, 通过value对应的函数名来指定exec /** * return this.setState({ * value: function set(nextState, payload){ * return payload.data; * } * }) */ }
这样下来,所有的接口都单独定义在resource对象下,对于大的应用会存在很多resource。对于resource我们可以在业务之外单独做调试,这样服务分层的管理,代码更加健壮和清晰。
Model的使用下面API有更详细介绍
BeatlePro的其他静态属性
属性 | 描述 |
---|---|
Ajax | 接口调用Ajax类,可单独初始化ajax实例 |
Poller | 轮询调用Poller类 |
Link | 封装了react-router 的Link, 带上全局base和query |
ReduxSeed | 数据驱动机制可单独使用,不依赖BeatlePro,包含完整的数据模型以及Redux处理一整套机制 |
下面我们来看下BeatlePro实例app
有哪些方法和对象可以使用。
app.ajax
app
是有new BeatlePro
初始化的实例,在初始化同时时,内部还会初始化2个实例:ajax
和 seed
, 分别为Ajax的实例 和 ReduxSeed的实例。
ajax可以设置实例级别的事件监听,分别通过以下方法来设置
方法 | 参数类型 | 描述 |
---|---|---|
setHeader(headers) | headers Object |
设置headers 配置 |
beforeRequest(fn) | fn Function |
请求之前beforeRequest 的处理,此时可以更改接口配置或者更多 |
beforeResponse(fn) | fn Function |
接口结果预处理beforeResponse , |
afterResponse(fn) | fn Function |
接口结果后处理afterResponse |
set(name[, value]) | name String , value any |
前4个方法都可以通过set方法来设置,简化操作 |
const app = ; // 在请求之前,监听事件处理 appajax; appajax // 请求成功,并解析response数据成功后进入 appajax;
接口请求配置dataType用于声明如何解析接口数据
app.seed
seed实例是ReduxSeed实例,app.getStore()
实际上是通过seed实例中获取store对象。
app实例开放API
方法 | 参数类型 | 描述 |
---|---|---|
getStore() Object |
N/A | 获取redux状态容器 |
getRoutes() Array |
N/A | 获取react-router的路由配置 |
use(middleware) | middleware Function |
注册中间件,中间件是在处理处理过程中变更数据结构或者做一些必要的监控 |
getResolvePath(routeConfig) String |
routeConfig Object |
根据路由配置获取真实的路径 |
route(path[, component]) | path String︱Array︱Object︱Context , component ReactComponent |
只有一个参数,此时为字符串则查找路由配置,否则是批量注册路由配置;2个参数未显示注册单个路由配置 |
routesFactory(routes, option) | routes Array︱Object︱Context , option Object |
批量注册路由,可以传入option做更多处理 |
model(Model) | Model Object |
注册数据模型 |
connect(bindings, component[, context, flattern]) | bindings String︱Object︱Array , component ReactComponent , context Object , flattern Boolean |
设置视图, binding指定注入数据模型或者根据数据模型注入数据和方法 |
service(providers, isGlobal) | providers <Object|Function|Array> , isGlobal Boolean |
注册全局服务(通用js对象) |
observable(obj) | obj <Array|Promise|Observable> |
把数据转为观察序列 |
view(Selector, component, providers) | Selector Object , component: ReactComponent , providers: Array<Object|Function|Array> |
设置视图,并注入context |
run([rootDom, basePath]) | rootDom Object , basePath String |
启动应用 |
当app为BeatlePro的主应用时,可以通过BeatlePro.xxx直接调用app对应的方法。 所有app实例的开放api都可以通过BeatlePro进行访问
const mainApp = {}; const subApp = subApp: true; // BeatlePro.run 等同于mainApp.run, 相同的还有`use`, `model`等
在new BeatlePro的配置项options中有subApp属性来声明是否为子应用,否则就是主应用。 在BeatlePro支持多应用的场景下,主应用必须只为一个,其他均为子应用,否则将会出现预想不到的问题。
app.getStore()
在new BeatlePro产生实例app
时,应用内部会创建一个单一的数据共享对象,后面统一称之为状态容器store
, 如果你熟悉Redux
,当前store
也可以在Redux
技术体系下正常工作。
const app = ; const store = app; store;
app.model(model)
- model <Model>
应用中注入数据模型Model,注册功能后,数据模型的将交给store
进行托管。
// 此时user还未注册到app中,所以将没有任何内容被绑定 app; app; // 此时绑定有效,user数据模型和组件建立了绑定,后续一旦这个user发生数据变更时,组件将自动调用render来更新视图。 app;
app.connect(modelList, component, flattern)
- modelList <
String|Object|Array
> 指定需要绑定的数据模型实例名 - component <
ReactComponent
> 指定组件来绑定 - flattern <
boolean
> 是否平铺属性 - return <
ReactComponent
> 返回新的React组件
; ; const app = ; const Model = displayName: 'user' store: nickname: 'anonymous' actions: login: // 同步的action,直接从arguments中取值,arguments = ['Trump'] { nextStorenickname = payloadarguments0; } Component { thispropsuser; } { return 'hello ' + thispropsusernickname; } ; app; const component = app; app; app; // 访问/, console输出为:hello Trump!
app.service(providers, isGlobal)
- providers <
Function|Object|Array
> 注入的全局的服务JS类 - isGlobal <
Boolean
> 是否是全局的(跨所有应用)
const app = name: 'main'; { return v: 1 }; // B依赖于A,通过数组最后一位是服务定义,其他项为依赖的服务名 const B = 'a' { return v: av + 1 }; // B是其中的一种依赖方式,C是另外一种依赖方式,通过contextTypes属性声明 static contextTypes: b: ReactPropTypesobjectisRequired { return thiscontextbv + 1; } { return cv + 1; } // D是另外一种依赖方式,通过$inject声明,是不是很熟悉,ng 1.x中服务依赖也是如此 D$inject = 'c'; // 注册服务A,通过displayName来指定服务名 AdisplayName = 'a'; const a = app; // 输出 1 console; // 注册服务, 通过key来指定服务实例名称 app; // 通过名称获取服务实例 const b = app; // 输出2, 因为b依赖于a + 1, B的依赖会从全局服务中找 console; const d = app; // 输出4, 因为d依赖于c + 1, c依赖于b + 1, b依赖于a + 1 console;
app.observable(obj)
- obj <
Array|Promise|Observable
> 指定需要转为序列的数据 - return <
Observable
> 返回可订阅序列
const stream = app;stream;// 输出 1, 2, 3 const stream = app;stream;// 输出 123 const promise = { ;};// 针对react特殊定义,可以输出异步组件ReactDOM;
Observable序列是rxjs中的概念,适用于把异步数据按时间轴转换为有顺序的序列数据,方便操作。
app.view(Selector, component, providers)
- Selector <
Object
> 指定需要绑定的数据选择器 - component <
ReactComponent
> 指定组件来绑定 - providers <
Array<Object|Function|Array>
> 注入其他的服务,使得组件通过this.context可以访问到。 - return <
ReactComponent
> 返回新的React组件
BaseModel state = profile: name: 'Guest' { return this } BaseSelector // inputs相当于connect的 stateMergeToProps, 相对应的outputs等同于connect的 actionMergeToProps { return { return profile: stateuserprofile } } // 这是数据选择器的钩子函数,在组件初始化完成时自动触发。 { this; } Component static propTypes = profile: ReactProptypesobject static contextTypes = test: ReactProptypesobject { // 组件会先输出 Hello Guest!,接口调用成功后,更新为 Hello baqian return <div>thiscontexttesttitle thispropsprofilelogin!</div> } // 和BeatleProp.connect不同,connect绑定数据模型,view绑定数据选择器 Root = BeatleProp;
数据选择器是一个新的概念,在复杂的场景,一个组件往往会调用多个model,通过数据选择器来统一管理model,提高代码可读性
- BeatleProp.crud
这是action数据处理的模板,以上的UserModel通过crud重新处理如下:
BaseModel state = profile: name: 'Guest' { return this }
crud的全部接口
crud = item: {} itemsEntry: data: loading: false total: 0 pageSize: 10 page: 1 get // 获取数据 create // 新增 update // 更新 query // 分页形式 reset // 恢复为初始化数据
举个例子,通过crud创建一个UserModel,能节省大量代码
static displayName = 'user'; state = user: cruditem usersEntry: cruditemsEntry // 必须有id属性,用来识别指定数据项,从而判断是更新还是创建 id = 'id'; { return this; } { return this; } { return this; } { return this; } { return this; }
app.route([path, routes])
- path <
String
>, 当存在path时,则是配置单个路由,此时routes应该为React组件或者BeatlePro子应用。 - routes <
ReactComponent|BeatlePro|ReactRouter
>, 不存在path时基于ReactRouter的路由的配置.
- app.route(routes)
// routes为标准的react-router的路由配置项 app
- app.route(path, component)
app; // 这种形式,如果想要配置childRoutes RootComponentrouteOptions = childRoues: path: 'profile' component: ProfileComponent app;
- app.route(path, subApp) 把子应用挂在主父级应用下,子应用的路由会继承下来,但需要追加根路径来访问。
const subApp = subApp: true; subApp; subApp; app; app; // 访问/subApp/ 会触达subAppRootComponent视图 // 访问/subApp/profile 会触达subAppProfileComponent视图
app.run([root, base])
- root <
DOM
>, app最终需要挂载到真实的DOM节点下. - base <
string
>, app访问的路由,统一加上跟路由路径.
const app = ; app; app; app; // 此时访问/不能匹配任何路由 // 访问/beatlePro/ 会触达RootComponent视图 // 访问/beatlePro/profile 会触达ProfileComponent视图
Model
Model数据模型是一类数据的集合,包含了数据的初始化结构,以及改变这些数据的行为方法。
描述一个Model对象,需要具备以下数据结构:
属性 | 描述 | 默认值 |
---|---|---|
displayName | 实例名 | N/A |
store | 数据基础结构 | {} |
actions | 改变数据的行为方法 | N/A |
subscriptions | 跨数据模型的行为监听 | N/A |
// 以React的propTypes概念来描述属性类型,方便我们来描述每个属性的类型 const propTypes = ReactPropTypes; const modelShape = displayName: propTypesstring store: propTypesobjectisRequired actions: propTypesobject subscriptions: propTypesobject // 在actions中每个action的结构,分2种情况 // 异步action const action = exec: propTypes callback: propTypes // 同步action const action = callback: propTypesfunc // subscriptions每个subscription必须为方法 const subscriptions = `//: (nextStore, playload) => { } }
符合以上数据结构的Model可以通过app.model(Model)
注册到应用中。
何时使用
BeatlePro.createModel(model, resource)
, 当你异步的action中exec需要单独维护到model外部时,通过Bealte.createModel组合进来,生成最终的Model
Model行为action的配置
属性 | 参数类型 | 描述 |
---|---|---|
exec | Object/Function |
异步行为的触发条件,BeatlePro内部通过exec来识别异步行为,当exec为接口配置,会转为一个接口调用函数,如果是函数则不用做变动 |
callback | Object/Function |
行为触发成功后进入,在同步行为时,callback只能为函数,异步行为时callback一般来说是对象,有3个回调函数,start , success 和 error |
reducer | Object/Function |
同上callback |
subscriptions | Object |
跨数据模型监听行为,从而变更自身数据 |
externalReducers | Object |
同上subscriptions |
- 行为action调用成功的回调函数
行为调用的处理逻辑
- 行为方法触发时传入的参数会放到payload.arguments中
- 判断行为是否存在
exec
属性,则会当做异步行为进行调用 - 触发行为时,会先执行
start
回调, - 判断exec为函数时,执行函数返回非promise值,会直接进入到
success
回调,否则在promise的接收值时进入到success
回调,在拒绝值时进入到error
回调 - 如果exec为接口配置,则通过应用内部的ajax实例来发起接口调用,在接口成功并接收值时进入到
success
回调,在拒绝值时进入到error
回调 - 同步行为时直接进入到callback回调
{ // nextStore是当前model可变的数据,我们知道model的基础数据是在store中定义,每次更新后会存到内存中,并不会改变store属性 // 所以每次行为调用后的回调nextStore拿到可变的数据 // payload是数据装载对象,最常用的,arguments是行为调用时传入的参数,而data属性是异步行为调用时接收的数据。 }
- 数据装在对象payload的结构
属性 | 描述 |
---|---|
type | 当前行为处理状态,不同行为状态会进入到不同的回调中 |
store | 当前model的基础数据 |
arguments | 行为调用时传入的参数 |
data | 异步行为调用后,接收的数据 |
message | 当异步行为调用失败后,会存在错误信息 |
- 基于异步action调用以及跨数据模型监听行为的实现举个例子:
const UserModel = displayName: 'user' store: profile: pending: true nickname: 'anonymous' actions: login: callback: { // 每次请求之前都重置为初始化值,通过payload.store可以获取到初始化值 nextStoreprofile = payloadstore; } { // 获取成功后,接口返回值通过playload.data可以获取到 nextStoreprofile = pending: false nickname: payloaddatanickname ; } ; const UserResource = login: url: '/login' method: 'GET' const AccountModel = dispayName: 'account' store: nickname: '' subscriptions: // nextStore为当前model的可变数据对象,user_login_payload是user实例的login行为调用成功后的payload { nextStorenickname = user_login_payloaddatanickname; } // 你会发现,UserResource存在相同行为名称的属性,值为接口调用配置。通过BeatlePro.createModel会组装到UserModel中 app; app; // 当UserModel的login行为触发调用,成功后,AccountModel的监听也会被触发,从而更新AccountModel的数据
Resource
Resource是接口配置对象,结合BeatlePro.createModel来使用
BeatlePro.createModel(model, resource)
时其内部将做如下处理
- 遍历resource对象,拿到每个属性和值
- 在model.actions中找到对应属性的行为,把值赋给行为的exec对象,找不到行为则,则丢弃掉
const userModel = ... actions: login: ... ; // resource/user.jsconst userResource = login: url: '/login' method: 'GET' params: username: 'default username' getUserList: url: '/user/list' method: 'GET' params: pageSize: 10 pageNo: 1 ; // getUserList不会生成行为,只有login会组合到login行为中BeatlePro;
Class: ReduxSeed
- 通过new ReduxSeed产生seed实例
; const seed = ...;
- new ReduxSeed传入options配置项:
属性 | 描述 | 默认 |
---|---|---|
name String |
ReduxSeed支持多实例,初始化一个seed实例需要指定实例名称 | main |
ajax Object |
ajax实例 | N/A |
initialState Object |
store的基础结构 | {} |
middlewares Array |
应用数据处理中间件,通过中间件可以变更数据结果 | [] |
Models Object |
注册多个数据模型 | {} |
ReduxSeed静态属性
名称 | 参数类型 | 描述 |
---|---|---|
createModel | model Object , resource Object |
组合resource到model中,等同于BeatlePro.createModel |
getRedux | name String |
获取指定的seed实例 |
seed实例方法
名称 | 参数类型 | 描述 |
---|---|---|
reducerBuilder | model Object , resource Object |
组合resource到model中,等同于BeatlePro.createModel |
register | model Object , resource Object |
注册一个model到seed实例 |
getActions | modelName String |
获取指定的seed实例下的model的行为,为空时获取所有行为 |
Class: Ajax
- 通过new Ajax产生ajax实例,传入的options配置项,设置实例级的全局配置:
名称 | 描述 |
---|---|
headers | 全局的Header配置, 默认取值window.ajaxHeader |
delimeter | 请求url默认支持插值替换,delimeter 是插值变量的语法 |
normalize | 请求url插值替换,是否都走data属性, 默认为false |
beforeRequest(ajaxOptions) | 请求之前的钩子函数 |
beforeResponse(response, ajaxOptions, xhr) | 请求成功后处理response对象的钩子函数 |
afterResponse(result, ajaxOptions, xhr) | 请求成功后处理接口结果数据的钩子函数 |
origin | 配置请求地址前缀 |
- Ajax的全局配置分为2种:全局(所有实例有效) 和 实例级,支持的值如上
; Ajaxheaders = csrfToken: '...' Ajaxnormalize = false; const ajax = normalize: true ; // ajax发起请求时,normalize为`true`,而headers值为`{ csrfToken: '...' }` ajax; ajax; // 此时再发请求,normalize为`true`,headers为`{}` ajax
实例级设置可以参考ajax实例设置实例级别的全局监听。
Ajax.request(ajaxOptions)
Ajax静态方法,其内部会初始化一个ajax实例,并调用ajax.request来执行
ajax实例方法
名称 | 参数类型 | 描述 |
---|---|---|
request | options Object |
接口请求调用,所有其他方式的请求最终都会走request来执行 |
get | path String , data Object/null , options Object/Function , dataType String/Function |
get请求 |
post | path String , data Object/null , options Object/Function , dataType String/Function |
post请求 |
put | path String , data Object/null , options Object/Function , dataType String/Function |
put请求 |
delete | path String , data Object/null , options Object/Function , dataType String/Function |
delete请求 |
patch | path String , data Object/null , options Object/Function , dataType String/Function |
patch请求 |
ajax.request(options)
- options <
Object
> 接口请求配置 - return <
Promise|null
> 配置中有callback则不会返回内容,否则会返回调用的promise
- 常用接口配置
属性 | 参数类型 | 描述 |
---|---|---|
url | String |
请求地址 |
method | String |
请求方法 |
headers | Object |
请求头部 |
mode | String |
请求模式,参考 cors , no-cors , same-origin , 默认no-cors |
credentials | String |
请求凭证, 参考omit , same-origin , include , 有凭证才带cookie,否则不带cookie |
cache | String |
缓存模式,参考 default , reload , no-cache , 默认default |
callback | Function |
回调处理函数,当存在callback时不会返回promise实例 |
dataType | String |
接口返回结果对数据解析处理基于dataType类型来决定,默认为json解析 |
- dataType解析数据类型
取值 | 描述 |
---|---|
arrayBuffer | 解析为ArrayBuffer 的promise对象 |
blob | 解析为Blob 的promise对象, URL.createObjectURL(Blob) 转为base64 |
formData | 解析为FormData 的promise对象 |
json | 解析为Json 的promise对象 |
text | 解析为USVString 的promise对象 |
ajax.get(path[, data, options, dataType])
- path <
String
> 请求地址 - data <
Object|null
> 请求参数 - options <
Object|Function
> 当为函数式,则是callback回调,否则为请求配置信息 - dataType <
String|Function
> 请求数据进行数据解析类型,默认是json解析, 当dataType为函数时,则是callback回调,此时options必须为请求配置信息 - return <
Promise|null
> 配置中有callback则不会返回内容,否则会返回调用的promise
其他接口方法形式一致,包括
post
、delete
、put
和patch
Class: Poller
通过new Poller产生poller实例,传入配置项options:
属性 | 描述 | 默认 |
---|---|---|
delay Number |
每次轮询需要等待是时长 | 5000 |
smart Boolean |
智能识别,当某个请求超过等待时长,会等待请求结束后才会轮询下个动作 | false |
action Function |
每个轮询动作触发时,调用action函数 | N/A |
catchError Function |
轮询中每个动作调用失败时都会进入到错误回调 | N/A |
; const poller = { // 每个5秒会轮询调用改函数 return BeatleProAjax; } ; // 当subscribe订阅或者start方法调用时,轮询开始工作。 poller;
poller实例方法
方法 | 参数类型 | 描述 |
---|---|---|
then | success Function , error Function |
注册回调队列,每次轮询产生结果时触发 |
subscribe | watcher Function |
开始订阅,同上注册回调队列,并且启动轮询 |
unsubscribe | N/A | 取消订阅,并关闭轮询 |
remove | N/A | 同上 |
start | N/A | 开始轮询 |
stop | N/A | 停止轮询 |
tick | N/A | 等当前产生结果后跳到下一个轮询 |
Class: Link
是React组件,封装了React Router中Link组件。用法同Link组件一致,所做的事情就是当app实例中设置了路由的统一前缀以及全局的query参数, 通过Link跳转时会自动带上。
const app = base: '/example' // 设置了路由前缀 query: debug: true // 设置了全局的query ; // 访问/example/进来到此路由 app; app;