[关闭]
@winpzs 2015-01-30T03:16:18.000000Z 字数 17166 阅读 1463

bingoJS使用说明

JS前端开发: bingoJS
原码github:https://github.com/winpzs/bingoJS/tree/master
dome github:https://github.com/winpzs/bingoJS/tree/gh-pages
dome:http://winpzs.github.io/bingoJS/mvc/index.html

bingJS:下载


1、关于bingoJS

bingoJS是一个前端MVC开发框架,对JS前端开发、调试、维护、重构进一步规范。 框架可以简单用双向绑定的手段把JS与html分离,进行前端MV方式;并进一步提供service和controll把JS方面分离成MC二层,再细分成前端MVC模式开发;现实资源(模板、JS)按需加载,从而不需要对JS资源的压缩与合并;改变前端开发从jQuery面向Dom操作为主到面向业务(数据)开发为主,并以MVC分工以减少开发、迭代、维护等成本.

1.1、双向绑定(数据绑定)

不可否认AngularJS是在双向绑定方面做非常出色的,特别是底层注入方面,和绑定机制等, 但我并不认为它是一个完整的开发框架, 只能说它是一种揭示了一种新的应用组织与开发方式。之前试过用它集成按需加载等,都非常痛苦的事, 最终只能放弃, 不明白它既然提供MVC模式开发, 没有考虑MVC模式下前端开发处理业务会细化很多,前端开发任务会变行重要起来, 不提供按需加载。在之前公司有个团队分享用AngularJS开发了一个小项目,把代码打包后单个JS就5M以上。最后在处理集成方面还是有点过重(多),要学习的知识点非常多,就算一个有经验都一时难以接受并用于开发。bingoJS将采纳几点核心机制(底层注入,标签,过滤器),将学习成本尽可能降低,并与MVC简单提供一种基础开发模式,过多的事不在基础做。

1.2、按需加载

无论是CMD还是AMD始初只是为了解决javascript平行运行提供模块管理和一定的动态加载能力,正如我当初所认为一样它们的规范会对以后前端业务越来越重变得非常辛苦,而且碎片化严重,并与其它库难以磨合。因此走了自己一套加载机制,javascript是自由语言, 就应该自由。所以提供一种最单纯加载机制,就是只负责加载, 因此是兼容所有现有的JS库, 对打包最低限度设置即可,但不排除以后对版本进行管理。

1.3、提供MVC开发模式

前端MVC是处理业务逻辑比较重的系统(内部系统)的一种开发模式。前后端分离开发(rest ful+前端), 必为带来rest接口细化(各种基础数据接口),前端会处理大量数据业务(过滤,组装等),这里前端MVC开发模式会带来很好分工管理, 无论在前后分离或是与dom分分离, 还是对迭代和后期维护。
还有一个点非常重要,就是对开发模式规范起来,如果有开发经验会发现后端业务无论是多复杂总能交付别人继续开发或维护,但前端一直都很难(业务重时),表面是业务重,但核心问题是之前前端开发没有统一的开发模式或现有的开发模式不利交付出去(如jQuery)

MVC开发模式大概分工:
M层:数据业务层,主要负责与后端数据互交, 提供常用方法,处理常用数据(过滤,组装);
C层:主要是对V层一一对应, 根据V层显示处理相应的数据
V层:主要处理html以双向绑定语法,跟C层数据连接

1.4、兼容性

在JS方面可以说完全兼容到IE6;在dom管理方除了核心编译部分用了原生外,其它都几乎依赖jQuery写的,所以取决于jQuery版本的兼容;


2、开始bingoJS

2.1、例子代码

  1. <!DOCTYPE html>
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title></title>
  6. </head>
  7. <body>
  8. <!--通过指令bg-controller与control连接-->
  9. <div bg-controller="control">
  10. <!--通过指令bg-text绑定hello变量-->
  11. <p bg-text="hello"></p>
  12. <!--通过标签绑定hello变量-->
  13. <p>tag: {{hello}}</p>
  14. <!--通过指令bg-click绑定事件-->
  15. <button bg-click="clickMe">点击我</button>
  16. </div>
  17. <!--启动bingoJS需用依赖jQuery-->
  18. <script src="scripts/jquery-1.8.1.min.js"></script>
  19. <!--引入bingoJS会自动启动-->
  20. <script src="scripts/bingo.js"></script>
  21. <script type="text/javascript">
  22. //定义contoller
  23. var control = function ($view) {
  24. //定义view的hello变量, 并设置值
  25. $view.hello = 'hello world!';
  26. $view.clickMe = function () {
  27. //点击, 改变变量hello内容
  28. $view.hello = 'hello world! click Me on: ' + new Date().toString();
  29. };
  30. };
  31. </script>
  32. </body>
  33. </html>

运行效果

2.2、例子说明

从上面的代码中,我们看到在通常的 HTML 代码当中,引入了一些标记,这些就是 bg 的模板机制,它不光完成数据渲染的工作,还实现了数据绑定的功能。

同时,在 HTML 中的本身的 DOM 层级结构,被 bg 利用起来,直接作为它的内部机制中,上下文结构的判断依据。比如例子中 p 是 div 的子节点,那么 p 中的那些模板标记就是在 div 的 Ctrl 的作用范围之内。

其它的,也同样写一些 js 代码,里面重要的是作一些数据的操作,事件的绑定定义等。这样,数据的变化就会和页面中的 DOM 表现联系起来。一旦这种联系建立起来,也即完成了我们所说的“双向绑定”。然后,这里说的“事件”,除了那些“点击”等通常的 DOM 事件之外,我们还更关注“数据变化”这个事件。这样一来,我们就可能从面向操作DOM编程转到面向业务代编程。

在启动方面,只要引用jquery和bingo.js,就会自动启动

2.3、原理图

运行效果

3、作用域

上面的代码中,我们给一个 div 元素指定了一个 controller ,那么, div 元素之内,就是 control 这个函数运行时, $view 这个注入资源的控制范围。在代码中我们看到的 clickMe() , hello 这些东西,它们本来的位置对应于 $view.clickMe, $view.hello。

我们在后面的 js 代码中,也可以看到我们就是在操作这些变量。依赖于 bg 的数据绑定机制,操作变量的结果直接在页面上表现出来了。

4、数据绑定与模板

在bingoJS里, 数据绑定与模板是主功能之一; 如果没有它,就没有可以面向业务编程了。通常模板是可以html dom或html 文本, 然后通过指令与数据绑定,从而做view层和control层分离出来。

4.1、数据->模板

数据到表现的绑定,主要是使用模板标记直接完成的:

  1. <p bg-text="hello"></p>
  2. <p>tag: {{hello}}</p>

使用指令或{{ }}标签,就可以直接引用,并绑定一个作用域内的变量。在实现上, bg 自动通过 subscribesubs)观察变量 。效果就是,不管因为什么,如果作用域的变量发生了改变,我们随时可以让相应的页面表现也随之改变。我们可以看下面的例子:

  1. <div id="testView" bg-controller="control" bg-text="aaa"></div>
  2. <script type="text/javascript">
  3. var control = function ($view) {
  4. $view.aaa = '10'
  5. };
  6. </script>

上面的例子在页面载入之后,我们可以在页面上看到 10 。这时,我们可以打开浏览器控制台,输入:

  1. var view = bingo.getView('#testView');
  2. view.aaa = 99;
  3. view.$update();

上面的代码执行之后,就可以看到页面变化了。对于使用 bg 进行的事件绑定,在处理函数中就不需要去关心 $upate() 的调用了,因为 bg 会自己处理。

4.2、模板->数据

模板到数据的绑定,主要是通过 bg-model 来完成的:

  1. <input id="testView" bg-controller="control" bg-model="aaa" />
  2. <script type="text/javascript">
  3. var control = function ($view) {
  4. $view.aaa = '10'
  5. };
  6. </script>

这时修改 input 中的值,我们可以打开浏览器控制台,输入:

  1. bingo.getView('#testView').aaa;

查看,发现变量 aaa 的值已经更改了。

实际上, bg-model 是把两个方向的绑定都做了。它不光显示出变量的值,也把显示上的数值变化反映给了变量。这个在实现上就简单多了,只是绑定 change 事件,然后做一些赋值操作即可。

4.3、模板->数据-模板

现在要考虑的是一种在现实中很普遍的一个需求。比如就是我们可以输入数值,来控制一个矩形的长度:
- 长度数值保存在变量中
- 变量显示于某个 input 中
- 变量的值即是矩形的长度
- input 中的值变化时,变量也要变化
- input 中的值变化时,矩形的长度也要变化

  1. <div id="testView" bg-controller="control">
  2. <input bg-model="width" />
  3. width: {{width}}
  4. <div style="width: 100px; height: 10px; background-color: red"></div>
  5. </div>
  6. <script type="text/javascript">
  7. var control = function ($view, $node) {
  8. $view.width = 100;
  9. $view.$subs('width', function () {
  10. $node.find('div').width($view.width);
  11. });
  12. };
  13. </script>

运行效果

上面例子中, 变量width与input绑定, 并使用$subs来观察width的值, 当我们在input框中输入数量时 ,变量width也同时改变,这里$subs观察到width的改变,并通过$node(jQuery对象),操作div的宽度。

5、模板指令

前面讲了数据绑定之后,现在可以单独讲讲模板了。

作为一套能称之谓“模板”的系统,除了能干一些模板的常规的事之外(好吧,即使是常规的逻辑判断现在它也做不了的),配合作用域 $viewbg 的数据双向绑定机制。

5.1、控制器指令bg-controller

控制器指令,用于将view层和Control层关联起来,关联有以下二种方式:

5.1.1、直接与一个function关联起来

  1. <div bg-controller="control">
  2. <p bg-text="hello"></p>
  3. </div>
  4. <script type="text/javascript">
  5. //定义contoller
  6. var control = function ($view) {
  7. //定义view的hello变量, 并设置值
  8. $view.hello = 'hello world!';
  9. };
  10. </script>

运行效果
如上面代码, 我们定义了一个control function,然后直接用bg-controller,使view与control关联起来。

5.1.2、通过route url关联起来,以实现MVC方式开发

  1. <div bg-controller="/system/module/user/list">
  2. <p bg-text="hello"></p>
  3. </div>

这里我们定义一个route url方式使view与control关联起来,这种方式将会根据route内容决定对应的control js文件按需加载,可以使view tmpl与control js一一对应开发,这种方式将在后面MVC开发式细讲。

5.2、页面加载bg-frame

bg-frame通过route url加载相应模板文件:

  1. <div bg-frame="/system/module/user/list" bg-frame-name="main"></div>
  2. <a href="#/system/module/user/list" bg-target="main">测试1</a>

bg-frame用法有点像html iframe, 我们可以a href指url和设置bg-target, 如果控制加载内容;

5.3、内容引用指令bg-include

内容引用指令,主要用于重复使用的内容引用,引用有以下二种方式:
- 通过url引用同域的内容文件;
- 使用script标签定义的“内部内容”;

5.3.1、通过url引用同域的内容文件:

  1. <div bg-include="include_tmpl.html"></div>

include_tmpl.html为引用文件地址
运行效果

5.3.2、使用 script 标签定义的“内部内容”:

  1. <div bg-include="tmpl1"></div>
  2. <script type="text/html" id="tmpl1">
  3. <p>include by Id: {{selectValue}}</p>
  4. <select bg-foreach="item in list" bg-model="selectValue">
  5. <option value="${item.id}">text_${item.text}</option>
  6. </select>
  7. </script>

tmpl1为script 标签的id
运行效果

5.3.3、bg-include如何确定引用方式?

5.4、循环指令,bg-render/bg-foreach

如果使用bg-foreach, 更喜欢bg-render, 它们两个指令是一样效果的, 原因它可以使用模板语法, 定义模板的内容主要有三种方式:
- 在html需要的地方直接写字符串;
- 通过url引用同域的内容文件;
- 使用script标签定义的“内部内容”;

5.4.1、在html需要的地方直接写字符串:

  1. <select bg-tmpl="item in list">
  2. <option value="${item.id}">text_${item.text}</option>
  3. </select>
  4. <script type="text/javascript">
  5. var control = function ($view) {
  6. $view.list = [{ id: 1, text: "111" }, { id: 2, text: "222" }];
  7. };
  8. </script>

运行效果
如果上面代码, select内部html为模板内容, ${ }为模板标签, 当然可以{{ }}标签, 但{{ }}为绑定标签,为了支持绑定, 性能比较慢,而${ }为模板直接输出标签,没有绑定能力,性能是高率的;

5.4.2、通过url引用同域的内容文件:

  1. <select bg-foreach="item in list" tmpl-url="tmpl_tmpl.html"></select>

运行效果

5.4.3、使用 script 标签定义的“内部内容”:

  1. <select bg-foreach="item in list" tmpl-id="tmpl1"></select>
  2. <script type="text/html" id="tmpl1">
  3. <option value="${item.id}">text_id_${item.text}</option>
  4. </script>

运行效果

5.4.4、模板语法

  1. 支持js语句, 如: ${item.name} ${document.body.childNodes[0].nodeName}
  2. 支持if语句, 如: ${if item.isLogin} 已登录 ${else} 未登录 ${/if}
  3. 支持foreach, 如: ${foreach item in list tmpl=idAAA} ${item_index}|${item.id}|${item_count}|${item_first}|${item_last}${/foreach}
  4. 支持过滤器, 如: ${item.name | text}, 请参考过滤器
  1. <select bg-tmpl="item in list">
  2. ${if item.id == 1}
  3. <option value="${item.id}">text_${item.text}</option>
  4. ${else}
  5. <option value="${item.id}">text_${item.text}</option>
  6. ${/if}
  7. ${foreach cItem in list} ${cItem.id} ${/foreach}
  8. </select>
  9. <script type="text/javascript">
  10. var control = function ($view) {
  11. $view.list = [{ id: 1, text: "111" }, { id: 2, text: "222" }];
  12. };
  13. </script>

运行效果

5.5、条件指令bg-if

主要用于界面分支显示,也可以bg-show | bg-hide来实现同一效果;但bg-if更为撤底,原因bg-if会把下级节点清除,去除没必要的绑定,以提高性能;

  1. <div id="testView" bg-controller="control">
  2. <div bg-if="isOk | eq:'1'"><span>你选择了 "真"</span></div>
  3. <div bg-if="isOk | neq:'1'"><span>你选择了 "假"</span></div>
  4. <select bg-model="isOk">
  5. <option value="1"></option>
  6. <option value="0"></option>
  7. </select>
  8. </div>
  9. <script type="text/javascript">
  10. var control = function ($view, $node) {
  11. $view.isOk = '1';
  12. };
  13. </script>

运行效果

5.6、dom操作指令

5.6.1、dom属性指令(attr)

直接与Dom节点属性(attr)绑定:

  1. <div id="testView" bg-controller="control">
  2. <div bg-attr="{aaa:1,bbb:23, ccc:testVal}">请查看生成后的属性</div>
  3. </div>
  4. <script type="text/javascript">
  5. var control = function ($view, $node) {
  6. $view.testVal = 100;
  7. };
  8. </script>

运行效果

5.6.2、dom样式指令(style)

直接与Dom节点样式(style)绑定:

  1. <div id="Div1" bg-controller="control">
  2. <div bg-style="{width:width, 'background-color':'red'}"></div>
  3. </div>
  4. <script type="text/javascript">
  5. var control = function ($view, $node) {
  6. $view.width = 100;
  7. };
  8. </script>

运行效果

5.6.3、dom事件指令(event)

直接与Dom节点事件(event)绑定:

  1. <div id="Div1" bg-controller="control">
  2. <button bg-event="{click:clickTest}">event方式</button>
  3. <button bg-click="clickTest">事件方式1</button>
  4. <button bg-click="clickAlert('test')">事件方式2</button>
  5. </div>
  6. <script type="text/javascript">
  7. var control = function ($view, $node) {
  8. $view.clickTest = function (e) {
  9. alert('click');
  10. };
  11. $view.clickAlert = function (msg) {
  12. alert(msg);
  13. };
  14. };
  15. </script>

运行效果
如上代码事件可以有两种方式调用:一是直接绑定;二是直接执行;
支持事件有:
- click:click事件
- blur:失去焦点的时候触发
- dblclick:双击时触发
- focus:设置焦点时触发
- focusin:获得焦点的时候会触发这个事件
- focusout:失去焦点的时候会触发这个事件
- keydown:键盘按下时触发
- keypress:键盘按下时触发
- keyup:在按键释放时触发
- mousedown:鼠标在元素上点击后会触发
- mouseenter:当鼠标指针穿过元素时触发, 与mouseleave 事件一起使用
- mouseleave:当鼠标指针离开元素时触发, 与mouseenter 事件一起使用
- mousemove:元素上移动来触发
- mouseout:在鼠标离开对象时触发, 与mousemove事件一起使用
- mouseover:鼠标移入对象时触发
- mouseup:鼠标点击对象释放时触发
- resize:当文档窗口改变大小时触发
- scroll:当滚动条发生变化时触发
- select:当选择input,textarea内容时触发
- submit:fomr提交时触发

5.6.4、dom操作其他指令

5.7、表单指令(bg-model)

表单控件类的模板指令,最大的作用是它预定义了需要绑定的数据的格式。这样,就可以对于既定的数据进行既定的处理
直接与Dom节点样式(style)绑定:

  1. <div id="Div1" bg-controller="control">
  2. <div>input: <input type="text" bg-model="data.input" /></div>
  3. <div>select: <select bg-model="data.select">
  4. <option value="1">1111</option>
  5. <option value="2">222</option>
  6. </select>
  7. </div>
  8. <div>checkbox: <input type="checkbox" value="chk" bg-model="data.checkbox" /></div>
  9. <div>radio:
  10. <input type="radio" value="rd1" name="rr" bg-model="data.radio" />
  11. <input type="radio" value="rd2" name="rr" bg-model="data.radio" />
  12. </div>
  13. <div>textarea: <textarea bg-model="data.textarea"></textarea> </div>
  14. <button bg-click="save">提交</button>
  15. </div>
  16. <script type="text/javascript">
  17. var control = function ($view, $node) {
  18. $view.data = {
  19. input: '1',
  20. select: '2',
  21. checkbox:'chk',
  22. radio: 'rd1',
  23. textarea:'text'
  24. };
  25. $view.save = function () {
  26. console.log($view.data);
  27. };
  28. };
  29. </script>

上面代码寅示bg-model在表单各种元素的用法
运行效果

5.8、过滤器(filter)

这里说的过滤器,是用于对数据的格式化,或者筛选的函数。它们可以直接在模板中通过一种语法使用。对于常用功能来说,是很方便的一种机制。

多个过滤器之间可以直接连续使用。

  1. <div id="Div1" bg-controller="control">
  2. <div bg-show="isHide | not">show ok</div>
  3. <span bg-show="testSW | sw:[1, true, false]">显示: 1</span>
  4. <span bg-show="testSW | sw:[2, true, false]">显示: 2</span>
  5. <span bg-show="testSW | sw:[3, true, false]">显示: 3</span>
  6. </div>
  7. <script type="text/javascript">
  8. var control = function ($view, $node) {
  9. $view.isHide = true;
  10. $view.testSW = 3;
  11. };
  12. </script>

运行效果

默认提供的过滤器:
- eq:相等(eq:'1'意思是等于1)
- neq:不相等(neq:'1'意思是不等于1)
- not:非, not
- gt:大于, (gt:1意思是大于1)
- gte:大于等于, gte:1
- lt:小于, lt:10
- lte:小于等于, lte:10
- text:htmlEncode文本
- sw:switch, sw:[true, '1', '2']

6、依赖注入

6.1、关于依赖注入

先看我们之前代码中的一处函数定义:

  1. var control = function ($view, $node) {
  2. $view.isHide = true;
  3. $node.find('input').val('100');
  4. };

在这个函数定义中,注意那两个参数: $view , $node ,这是两个很有意思的东西。总的来说,它们是参数,这没什么可说的。但又不仅仅是参数——你换个名字代码就不能正常运行了。
事实上,这两个参数,除了完成“参数”的本身任务之外,还可以作为一种语法糖完成了“依赖声明”的任务,并解决合并压缩带来的问题:

  1. var control = ['$view', '$node', function (v, jNode) {
  2. v.isHide = true;
  3. jNode.find('input').val('100');
  4. }];

6.2、依赖注入定义

正如名称,我们可以平时把常用的东西写成一个依赖,在须要使用时可以很方便的注入使用;
使用依赖注入,可以在创建阶段帮我干一些不必要的初始化,简化我们使用,如下面我要定义一个$node(jQuery对象), 而它要依赖原生的node :

  1. bingo.factory('$node', ['node', function (node) {
  2. return $(node);
  3. }]);

如上代码, 我们使用bingo.factory方法定义依赖(工厂),在定义$node过程中我们还依赖了框架自带的node, 例外如果不用考虑合并压缩,我们还可以简化成这样定义:

  1. bingo.factory('$node', function (node) {
  2. return $(node);
  3. });

框架自带依赖可以转到github开源项目参考定义

7、前端MVC

在使用前端MVC开发模式之前,使用以上的机制我们已经可以用MVVM的方式面向数据开发代替jQuery操作方式主面向Dom操作开发,可以实现业务层(M)和展示层(View)分离开发:
运行效果
上图我们可以简单从前端角度看,把后端简单看成后端服务(Services),前端方面分成MV二层,这里我们可以这样理解成所有JS代码放在M层,HTML模板看成V层,然后M层与V层通过双向绑定机制进行互交; 即我们在M层可以定义一个变量与V层连接起来,JS开发时,我们只操作M层这个变量就可以了,从而可以省去对DOM的处理或操作;让我在M层专注于处理更多的业务;并在View层我们可以分工给UE处理和给予UE更大的自由;

前端MVC主要提供ful REST+前端MVC SPA与后台完全分离的一种开发模式:
运行效果
如果之前的前端MV已经实现了M与V分工(即FE与UE的分工),那前端MVC是对FE这职位进一步进化,将FE处理的M层进一步分成MC二层; 在前端MV时,M层要处理JS所有逻辑,如果要处理的东西多了,就会变得非常重,1000行代码不是问题了.在其开发过程过中你会发现M层主要处理三种逻辑:与后端数据处理,项目业务,和View层显示数据;在这三种逻辑中,其中后端数据处理,项目业务是可以重用, 而View层显示数据是要根据V层的展示组装数据;所以前端MVC会将后端数据处理,项目业务分到M层,View层显示数据分到C层并与V层一对一绑定起来;

7.1、路由(route)

跟后端不同的是前端所有定义(模块、库),都是以JS文件(资源)存放,只能先加载(引用)这些定义的JS文件(资源)才能生效;
所以在此框架加载所有资源(JS、模板)地址都会经过路由器(控制)地址。
路由的定义:https://github.com/winpzs/bingoJS/blob/master/src/mv/route.js

7.1.1、三个默认路由

框架已经经典MVC文件存放方式做了几个路由:

  1. //设置view资源路由
  2. bingo.route('view', {
  3. //路由url, 如: view/system/user/list
  4. url: 'view/{module}/{controller}/{action}',
  5. //路由到目标url, 生成:modules/system/views/user/list.html
  6. toUrl: 'modules/{module}/views/{controller}/{action}.html',
  7. //变量默认值, 框架提供内部用的变量: module, controller, action, service
  8. defaultValue: { module: 'system', controller: 'user', action: 'list' }
  9. //如果toUrl不能满足须要时, 可以使用translate
  10. /*
  11. , translate: function (url, toUrl, params) {
  12. params = bingo.extend({
  13. module: 'system',
  14. controller: 'user',
  15. action: 'list', service: 'user'
  16. }, params);
  17. return {
  18. params: params,
  19. url: url, toUrl: 'modules/' + params.module + '/' + params.controller
  20. };
  21. }
  22. */
  23. });
  24. //设置controller资源路由
  25. bingo.route('ctrl', {
  26. url: 'ctrl/{module}/{controller}/{action}',
  27. toUrl: 'modules/{module}/controllers/{controller}.js',
  28. defaultValue: { module: 'system', controller: 'user', action: 'list' }
  29. });
  30. //设置service资源路由
  31. bingo.route('service', {
  32. url: 'service/{module}/{service}',
  33. toUrl: 'modules/{module}/services/{service}.js',
  34. defaultValue: { module: 'system', service: 'user' }
  35. });

可以看出上面定义了三个默认路由:view、ctrl、service
- view:为view层模板资源加载地址路由;
- ctrl:为ctrl层JS加载地址路由;
- service:为M层JS加载地址路由;
其实就是MVC三层的资源加载路由;例如:system(系统)模块下的user(用户)功能,它有两个action页面分别为list列表和form窗口页面, 最终路由生成文件目录结构:
运行效果
如果有接触过后台MVC,这目录结构并不会觉得莫生; 当然你认为这目录结构太过复杂,你可以建立你自己的路由;它只不过但一个资源加载的路由控制而已。
那路由如何转发呢? 如果我输入的url为:view/system/user/list,这时路由会对url进行匹配,并会匹配到‘view’路由,然后由‘view’路由负责解释,它会根据url解释出module、controller、action三个参数,这样参数可以使用进目标的组装和开发中使用$location.params获取,‘view’路由最后解释出modules/system/views/user/list.html。

所以按照上面三个默认路由,system(module)模块下user(controller)功能的list(action)页面,我们使用这样url:
加载view模板资源url: view/system/user/list
加载ctrl引用资源url: ctrl/system/user/list
加载service资源url: service/system/userService
主意,service不是必须的,可以实现简单V C分离开发,但见意C的可重用的逻辑分离到M层(service),方便以后迭代。

7.1.2、路由参数

在上面代码中的{module}、{controller}、{action}、{service},它们是框架默认占用的路由参数,并会用于绑定时引用意义:
- module:为模块名称,只要用于分开各个模块开发;
- controller:控制器,管理Ctrl层,并定义一组action与View层一一连接;
- action:一个控制器可以用多个action,一个action会对应一个View层,如user会有list(列表)、form(窗口)两个action;
- service:服务,管理Models层,负责与后端连接,提供业务接口等;
注意,框架默认占用的路由参数,还使用对模块、控制器、action、service的引用相关,所以不要占用了。

除了上面默认参数, 能不能用自定义参数了?答案是当然的,如:

  1. bingo.route('sysconfig', {
  2. url: 'system/{sysconfig}/{userid}',
  3. toUrl: 'modules/{module}/controllers/{sysconfig}.js',
  4. defaultValue: { module: 'system', controller: 'sysconfig', action: 'sysconfig' }
  5. });

上面的{sysconfig}和{userid}自定义参数,可以用于目标地址的转发,还可以在具体开发时还可以用$location.params获取传入的参数,如:var userid = $location.params.userid;

  1. var control = function ($view, $location) {
  2. var userid = $location.params.userid;
  3. };

7.1.3、路由相关方法

  1. //添加或修改view路由(如果已经有路由,则修改路由)
  2. bingo.route('view', {
  3. url: 'view/{module}/{controller}/{action}',
  4. toUrl: 'modules/{module}/views/{controller}/{action}.html',
  5. defaultValue: { module: 'system', controller: 'user', action: 'list' }
  6. });
  7. //解释url, 返回解释后的url
  8. bingo.route('view/system/user/list')
  9. //结果:modules/system/views/user/list.html
  10. //生成路由url
  11. bingo.routeLink('view', { module: 'system', controller: 'user', action: 'list' })
  12. //结果:view/system/user/list
  13. //解释url, 返回解释后的结果
  14. bingo.routeContext('view/system/user/list')
  15. /*结果:
  16. {
  17. "params": {
  18. "module": "system",
  19. "controller": "user",
  20. "action": "list"
  21. },
  22. "url": "view/system/user/list",
  23. "toUrl": "modules/system/views/user/list.html"
  24. }
  25. */

7.2、MVC Demo 讲解

接下来讲解MVC使用都会用到此Demo:http://winpzs.github.io/bingoJS/mvc/index.html
或者到github下载:https://github.com/winpzs/bingoJS/tree/gh-pages
此Demo只为解说方便,可能体验处理比较粗爆请见谅;

demo主要功能有:
- system/user:system模块用户管理
- system/role:system模块用户角色管理
- crm/client:crm模块客户管理

这里, 我主要用system模块用户管理讲解:
A. 首先是index.html:

  1. <!--用户管理 链接到mvc/modules/system/user/list-->
  2. <a href="#view/system/user/list" bg-target="main">
  3. <i class="icon-double-angle-right"></i>用户管理</a>
  4. <!--页面内容main-->
  5. <div class="row-fluid" style="min-height:100px;"
  6. bg-frame="" bg-frame-name="main">

上面代码中使用bg-frame标签配合href使用,通过设置bg-target与bg-frame-name对应,可以实现类似iframe跳转效果; 这里的会根据路由解释url:view/system/user/list, 并加载view模板;
index.html详细内容:https://github.com/winpzs/bingoJS/blob/gh-pages/mvc/index.html
index.html效果:http://winpzs.github.io/bingoJS/mvc/index.html

B. 加载view/system/user/list模板:

  1. <div class="row-fluid" bg-controller="ctrl/system/user/list">
  2. <!--模板html内容-->
  3. </div>

这里通过bg-controller标签内容ctrl/system/user/list加载JS文件,并关联到相关action;
详细内容:https://github.com/winpzs/bingoJS/blob/gh-pages/mvc/modules/system/views/user/list.html

C. 加载ctrl/system/user/list,并连接起来:

  1. //模块system
  2. bingo.module('system', function () {
  3. //引用service
  4. bingo.using('service/system/userService');
  5. bingo.using('service/system/roleService');
  6. //控制器user
  7. bingo.controller('user', function () {
  8. //action list: ctrl/system/user/list
  9. bingo.action('list', function ($view, $node, $ajax, $service, $dialog) {
  10. //实例service
  11. var userService = $service('userService');
  12. });
  13. });
  14. });

这里定义了system(module)、user(controller)、list(action),并会根据ctrl/system/user/list路由地址参数对应,这样就可以View与Controller的action连接起来;
连接成功后,我们就可以对controller的action和view进行正常的(View - Ctrl)开发了。
而Model层框架是以service方式提供,可以按上面代码先用bingo.using('service/system/userService')把userService的JS加载(引用),然后再使用$service注入获取服务如:var userService = \$service('userService');这样就可以实现真正的前端MVC开发了。

控制器user详细内容:https://github.com/winpzs/bingoJS/blob/gh-pages/mvc/modules/system/controllers/user.js
userService详细内容:https://github.com/winpzs/bingoJS/blob/gh-pages/mvc/modules/system/services/userService.js

以上简单把框架整体开发模式跑了一遍,可能会有很多不足之处;
一个人能力有限了。愿请谁有兴趣一块研究,开发。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注