• 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.getDataBox().clear();
               //TWaver内置的属性和方法都在prototype上,所以如果data的类型是function,我们就遍历它的prototype
               var obj = typeof selectedData.clazz === "function" ? selectedData.clazz.prototype : selectedData.clazz;
               for (var name in obj) {
                    if (obj.hasOwnProperty(name)) {
                          var listNode = new twaver.Node();
                          if (typeof obj[name] === "function") {
                                listNode.setIcon("method");
                          } else {
                                listNode.setIcon("property");
                          }
                          listNode.setName(name + " - " + typeof obj[name]);
                          //注意getContent方法,对于function直接返回,对于Object再进行一次遍历
                          listNode.content = "" + getContent(obj[name]);
                          html += name + ":" + listNode.content;
                          list.getDataBox().add(listNode);
                     }
                }
                pre.innerHTML = '';
                html = js_beautify(html);
                pre.appendChild(document.createTextNode(html));
                prettyPrint();
           }
    });

    除了填充list,我们还直接把对象属性的js代码组合起来放到右侧pre中,为了规范js代码,我们用到了js_beautify和prettify两个类库,感兴趣的同学可以谷歌一下。

    • pre的实现

    在List上点击某个属性或方法的时候,更新pre的内容为属性值或方法代码

    //list选中的节点发生变化时更新pre
    list.getSelectionModel().addSelectionChangeListener(function (e) {
         var data = list.getSelectionModel().getLastData();
         if (data) {
             pre.innerHTML = '';
             var html = js_beautify(data.content + "");
             pre.appendChild(document.createTextNode(html));
             prettyPrint();
          }
    });

    这三部分介绍完,实际上这个页面也就写完了,通过这些代码,大家应该可以感受到JavaScript的灵活之处,页面布局部分的代码就不介绍了,大家可从下载附件自行研究,最后附上附件见原文最下方

  • 相关阅读:
    【JavaScript】JavaScript 思维导图
    python logging 模块
    推荐系统
    【Linux】国内镜像汇总
    python 小游戏练手
    Python3 拼图小游戏
    python cls self 讲解
    Python-插件化开发
    Python-并发和线程
    git命令的使用
  • 原文地址:https://www.cnblogs.com/twaver/p/2777019.html
Copyright © 2020-2023  润新知