树形组件是一种具有层级结构的组件,广泛应用于各种场景。本章会实现一个简单的树形组件,尽管功能有限,但你可以通过扩展它来实现自己所需要的树形组件。
数据源
树形组件的数据源可以是 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。这里有详尽的入门文档可供参考。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# xmlplus
# 组件
# tree
# xmlplus组件设计系列之网格(DataGrid)(10)
# xmlplus组件设计系列之路由(ViewStack)(7)
# xmlplus组件设计系列之分隔框(DividedBox)(8)
# 值得分享和收藏的xmlplus组件学习教程
# 递归
# 是一个
# 是一种
# 你可以
# 才会
# 但在
# 我们可以
# 可以通过
# 而成
# 或者是
# 你对
# 可供
# 应用于
# 拖动
# 报错
# 会比
# 但你
# 定了
# 设置为
# 它会
相关文章:
PHP 500报错的快速解决方法
专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?
网站app免费制作软件,能免费看各大网站视频的手机app?
c++怎么使用类型萃取type_traits_c++ 模板元编程类型判断【方法】
如何快速搭建安全的FTP站点?
北京制作网站的公司排名,北京三快科技有限公司是做什么?北京三快科技?
矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?
如何在阿里云香港服务器快速搭建网站?
上海网站制作网页,上海本地的生活网站有哪些?最好包括生活的各个方面的?
深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?
如何彻底删除建站之星生成的Banner?
如何将凡科建站内容保存为本地文件?
网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?
建站之星2.7模板快速切换与批量管理功能操作指南
微网站制作教程,我微信里的网站怎么才能复制到浏览器里?
建站之星手机一键生成:多端自适应+小程序开发快速建站指南
建站DNS解析失败?如何正确配置域名服务器?
php能控制zigbee模块吗_php通过串口与cc2530 zigbee通信【介绍】
网站制作公司,橙子建站是合法的吗?
网站制作大概多少钱一个,做一个平台网站大概多少钱?
如何选择域名并搭建高效网站?
韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐
微信网站制作公司有哪些,民生银行办理公司开户怎么在微信网页上查询进度?
大型企业网站制作流程,做网站需要注册公司吗?
北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?
如何用IIS7快速搭建并优化网站站点?
网站好制作吗知乎,网站开发好学吗?有什么技巧?
如何通过商城免费建站系统源码自定义网站主题?
内网网站制作软件,内网的网站如何发布到外网?
c++怎么编写动态链接库dll_c++ __declspec(dllexport)导出与调用【方法】
TestNG的testng.xml配置文件怎么写
手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?
成都响应式网站开发,dw怎么把手机适应页面变成网页?
合肥做个网站多少钱,合肥本地有没有比较靠谱的交友平台?
香港服务器WordPress建站指南:SEO优化与高效部署策略
,石家庄四十八中学官网?
建站之星后台管理:高效配置与模板优化提升用户体验
南宁网站建设制作定制,南宁网站建设可以定制吗?
Python如何创建带属性的XML节点
h5网站制作工具有哪些,h5页面制作工具有哪些?
建站之星代理平台如何选择最佳方案?
沈阳个人网站制作公司,哪个网站能考到沈阳事业编招聘的信息?
用v-html解决Vue.js渲染中html标签不被解析的问题
济南网站制作的价格,历城一职专官方网站?
常州企业网站制作公司,全国继续教育网怎么登录?
制作网站的软件下载免费,今日头条开宝箱老是需要下载怎么回事?
Dapper的Execute方法的返回值是什么意思 Dapper Execute返回值详解
网站制作大概要多少钱一个,做一个平台网站大概多少钱?
如何选购建站域名与空间?自助平台全解析
阿里云网站制作公司,阿里云快速搭建网站好用吗?
*请认真填写需求信息,我们会在24小时内与您取得联系。