regularjs / regular

regularjs: a living template engine that helps us to create data-driven component.
http://regularjs.github.io/
MIT License
1.06k stars 149 forks source link

Not only a component library now. combine stateman to create SPA use Regularjs #23

Closed leeluolee closed 9 years ago

leeluolee commented 9 years ago

I have completed the work to creating Single Page Application use Regularjs, and have test it in production , thanks for my patient colleague :).

The routing function is supported by stateman which is a nested state-based routing library.

final router.js looks like:

  .state("app", Application, "")
    .state('app.knowledge', Knowledge)
    .state('app.knowledge.list', KnowledgeList, '')
  .state('app.knowledge.manage', KnowledgeManage,  "manage/:type/:id")
  .state('app.question', Question)
    .state('app.question.list', QuestionList, 'list/:type')
    .state('app.question.manage', QuestionManage, "manage/:type/:method/:id")
  .state('app.testmanagement', TestManagement)
    .state('app.testmanagement.list', TestManagementList,'')
    .state('app.testmanagement.manage', TestManage, "manage/:type/:id")
    .state('app.testmanagement.rank', TestManageableRank,  "rank/:id")
    .state('app.testmanagement.profile', TestManagementProfile, "profile/:tid/:uid" )
  .state('app.preview', TestManagementPreview, "preview/:type/:id" )
  .state('app.group', Group)
    .state('app.group.list', GroupList, '')
    .state('app.group.manage', GroupManage, 'manage/:type/:id')
    .state('app.group.members', GroupMembers, 'members/:id/:type')
    .state('app.group.member', GroupMember, 'member/:id/:type')
  .state('app.judge', Judge)
  .state('app.judge.list', JudgeList, '')
  .state('app.judge.manage', JudgeManage, 'manage/:type/:id')
  .state('app.testlist', TestList)

  // test level1
  .state('app.test', Test )
    .state('app.test.list', TestList, '')
    .state('app.test.rank', TestRank, ':id/rank')
    .state('app.test.view', TestView, ':id/view')
  .state('app.exam', TestExam, '/test/:id')
    // choice or judge.
    .state('app.exam.judge', ExamSimple)
    .state('app.exam.choice', ExamSimple)
    .state('app.exam.blank', ExamSimple)
    .state('app.exam.list', ExamList, ":type(coding|complement)")
    // coding complement 
    .state('app.exam.complex', ExamComplex, ':type(coding|complement)/:qid'  )
    .state('app.exam.complex.detail', ExamComplexDetail, '')  //question id
    .state('app.exam.complex.submit', ExamComplexSubmit)
    // need preview or &preview or sid  result?sid&preview
    .state('app.exam.complex.result', ExamComplexResult)
 .....

The code is from the application that still in developing. router is much bigger now, but works fine.

the second param passed to state is standard Regularjs Component, the only thing you must do is to mark a view tag in each parent state.

take app.exam for example, its template need create a ref named view

...
<div>
  <div class="m-emn" ref=view></div>
</div>
...

then the child state app.exam.judge will automately inject its template to the ref view and so on

leeluolee commented 9 years ago

I will publish the regular-router based on stateman soon. but before it, I need to updating the document now.

meanwhile , the default TAG will be change to {}

xiongxin commented 9 years ago

还是改了模板标签呀。。。优先出中文文档吧 - -!

ginus commented 9 years ago

还可以用json来配置状态机 .NestedState({ name: 'app', component: 'Application', url:'/' children: [ { name: 'knowledge', component: 'knowledge', url:'/' children: [ { name: 'list', component: 'KnowledgeList', url:'/' } ] } ] } 原本api .state(name,component,urlHash) 当然如果规约了则更简单,只要一个url和状态之间的map。 状态名使用“.”语法,组件使用“_”语法,驼峰不便于阅读。 比如状态app.knowledge对应的组件就是app_knowledge 这样的坏处是不利于组件复用,所以可以作为默认值,需要复用的手动指定,不需要的则使用这个规则对应。

leeluolee commented 9 years ago

@ginus 和我目前思考的问题可能有点接近? Good suggestion. 已经用这个做了一大一小两个单页系统,如果那个DEMO也算,那就是三个. 目前其实最想做是针对爬虫的SEO优化。 后期再做到对所有请求的first page的服务端渲染.

这个系统其实从设计到使用花了不到一周事件(包括stateman的第一版), 发现还是有些问题。

如果按目前的样子是一大段的内部DSL的脚本调用,很难去分别处理Server rendering 和 Client Rendering. 可能最终还是会发展成你提到的这种方式, 用配置文件的方式去描述Application. 用字符串去描述具体的组件。

ginus commented 9 years ago

1、优秀的框架,让使用者在开发阶段主要是写配置参数,这样能适应多变的需求,并且保证执行的可靠性。 2、react使用字符串作为参数,描述页面,利于服务器端输出第一页。angular使用dom则不利于,原来想过一个方案就是用phontomJs,在服务器端渲染了第一页。现在也有人使用react实现了同构。 3、在出1.0.0版本之前一定要慢工出细活。把周边做好,比如编辑器的支持,文档等等,才能建立一个健康的成长环境。 4、写框架尽量使用livescript或者coffeescript不要使用原生js,避免不必要的填坑工作。且便于阅读代码。

ginus commented 9 years ago

刚刚阅读了部分源码,觉得必须赞一个,尽管设计之初考虑不充分,必定是孵化阶段。 值得借鉴的一些框架提供给你: 1、YII,php框架追求易用高效,约定多,开发效率重于执行效率,当然也挺快的,因为作者使用了轻量模式、修饰模式等使得框架本身结构很优良,oop的功底很好。国人主导适合中国程序员的思维方式。1.0版结合jquery ui,2.0版结合bootstrap。做到了一门语言全部完成整个工作流。 2、phpPhalcon这个框架作者是写c的所以直接写了个c扩展的框架,执行效率绝对是顶级的,在没有换到nodejs之前我最喜欢用的框架。一样的ioc,di,轻量,修饰等等编程模式的恰当运用。结构优良,很值得借鉴,框架本身灵活性相当高。

介绍两个php框架是因为在服务器端重度渲染的时代,他们做的确实好,可能是js未来的主要借鉴。

关于js 的框架,除了主流框架(特别是您性能比较页面提到的那些),我也建议几个供参考: 1、国内的avalon其实还是不错的,作者是个天才,就是写代码有些意识流,作者是希望“出奇制胜”。主要借鉴ko的vm,ng的directive。路由,动画很基本。 2、riotjs特点是小巧,5k的代码。重视执行效率高于开发效率,其实它在提醒我们高性能框架得区分开发时和运行时,这在c或许都是老话题了,随着硬件提升必定会越来越宽松,大方向是脚本语言提供语法糖之类的提高了代码开发体验,脚本执行器注重运行时优化,所以高效框架在主导上也应该借鉴这样的经验,core是运行时的,上层裹糖便于开发,然后就是有工具介于开发和执行之间,一般是转换器,去糖留干货,微软是IL,react就是vm,其实这个就是轻量化思想,dom的特性抽象成一个对象,应该说未来的框架都是分化的更细致,对于常用的功能点都是功能过载的,对于稍复杂或更复杂的功能点则是加速的。所以di,ioc这样的思想很重要,我记得thinkphp当时的努力就是静态配置内核。效率上去了,开发不便利了,对于js,好的做法是开发语法糖,程序收集依赖信息,自己编译内核js给给客户端。

ps,构建生态圈比构建一个框架重要。所以我比较欣赏angular的扩展html DOM,而并非jquery的控制,UI库中bootstrap也是组件的思想,但是它捆绑html的DOM结构,不按照这个结构来书写,你就得不到想要的组件,相对我一直看好的semantic-ui则是有些angular的味道,扩展而不是控制。控制往往能很快构建起生态圈,人性的缘故吧,但扩展的模式往往能走的更远。所以看这个框架怎么定位了,什么样的团队,在什么样的场景中使用这应该是头顶上最大的命题。

leeluolee commented 9 years ago

感谢 @ginus,源码其实相对刚发布有点脏了,后期会重构并统一加上注释方便别人看懂。 生态圈的重要性其实大家都清楚,后期可能还是会短期内专注在国内多放点中文教程。

ginus commented 9 years ago

angular去年关注增长379%,应该是国人贡献的,其实这个项目已经好多年了,我也是比较早的使用者,按照国情,糖糖第一,执行速度第二,这个你明白的。

leeluolee commented 9 years ago

基本稳定与生产环境, 移步 regular/regular-state. 文档暂定