引言

Cube是基于Jquery和KnockJS的前端组件库,它遵循AMD的模块化规范。下面是一个典型的cube页面
image.png

使用

1. 导入cube组件库

将Cube组件库导入项目的resources目录下
image.png

2. 新建主页html并引入cube

新建目录,新建html文件,引入framework.js,因为Cube组件都遵循AMD的模块化规范,这里还要引入require.js。页面加载时,会先加载framework.js,该js会自动加载基本的js组件,这里CUBE全局变量被挂在到window上了,然后加载require.js。等require.js加载完成后,会执行require.js标签上的data-main属性对应的js文件,这里就是我们主程序的入口了。
image.png

3. 新建首页js

model.js 类似下面的代码,当然这个model.js的名称是可以变的。define([一个数组], function(和数组里的内容一一对应) {},是AMD的编码规范,前面数组表示引用哪些模块(模块本身必须是符合AMD规范的,这里的require.js是南瑞改造的,代码),后面function的入参表示那些模块使用哪些名称去使用。具体的模块可以参考framework.js里的代码。

  1. define(["sammy", "JSONUtil","RESTClient"], function(sammy, jsonUtil,RESTClient) {
  2. var PageViewModel = function() {
  3. var self = this;
  4. //假装有很多代码
  5. cube.endViewModel(self, params);
  6. };
  7. var pvm = new PageViewModel();
  8. $(document).ready(function(e){
  9. cube.startWebPage(pvm);
  10. });
  11. });

image.png

4. 新建页面存放文件夹pages

然后再model.js对应的目录下新建 pages目录,名称不可随意更改,因为framework.js里写死了,之后我们新建一个js和一个相对应的html,注意:html文件的文件名最后一定是view.html,js文件的最后一定是viewmodel.js,这也是framework.js里写死的。
image.pngimage.png

viewmodel.js中的内容类似下面的结构,和首页的js稍微有些不同。因为不可能从两个不同的地方启动应用,会出现下面报错。

  1. define(["RESTClient"], function(RestClient) {
  2. var PageViewModel = function(params) {
  3. var self = this;
  4. cube.endViewModel(this, params);
  5. };
  6. return PageViewModel;
  7. });

image.png

5. 代码目录结构与范例

常见的代码路径类似下面的结构,其中hello-world.html是首页,demo.js是首页js,default-config.js是cube的一些默认选项配置,dialog下面是一个测试页面。
image.png

附上代码:
cube-demo.zip

简单看下首页内容

  1. <!-- 工具栏组件 -->
  2. <toolbar id="homeTool" params="
  3. toolbarContent: toolbarContent,
  4. showtext:true,
  5. onItemClick: onItemClick
  6. "></toolbar>
  7. <!-- 标签页容器 -->
  8. <tabcontainer params="
  9. tabContents: tabContents,
  10. selectedTabRoute: selectedTabRoute
  11. "></tabcontainer>
define(['sammy', 'JSONUtil','RESTClient'], function(sammy, jsonUtil,RESTClient) {

    var PageViewModel = function(params) {
        console.log('home');
        var self = this;

        self.toolbarContent = [ {
            group : [ 
                { text : '页面1', icon:'' ,func : 'toPage1' },
                { text : '页面2', icon:'' ,func : 'toPage2' }
            ]
        }];

        self.onItemClick = function(e) {
            switch (e) {
            case 'toPage1':
                self.selectedTabRoute('#dialog');
                break;
            case 'toPage2':
                self.selectedTabRoute('#text');
                break;
            default:
                break;
            }
        }

        self.tabContents = [{
            title : '页面1',
            route : '#dialog',
//            content: '省级统计内容 ',//当content属性存在时优先显示其内容,否则显示templateOptions配置的页面
            templateOptions: {
                name: 'demo.dialog.dialog',
                params: {title: '测试页面'}
                //type: 'iframe'
                //iframeHeight: '500px'
            }
        }, {
            title : '页面2',
            route : '#text',
            content: '这是一段测试的文字 '//当content属性存在时优先显示其内容,否则显示templateOptions配置的页面
        }];

        self.selectedTabRoute = cube.obj('#dialog');// 这里使用了被观察者对象,下面简称可变对象

        cube.endViewModel(self, params);
    };
    var pvm = new PageViewModel();
    $(document).ready(function(e){
        cube.startWebPage(pvm);
    });
});

在页面中使用的对象或者方法等,需要优先挂载到 PageViewModel对象上,即代码中的self上,如果该属性不是一个固定值,是个可变对象,则你需要使用cube.obj或者cube.array方法,获得一个被观察者对象/数组。
观察者模式各位应该不会陌生,当被观察对象发送改变时,观察者能做出相应的处理,这里也是一样。代码中将标签页的selectedTabRoute属性设置成了被观察者,当我点击相应按钮时,修改了相应的值,标签页容器对象观察到这个改变,就会自动切换分页了。另外,有点类似于jquery中的各种属性设置,调用有参函数可以设置被观察者的值,无参函数可以获得被观察者的值。

6. 获得组件对象和方法调用

当我们查阅API文档时,会发现组件存在方法,而我们上面演示的,都是自动绑定的,如何调用方法是个问题。cube提供了一个api帮助我们去拿到相应的组件实例对象。

cube.getPageViewModelByNode(传入jquery对象);

cube组件设置值.gif
为了避免使用jquery难以获得相应组件,或者获得了错误的组件,再给组件设置ID时应尽量独特,不重复。另外复合组件,比如form表单里的editor编辑器等,也可以用同样的方法去获得值。

7. 父子页面之间传值

一般父页面展示子页面的时候,都存在一个叫templateOptions的值,我们可以将要传递的值放入它的params字段中,上面例子做些简单修改。

  1. hello-world.html增加一个label变成下面的
<!-- 工具栏组件 -->
<toolbar id="homeTool" params="
                    toolbarContent: toolbarContent,
                    showtext:true,
                    onItemClick: onItemClick
                    "></toolbar>
页面1的输入: <cubelabel params="text: text"></cubelabel>
<!-- 标签页容器 -->
  1. demo.js 增加text属性并传入页面1的templateOptions中
self.text = cube.obj();

self.tabContents = [{
  title : '页面1',
  route : '#dialog',
  //            content: '省级统计内容 ',//当content属性存在时优先显示其内容,否则显示templateOptions配置的页面
  templateOptions: {
    name: 'demo.dialog.dialog',
    params: {text: self.text}
    //type: 'iframe'
    //iframeHeight: '500px'
  }
}, {
  title : '页面2',
  route : '#text',
  content: '这是一段测试的文字 '//当content属性存在时优先显示其内容,否则显示templateOptions配置的页面
}];
  1. dialogviewmodel.js 修改下fields
// 查询框字段
self.fields = [ 
  { name : "taskType", caption : "任务类型",editorType : "TextEditor", value: cube.obj('current'), visible: false }, 
  { name : "facilityName", caption : "设备名称",editorType : "TextEditor", value: params.text}, 
  { name : "eventlevel", caption : "事件等级",editorType : "DropDownEditor", list:[
    { value: "level1", text: "一级" },
    { value: "level2", text: "二级" },
    { value: "level3", text: "三级" },
    { value: "level4", text: "四级" }
  ]}, 
  { name : "periods", caption : "期数", editorType : "DropDownEditor"},
  { name : "beginTime", caption : "停电开始时间",editorType : "DateTimeEditor",formatString: "yyyy-MM-dd "}, 
  { name : "endTime", caption : "停电结束时间", editorType : "DateTimeEditor",formatString: "yyyy-MM-dd "}
];

然后刷新页面测试下。

cube父子组件传值.gif