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


Posted in Javascript onMay 02, 2017

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

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

数据源

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

var data = {
 name: 'My Tree',
 children: [
 { name: 'hello' },
 { name: 'world' },
 {
  name: 'child folder',
  children: [
  { name: 'alice' }
  ]
 }
 ]
};

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

递归结构的设计

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

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

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

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

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

数据的加载与渲染

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

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

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

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.entries.show() && load()) : sys.entries.hide();
  });
  function load() {
   if ( sys.entries.children().length == 0 )
    for ( var item of data.children )
    sys.add.before("Item").value().val(item);
  }
  function val(value) {
   data = value;
   sys.neme.text(data.name);
   data.children && data.children.length && sys.expand.show().text(" [+]");
  }
  return { val: val };
 }
}

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

动态添加节点

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

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

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

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().val(stuff);
  });
  // 其余代码同前
 }
}

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

完整的树形组件

综合以上的内容,现在给出一个完整版本的树形组件:

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;
 }
},
Item: {
 css: "#item { cursor: pointer; }",
 xml: `<li id='item'>
   <div id='content'>
    <span id='neme'/><span id='expand'/>
   </div>
   <ul id='entries'>
    <li id='add'>+</li>
   </ul>
   </li>`,
 map: { defer: "entries" },
 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().val(stuff);
  });
  sys.expand.on("click", function () {
   open = !open;
   sys.expand.text(open ? " [-]" : " [+]");
   open ? (sys.entries.show() && load()) : sys.entries.hide();
  });
  function load() {
   if ( sys.entries.children().length == 1 )
    for ( var item of data.children )
    sys.add.before("Item").value().val(item);
  }
  function val(value) {
   data = value;
   sys.neme.text(data.name);
   data.children && data.children.length && sys.expand.show().text(" [+]");
  }
  return { val: val };
 }
}

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

本系列文章基于 xmlplus 框架。如果你对 xmlplus 没有多少了解,可以访问 www.xmlplus.cn。这里有详尽的入门文档可供参考。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
BOM与DOM的区别分析
Oct 26 Javascript
使用JavaScript和C#中获得referer
Nov 14 Javascript
jquery显示loading图片直到网页加载完成的方法
Jun 25 Javascript
jQuery+AJAX实现无刷新下拉加载更多
Jul 03 Javascript
js文字横向滚动特效
Nov 11 Javascript
Immutable 在 JavaScript 中的应用
May 02 Javascript
学JavaScript七大注意事项【必看】
May 04 Javascript
js时间比较 js计算时间差的简单实现方法
Aug 26 Javascript
Vue+Element实现动态生成新表单并添加验证功能
May 23 Javascript
Node.JS用纯JavaScript生成图片或滑块式验证码功能
Sep 12 Javascript
使用layer弹窗,制作编辑User信息页面的方法
Sep 27 Javascript
关于引入vue.js 文件的知识点总结
Jan 28 Javascript
详解Vue2.X的路由管理记录之 钩子函数(切割流水线)
May 02 #Javascript
令按钮悬浮在(手机)页面底部的实现方法
May 02 #Javascript
Vue2.0表单校验组件vee-validate的使用详解
May 02 #Javascript
ES6学习教程之对象的扩展详解
May 02 #Javascript
Javascript ES6中数据类型Symbol的使用详解
May 02 #Javascript
Bootstrap实现基于carousel.js框架的轮播图效果
May 02 #Javascript
Vue2.x中的父子组件相互通信的实现方法
May 02 #Javascript
You might like
简单的用PHP编写的导航条程序
2006/10/09 PHP
第十五节--Zend引擎的发展
2006/11/16 PHP
PHP的Yii框架使用中的一些错误解决方法与建议
2015/08/21 PHP
YII Framework框架教程之使用YIIC快速创建YII应用详解
2016/03/15 PHP
Joomla框架实现字符串截取的方法示例
2017/07/18 PHP
PHP空值检测函数与方法汇总
2017/11/19 PHP
javascript中onmouse事件在div中失效问题的解决方法
2012/01/09 Javascript
JQuery入门——用映射方式绑定不同事件应用示例
2013/02/05 Javascript
使用JS读秒使用示例
2013/09/21 Javascript
表单元素与非表单元素刷新区别详细解析
2013/11/06 Javascript
jquery操作下拉列表、文本框、复选框、单选框集合(收藏)
2014/01/08 Javascript
jQuery实现径向动画菜单效果
2015/07/17 Javascript
原生JavaScript实现瀑布流布局
2020/06/28 Javascript
Popup弹出框添加数据实现方法
2017/10/27 Javascript
React实现全局组件的Toast轻提示效果
2018/09/21 Javascript
微信小程序实现分页加载效果
2020/11/19 Javascript
Python修改MP3文件的方法
2015/06/15 Python
python实现批量按比例缩放图片效果
2018/03/30 Python
python 工具 字符串转numpy浮点数组的实现
2020/03/14 Python
Python爬虫破解登陆哔哩哔哩的方法
2020/11/17 Python
python上下文管理的使用场景实例讲解
2021/03/03 Python
Trina Turk官网:美国时装和泳装品牌
2018/06/10 全球购物
德国在线订购鲜花:Fleurop
2018/08/25 全球购物
介绍一下结构化程序设计方法和面向对象程序设计方法的区别
2012/06/27 面试题
毕业生找工作的自我评价
2013/10/18 职场文书
建筑工程管理专业自荐信范文
2013/12/28 职场文书
技校学生个人职业生涯规划范文
2014/03/03 职场文书
马智宇婚礼主持词
2014/03/22 职场文书
校园安全演讲稿
2014/05/09 职场文书
国贸专业求职信
2014/06/28 职场文书
违纪开除通知书
2015/04/25 职场文书
员工升职自我评价
2019/03/26 职场文书
2019消防宣传标语!
2019/07/10 职场文书
python3+PyQt5+Qt Designer实现界面可视化
2021/06/10 Python
Opencv中cv2.floodFill算法的使用
2021/06/18 Python
Nginx内网单机反向代理的实现
2021/11/07 Servers