日期:2014-05-17  浏览次数:20793 次

TWaver HTML5 继承结构和成员说明

JavaScript是一门动态语言,但是面向对象的特征没有Java那么明显,导致我们开发起来非常不习惯。拿继承来说,Java中有专门的extends和implements关键字实现,但是在JavaScript却引入了一个"别扭的"prototype,而且实现方式有很多种,虽然灵活,却很容易让初学者一头雾水不知所措。TWaver HTML5的doc是一个js文件,对编辑器很友好,但是我们看起来却不是很方便,远不如JavaDoc来得一目了然,于是我们做了另一个html,算是对原js格式doc的补充。先看一下最后完成的效果:

运行截图:


这并不是一个静态页面,而是用JavaScript动态解析TWaver,所以即使TWaver更新也没关系,只要在这个html中引入新的twaver.js就可以了。

界面说明:整个页面的布局借助twaver.controls.SplitPane实现,左侧是TWaver的树组件,中间是List组件,右侧是一个pre标签,借助beautify和prettify展现js代码。

接下来介绍一下页面上三个部分的实现方式:

  • Tree的实现,下面是初始化Tree的全部代码:

//twaver.Util.getAllClassNames()返回TWaver所有的内部类型
var allClassNames = twaver.Util.getAllClassNames();
//遍历类名
allClassNames.forEach(function (data) {
     addClass(data);
});
var elementBox = new twaver.ElementBox();
var map = {};
//初始化Tree box
function addClass(name) {
    var node = new twaver.Node(name);
    node.setName(name);
//分割字符串,找我们需要的类或对象
    var clazzArr = name.split(".");
    var clazz = window;
    for (var i = 0; i < clazzArr.length; i++) {
          clazz = clazz[clazzArr[i]];
    } 
//根据不同的类型设置Icon     
    if (typeof clazz === "object") {
          node.setIcon("object");     
    } else if (typeof clazz === "function") {
          node.setIcon("class");     
    }     
    //同时将node存入map,方便查询使用
    map[name] = node;
    node.clazz = clazz;
    elementBox.add(node); } 
    //... 
    var tree = new twaver.controls.Tree(elementBox); 

getAllClassNames返回的是类或对象的名字,但是我们要获得实际的类和对象以便可以解析它们的属性和方法。思考一下:在浏览器环境下window是根对象,所有全局对象都是window对象的属性而已,TWaver也不例外,所以我们分割字符串,通过window对象一层一层找属性,最终找到我们要的类或对象。然后我们生成Node,填充box数据容器;同时做了一个< 名字---Node>的映射,后面会用到。 初始化Tree以后设置节点的父子关系:

 
elementBox.toDatas().forEach(function (data) { 
//TWaver所有内置类型都有superClass属性,指向实际的父类或父对象,通过它可以得到父类然后从map中取出树上相应的节点     
     var superClass = data.clazz.superClass;     
     if (superClass && superClass.getClassName) { 
         data.setParent(map[superClass.getClassName()]);  
     } 
}); 

大家注意到,Tree的上方还有一个用来过滤数据的文本框,我们看一下它的事件处理:

 
//Tree的过滤文本框 
var treeFilter = document.createElement("input");
treeFilter.type = "text"; 
treeFilter.addEventListener("input", function () {
     var value = treeFilter.value.trim().toLowerCase();     
     if (value.length > 0) {
             tree.setVisibleFunction(function (data) {
                 if(data.getName().toLowerCase().indexOf(value)>=0){return true};
                 //如果当前节点的名字与过滤字符串不匹配,就去查询是否有子节点匹配
                 //如果子节点匹配,父节点同样可见
                 return isChildVisible(data, value);
             });
     } else {
            tree.setVisibleFunction(null);
     }
});
//...
//递归是否有子节点可见
function isChildVisible(parent, value) {
    var children = parent.getChildren();
    for (var i = 0; i < children.size(); i++) {           
          var child = children.get(i);           
           if (child.getName().toLowerCase().indexOf(value) >= 0) {
               return true;
          } else if (isChildVisible(child, value)) {
                return true;
          }
     }
     return false;
}

对于Tree过滤器,不能简单的判断当前节点,因为可能当前节点的名字不符合过滤字符串,但是子节点符合,这种时候父节点也要显示,所以需要做递归处理:如果当前节点的子节点符合过滤字符串,当前节点同样可见。

  • List的实现

List比Tree要简单的多,监听Tree的选中改变事件,得到选中的Node然后解析属性和方法,填充进List的数据容器

tree.getSelectionModel().addSelectionChangeListener(function (e) {
     var selectedData = tree.getSelectionModel().getLastData();
     if (selectedData) {
           var html = '';
           list.ge