文档章节

xmlplus 组件设计系列之九 - 树(Tree)

qudou
 qudou
发布于 2017/05/02 15:22
字数 1246
阅读 21
收藏 0
点赞 0
评论 0

树形组件是一种具有层级结构的组件,广泛应用于各种场景。本章会实现一个简单的树形组件,尽管功能有限,但你可以通过扩展它来实现自己所需要的树形组件。

<img src="http://xmlplus.cn/img/tree.png" class="img-responsive"/>

数据源

树形组件的数据源可以是 JSON 格式的数据对象,也可以是具有 XML 结构的数据或者是其它的具有层级结构的数据。本章将采用具有如下 JSON 格式的数据对象。

// 09-01
{
    name: 'My Tree',
    children: [
        { name: 'hello' },
        { name: 'world' },
        { name: 'child folder', children: [{ name: 'alice' }]}
    ]
};

上述数据源中,name 值会作为树结点的名称显示,含 children 的数组代表节点的子级。

递归结构的设计

由 HTML 中的列表元素 ul 以及 li 组合而成对象具有天然的树形结构,我们不妨采用它们作为构建树形组件的基本元素。树形组件的最外层必然是一个 ul 元素,所以我们可以暂时定义树形组件如下:

// 09-01
Tree: {
    xml: `<ul id='tree'>
            <Item id='item'/>
          </ul>`
}

这里的未定义的组件 Item 是一个需要递归定义的子项组件,它会根据提供的数据递归地生成子孙对象。下面是一种可能的设计:

// 09-01
Item: {
    xml: `<li id='item'>
            <div id='content'>
              <span id='neme'/><span id='expand'/>
            </div>
            <ul id='children'/>
          </li>`,
    map: { defer: "children" }
}

注意,上面的 neme 对象是用于显示 name 属性的。expand 对象用于展开或者关闭子级对象 entries。子级对象 children 被设置为需要延迟实例化,只有当用户点击 expand 对象展开子级时,该对象才会实例化。

数据的加载与渲染

如上一节所述,我们设定了子级对象 children 需要延迟实例化。所以,在给子项 Item 提供的数据设置接口不应该立马对 children 实例化。下面我们先给出数据接口函数。

// 09-01
Item: {
    // css, xml, map 项同上
    fun: function (sys, items, opts) {
        var data;
        return function (value) {
            data = value;
            sys.neme.text(data.name);
            data.children && data.children.length && sys.expand.show().text(" [+]");
        };
    }
}

该接口函数只是设置了当前节点相关的内容。下面我们来侦听 expand 对象的点击事件,并适时地完成组件对象 children 的实例化。

// 09-01
Item: {
    // css, xml, map 项同上
    fun: function (sys, items, opts) {
        var data, open;
        sys.expand.on("click", function () {
            open = !open;
            sys.expand.text(open ? " [-]" : " [+]");
            open ? (sys.children.show() && load()) : sys.children.hide();
        });
        function load() {
            if ( sys.children.children().length == 0 )
              for ( var item of data.children )
                sys.add.before("Item").value()(item);
        }
        return function (value) {
            data = value;
            sys.neme.text(data.name);
            data.children && data.children.length && sys.expand.show().text(" [+]");
        };
    }
}

上述代码中包含一个 open 参数,该参数记录了当前节点的是否处于展开状态以供相关的侦听器使用。

动态添加节点

现在我们对上述组件进行一个小的扩展,使得它支持动态添加树节点的功能。首先,我们在对象 children 的子级添加一个触发按钮,并命名为 add。

// 09-01
Item: {
    xml: `<li id='item'>
            <div id='content'>
              <span id='neme'/><span id='expand'/>
            </div>
            <ul id='children'>
              <li id='add'>+</li>
            </ul>
          </li>`,
    map: { defer: "children" }
}

其次,需要侦听 add 对象的点击事件,在侦听器中完成对象的添加。

// 09-01
Item: {
    // css, xml, map 项同前
    fun: function (sys, items, opts) {
        var data, open;
        sys.item.on("click", "//*[@id='add']", function () {
            var stuff = {name: 'new stuff'};
            data.children.push(stuff);
            sys.add.before("Item").value()(stuff);
        });
        // 其余代码同前
    }
}

这里需要注意,对 add 对象的侦听不能采取直接式的侦听:sys.add.on("click",...),而应该使用代理的方式,否则会报错。因为其父级属于延迟实例化的组件,在 children 对象未实例化之间,add 对象并不可见。

完整的树形组件

综合以上的内容,现在给出一个完整版本的树形组件,下面先给出的是树组件的子项组件:

// 09-01
Item: {
    css: "#item { cursor: pointer; }",
    xml: `<li id='item'>
            <div id='content'>
              <span id='neme'/><span id='expand'/>
            </div>
            <ul id='children'>
              <li id='add'>+</li>
            </ul>
          </li>`,
    map: { defer: "children" },
    fun: function (sys, items, opts) {
        var data, open;
        sys.item.on("click", "//*[@id='add']", function () {
            var stuff = {name: 'new stuff'};
            data.children.push(stuff);
            sys.add.before("Item").value()(stuff);
        });
        sys.expand.on("click", function () {
            open = !open;
            sys.expand.text(open ? " [-]" : " [+]");
            open ? (sys.children.show() && load()) : sys.children.hide();
        });
        function load() {
            if ( sys.children.children().length == 1 )
              for ( var item of data.children )
                sys.add.before("Item").value()(item);
        }
        return function (value) {
            data = value;
            sys.neme.text(data.name);
            data.children && data.children.length && sys.expand.show().text(" [+]");
        };
    }
}

其次给出树组件。在实际应用中的树形组件会比这里的功能更丰富些,你可以在上述代码的基础上进一步的改进,比如添加些 ICON 图标、让子项成为可拖动的等等。但在改进过程中尽量避免代码的复杂化,适当地剥离些代码出来封装成组件是非常有必要的。

// 09-01
Tree: {
    css: `#tree { font-family: Menlo, Consolas, monospace; color: #444; }
          #tree, #tree ul { padding-left: 1em; line-height: 1.5em; list-style-type: dot; }`,
    xml: `<ul id='tree'>
            <Item id='item'/>
          </ul>`,
    fun: function (sys, items, opts) {
        return items.item;
    }
}

测试

我们最后给出一个测试用例。该例子的测试数据与本章开始给出的数据一致。

Index: {
    xml: "<Tree id='tree' xmlns='tree'/>",
    fun: function (sys, items, opts) {
        items.tree({
            name: 'My Tree',
            children: [
                { name: 'hello' },
                { name: 'world' },
                { name: 'child folder', children: [{ name: 'alice' }]}
            ]
        });
    }
}

© 著作权归作者所有

共有 人打赏支持
qudou

qudou

粉丝 5
博文 11
码字总数 14933
作品 2
福州
程序员
全栈 JavaScript 框架 xmlplus 1.5.9 发布

该版本主要对全局函数 clearLibrary 作了简化,另外对文档的一些文字错误进行了修正,同时保持了 gitHub 与 npm 版本之间的同步。 xmlplus 是一个设计非常独特 JavaScript 框架,用于快速开发...

qudou ⋅ 2017/04/30 ⋅ 16

全栈 JavaScript 框架--xmlplus

xmlplus 是一个设计非常独特 JavaScript 框架,用于快速开发前后端项目。 基于组件设计 在 xmlplus 中,组件是基本的构造块。评价组件设计好坏的一个重要标准是封装度。基于 xmlplus 设计的组...

qudou ⋅ 2017/04/21 ⋅ 1

xmlplus v1.5.8 正式发布 - 全栈 JavaScript 框架

全栈 JavaScript 框架 xmlplus v1.5.8 正式发布 xmlplus 是一个设计非常独特 JavaScript 框架,用于快速开发前后端项目。 基于组件设计 在 xmlplus 中,组件是基本的构造块。评价组件设计好坏...

qudou ⋅ 2017/04/27 ⋅ 2

JavaScript 框架 xmlplus 1.5.12 发布

JavaScript 框架 xmlplus 1.5.12 发布了。xmlplus 是一个设计非常独特 JavaScript 框架,用于快速开发前后端项目。 这个版本主要添加了一个全局接口 create。该函数是一个轻量的用于创建组件...

qudou ⋅ 2017/05/24 ⋅ 0

再厉害的魔术也比不上真正的redux

why redux? 随着 JavaScript 单页应用开发日趋复杂,管理不断变化的 state 非常困难 Redux的出现就是为了解决state里的数据问题 在React中,数据在组件中是单向流动的 数据从一个方向父组件流...

Meteor ⋅ 06/06 ⋅ 0

JavaScript 框架 xmlplus 1.5.14 发布

JavaScript 框架 xmlplus 1.5.14 发布了。更新如下: 将原先对于 xmldom 模块的依赖改为 exmldom。exmldom 模块是对 xmldom 模块的扩展,添加了事件支持。也就是说,你可以像前端那样在 dom ...

qudou ⋅ 2017/06/10 ⋅ 0

Web界面开发框架--EdoJS

EdoJS是一个跨浏览器的富客户端界面框架解决方案。它的设计目标是为了让人们用最简单的方式,快速开发出丰富、健壮、高性能的跨浏览器Web应用程序。 EdoJS是使用Javascript开发的,所以它跟服...

匿名 ⋅ 2009/10/26 ⋅ 0

Behavior Designer文档-0(目录)

行为树设计师插件是一个专门为unity设计的AI插件。 中国大陆学习交流群:164034749(包含插件下载文件,仅供学习使用) 文档目录 1,什么是行为树(What is a Behavior Tree) 2,概述(ove...

安世博 ⋅ 2016/02/25 ⋅ 2

STL系列之六 set与hash_set

STL系列之六 set与hash_set set和hashset是STL中比较重要的容器,有必要对其进行深入了解。在STL中,set是以红黑树(RB-tree)作为底层数据结构的,hashset是以Hash table(哈希表)作为底层...

彭博 ⋅ 2012/04/12 ⋅ 0

STL系列之六 set与hash_set

STL系列之六 set与hash_set set和hashset是STL中比较重要的容器,有必要对其进行深入了解。在STL中,set是以红黑树(RB-tree)作为底层数据结构的,hashset是以Hash table(哈希表)作为底层...

长平狐 ⋅ 2012/12/10 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 今天 ⋅ 0

JavaScript零基础入门——(十一)JavaScript的DOM操作

JavaScript零基础入门——(十一)JavaScript的DOM操作 大家好,欢迎回到我们的JavaScript零基础入门。最近有些同学问我说,我讲的的比书上的精简不少。其实呢,我主要讲的是我在开发中经常会...

JandenMa ⋅ 今天 ⋅ 0

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 今天 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 今天 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 今天 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 今天 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

python f-string 字符串格式化

主要内容 从Python 3.6开始,f-string是格式化字符串的一种很好的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快! 在本文的最后,您将了解如何以及为什么今...

阿豪boy ⋅ 昨天 ⋅ 0

Python实现自动登录站点

如果我们想要实现自动登录,那么我们就需要能够驱动浏览器(比如谷歌浏览器)来实现操作,ChromeDriver 刚好能够帮助我们这一点(非谷歌浏览器的驱动有所不同)。 一、确认软件版本 首先我们...

blackfoxya ⋅ 昨天 ⋅ 0

线性回归原理和实现基本认识

一:介绍 定义:线性回归在假设特证满足线性关系,根据给定的训练数据训练一个模型,并用此模型进行预测。为了了解这个定义,我们先举个简单的例子;我们假设一个线性方程 Y=2x+1, x变量为商...

wangxuwei ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部