# Raab-js **Repository Path**: jcinedc/raab-js ## Basic Information - **Project Name**: Raab-js - **Description**: 一个简单的前端响应式框架实现 - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-07-14 - **Last Updated**: 2023-08-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Raab-js **简单的前端响应式框架实现(我更愿意称之为`伪响应式`,因为操作响应数据需要使用特定暴露出的api进行,而不是传统意义上直接操作数据,不过这样做的好处是可以更加精准且减少了代理数据的额外开销)** 另外RaabJS内置了路由管理,可以方便的开发单页面应用 ### 安装 ```shell npm install raab-js ``` ### 快速实践 ```typescript // main.ts import { App, creatApp, RouteNextFunctionType, RouteType } from 'raab-js' import MainPage from './mainPage' class app extends App { handleRoute(): RouteType[] { return [ { path: '/', page: new MainPage }, ] } RouteMiddle(to: string, from: string, next: RouteNextFunctionType): void { next() } } creatApp(app) // mainPage.ts import { BasePage, c, cVal } from 'raab-js' class MainPage extends BasePage { context = rVal('Hello, World!') setup() { return ( c('h1', {$text: this.context.bindPath(), style: 'color: red;'}) ) } enter() { return true } leave() { return true } } export default MainPage ``` ## 文档 **在RaabJS里,所有html元素需要被封装成组件和页面,页面可以包含许多组件,且每一个页面需要有一个路由与其对应。** ### 响应式 RaabJS响应式支持单一数据与数组数据,且数组数据依赖于单一数据 + rVal() 单一数据 rVal函数,需要传入相应数据,并支持泛型,与vue的ref相似的是,rVal读取与赋值时需要访问.value属性,另外rVal绑定元素需要调用bindPath方法,如: ```typescript const text = rVal(true) // 读取 text.value // 赋值 text.value = false // 绑定元素 c('div', {$text: text.bindPath()}) ``` + rList() 数组数据 rList函数,需要传入相应数组,支持泛型,且数组中的响应数据需要包裹rVal函数,另外绑定元素时需要调用bindPath方法并传入数据路径,如: ```typescript const list = rList([ {text1: rVal('这是第一个数据')}, {text2: rVal('这是第二个数据')}, {text3: rVal('这是第三个数据')}, ]) // 对应 这是第一个数据 c('div', {$text: list.bindPath('0/text1')}) // 对应 这是第二个数据 c('div', {$text: list.bindPath('1/text2')}) // 对应 这是第三个数据 c('div', {$text: list.bindPath('2/text3')} ``` + rList具体操作数组方法如下: + `forEach(fn: rListForEachFunctionType): void` 循环数组 + `append(list: T[]): void` 追加数组,且需要注意的是必须传入数组而不是单一数据 + `insert(index: number, val: T): void` 插入数组,index指定下标,val数据 + `delete(index: number): void` 删除数据,index指定下标 + `setVal(path: string, val: T): void` 设置数据,path为数据路径,val数据 + `getVal(path: string): any` 获取指定路径数据 ### 模板 用于构建html元素,RaabJS中为c,cFor方法,其中c方法接收三个参数为元素名称,元素属性,以及子元素,如: ```typescript c('div', {}, [ c('h1', {$text: 'test'}), ]) ``` 其中带$的参数为特殊属性,在函数执行时会进行特殊处理,一般用作事件绑定 + $text:元素文本 + $click:绑定点击事件 ......... cFor方法用于循环创建多个元素,其接收两个参数为响应式数组(类型为rListObject,且需要响应的数据必须包裹rVal方法),回调函数,函数会传入index为数组下标已方便绑定数据,如: ```typescript const list = rList([ {c: rVal('123')}, {c: rVal('456')}, {c: rVal('789')}, {c: rVal('012')}, ]) c('div', {}, cFor(list, index => { return ( c('div', {}, [ c('div', {$text: list.bindPath(`${index}/c`)}), c('button', {$text: 'delete', $click: (e, i)=>list.delete(i)}) ]) ) })) ``` **需要注意的是,回调函数的结果需要进行返回,另外在cFor内部绑定事件函数会被传入两个参数反别是Event与index,其中index为绑定的对应数组下标...** ### Init 首先,启动一个Raab app需要创建类并继承App基类,实现handleRoute方法与RouteMiddle方法,其中handleRoute需要返回RouteType[]类型结构,具体信息如下 ```typescript type RouteType = { path: string // 路由路径(支持动态路由,需要在路由参数名前加:,如:id,匹配到后会在页面的enter方法传入相关数据) page: BasePage // 页面类实例 children?: RouteType[] // 子路由信息 } ``` RouteMiddle路由中间件控制路由转跳,传入三个参数`to`路由去向,`from`路由来自,`next`中间方法,next方法必须放置在函数内,否则无法执行路由转跳,且next支持重定向,需要传入指定路由如: ```typescript next('/test') ``` **另外关于子路由显示的问题,需要在父路由页面引入Route类并新建实例充当容器以此来展示子路由,如:** ```typescript import { BasePage, c, Route, router } from 'raab-js' // router为路由方法,其中changeRoute改变路由不添加history历史,toRoute为前往目标路由并添加历史 class MainPage extends BasePage { setup() { return ( c('div', {}, [ c('div', {style: 'border: red solid 1px'}, [ // 展示子路由信息 new Route, ]), c('button', {$text: 'AAA', $click: ()=>router.changeRoute('/aaa')}), c('button', {$text: 'BBB', $click: ()=>router.changeRoute('/bbb')}), ]) ) } enter() { return true } leave() { return true } } export default MainPage ``` ### 页面 书写页面需要创建类并继承BasePage基类,并实现setup(),enter(),leave()方法,其中setup返回html模板,需要使用c或cFor方法,enter与leave为页面钩子函数,是抽象方法所有必须实现,一般enter会传入页面进入后的相关参数,且需要返回布尔类型或者字符串,true为允许进入或离开此页面,反之亦然,也可以进行重定向如: ```typescript enter(p: any) { return '/test' } ``` ### 组件 书写组件需要创建类并继承BaseComponent基类,并实现setup(),Created(),Destroy()方法,其中Created(),Destroy()为组件生命周期钩子函数,Created为组件被挂载到页面后,Destroy为组件将卸载时(由于目前元素被创建在页面后只实现了隐藏显示并不会真正卸载出dom树,所有Destroy方法暂时无效) ```typescript import { BaseComponent, c } from 'raab-js' class Com extends BaseComponent { setup() { return ( c('h1', {$text: 'Hello, Rab!!!', style: 'color: red;'}) ) } constructor() { super() } Created() { } Destroy() { } } export default Com ```