这是用过的"最差"树形插件 !!!
或许大家听过一个bootstrap UI框架---ace皮肤。有兴趣的童鞋可以在线查看:https://www.iteblog.com/ace/index.html
相较于此前使用的ExtJs 3.x或者传统的jquery easy ui框架,bootstrap风格的确让人眼前一亮。
但是说到它集成的属性插件,或许就没有那么让人愉快了。
下载官方Demo,找到位于如下位置:
与多数属性控件不同,fuelux.tree 的data格式不是很标准。
格式如下:
是的就是这么任性。
看起来就是反人类的一种格式,开发人员不得不从正常的属性结构做一次转换。
但是当你看了这个效果之后,你也许会和我一样,坚持尝试.是滴,水瓶就是那么坚持!
为了保持项目整体风格的一致性,笔者也只好尝试该控件。
花了大半天时间总算有点眉目,对于其中的艰辛不希望后来者走同样的弯路。方便别人也是帮助自己嘛。哈哈
笔者这里使用的是C#进行动态绑定,故按照结构是如下类,
public class FueluxTree { public Dictionary<string, FueluxTreeNode> data { get; set; } public string status { get; set; } } /// <summary> /// 绑定FueluxTreeNode /// </summary> public class FueluxTreeNode { public string type { get; set; } public string name { get; set; } public additionalParameters additionalParameters { get; set; } } public class additionalParameters { public int id { get; set; } public bool itemSelected { get; set; } public Dictionary<string, FueluxTreeNode> children { get; set; } }
这样基本的json格式就满足了。
接下来需要模拟一些后台数据,按关系型数据库存储格式准备一些数据。
设计类型如下:
public class Student { public int Id { get; set; } public int ParentId { get; set; } public string Name { get; set; } public int level { get; set; } }
服务数据:
public class TestService { private static TestService _Instance = null; public static TestService Instance { get { if (_Instance == null) _Instance = new TestService(); return _Instance; } } private TestService() { } public FueluxTree GetTree() { FueluxTree _Tree = new FueluxTree(); List<Student> students = GetSutdents(); FueluxTreeNode node = new FueluxTreeNode { name = "root", type = "folder", additionalParameters = new additionalParameters { id = 0, //children=new List<FueluxTreeNode>(), children = new Dictionary<string, FueluxTreeNode>(), itemSelected = false, } }; _LoopToAppendChildren(students, node); _Tree.data = node.additionalParameters.children; _Tree.status = "OK"; return _Tree; } private void _LoopToAppendChildren(List<Student> students, FueluxTreeNode node) { //[{status: "OK", data: [{"name":"South Africa","type":"folder","additionalParameters":{"id":"1"}}] }] var substudents = students.Where(c => c.ParentId == node.additionalParameters.id).ToList(); foreach (Student student in substudents) { string type = string.Empty; if (student.level == 3) type = "item"; else type = "folder"; FueluxTreeNode subnode = new FueluxTreeNode { name = student.Name, type = type, additionalParameters = new additionalParameters { id = student.Id, //children = new List<FueluxTreeNode>() children = new Dictionary<string, FueluxTreeNode>() } }; //node.additionalParameters.children.Add(subnode); node.additionalParameters.children.Add(student.Name, subnode); _LoopToAppendChildren(students, subnode); } } public List<Student> GetSutdents() { List<Student> _Students = new List<Student>(); _Students.Add(new Student { Id = 1, ParentId = 0, Name = "四川", level=1 }); _Students.Add(new Student { Id = 2, ParentId = 0, Name = "重庆", level=1 }); _Students.Add(new Student { Id = 3, ParentId = 1, Name = "成都", level=2 }); _Students.Add(new Student { Id = 4, ParentId = 3, Name = "大邑", level=3 }); _Students.Add(new Student { Id = 5, ParentId = 2, Name = "涪陵", level = 2 }); return _Students; } }
注意:这里 只是Demo,类型为Student,严格讲,应该是Area更为确切.
.net mvc 控制其中返回
[HttpPost] public JsonResult GetTreeData() { var tree= TestService.Instance.GetTree(); return Json(tree,JsonRequestBehavior.AllowGet); }
后台部分已经完成,相对来说,还是比较精简了.
接下来前台页面如何绑定呢??
@{ ViewBag.Title = "Index"; //Layout = "~/Areas/Admins/Views/Shared/_Layout.cshtml"; Layout = null; } <h2>Index</h2> <link href="~/Assets/Ace1.3/css/bootstrap.min.css" rel="stylesheet" /> <link href="~/Assets/Ace1.3/css/font-awesome.min.css" rel="stylesheet" /> <!-- fonts --> <link href="~/Assets/Ace1.3/css/ace-fonts.css" rel="stylesheet" /> <link href="~/Assets/Ace1.3/css/ace.min.css" rel="stylesheet" /> <!--[if lte IE 9]> <link rel="stylesheet" href="../assets/css/ace-ie.min.css" /> <![endif]--> <div class="row"> <div class="center" style="width:400px; margin:12px;"> <div class="widget-box align-left transparent"> <div class="widget-header"> <h4 class="lighter smaller">Tree element loading data from server <br /> pre-selecting some items randomly</h4> </div> <div class="widget-body"> <div class="widget-main padding-8"> <div id="treeview" class="tree"></div> <div class="hr"></div> <button id="submit-button" type="button" class="btn btn-sm btn-primary pull-right"> <i class="ace-icon fa fa-check"></i> Submit </button> </div> </div> </div> </div> </div> <div id="modal-tree-items" class="modal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h4 class="blue bigger">Treeview selection</h4> </div> <div class="modal-body"> <div class="row-fluid"> Content can be put inside a hidden input and sent to server </div> <div class="space-6"></div> <div class="row-fluid"> <textarea spellcheck="false" id="tree-value"></textarea> </div> </div> <div class="modal-footer"> <button class="btn btn-sm" data-dismiss="modal"><i class="ace-icon fa fa-times"></i> Cancel</button> <button class="btn btn-sm btn-primary"><i class="ace-icon fa fa-check"></i> OK</button> </div> </div> </div> </div> <!-- basic scripts --> <!--[if !IE]> --> <script src="~/Scripts/jquery-1.10.2.min.js"></script> <!-- <![endif]--> <!--[if IE]> <script type="text/javascript"> window.jQuery || document.write("<script src=‘../assets/js/jquery-1.10.2.min.js‘>"+"<"+"/script>"); </script> <![endif]--> <script src="~/Assets/Ace1.3/js/fuelux/data/fuelux.tree-sample-demo-data.js"></script> <script src="~/Assets/Ace1.3/js/bootstrap.min.js"></script> <script src="~/Assets/Ace1.3/js/fuelux/fuelux.tree.min.js"></script> <!-- ace scripts --> <script src="~/Assets/Ace1.3/js/ace.min.js"></script> <script src="~/Assets/Ace1.3/js/ace-elements.min.js"></script> <script type="text/javascript"> $(function () { var tree_data1 = getTreeData(); console.log(tree_data1); var treeDataSource = new DataSourceTree({ data: tree_data1 }); $(‘#treeview‘).ace_tree({ dataSource: treeDataSource, loadingHTML: ‘<div class="tree-loading"><i class="ace-icon fa fa-refresh fa-spin blue"></i></div>‘, ‘open-icon‘: ‘tree-minus‘, ‘close-icon‘: ‘tree-plus‘, ‘selectable‘: true, ‘selected-icon‘: ‘ace-icon fa fa-check‘, ‘unselected-icon‘: ‘ace-icon fa fa-times‘ }); $(‘#tree-selected-items‘).on(‘click‘, function () { console.log("selected items: ", $(‘#treeview‘).tree(‘selectedItems‘)); }); $(‘#treeview‘).on(‘selected‘, function (evt, data) { console.log(‘item selected: ‘, data); }); //show selected items inside a modal $(‘#submit-button‘).on(‘click‘, function () { var tree = $(‘#treeview‘).data(‘tree‘); var output = ‘‘; var items = tree.selectedItems(); for (var i in items) if (items.hasOwnProperty(i)) { var item = items[i]; //output += item.additionalParameters[‘id‘] + ":"+ item.name+"\n"; output += item.name + "\n"; } $(‘#modal-tree-items‘).modal(‘show‘); $(‘#tree-value‘).css({ ‘width‘: ‘98%‘, ‘height‘: ‘200px‘ }).val(output); }); if (location.protocol == ‘file:‘) alert("For retrieving data from server, you should access this page using a webserver."); }); function getTreeData() { var returnvalue; $.ajax({ type: ‘POST‘, url: "/Admins/AceTree/GetTreeData", async: false, dataType: "json", success: function (result) { if (result.status == "OK") { returnvalue = result.data; } } }); return returnvalue; } </script>
值得提醒的是,DataSourceTree的定义,来源于example包中,
好了,最终动态绑定已经实现,界面如下
当然,这里主要是将实现功能,美化需要进一步完善。
吐槽:
实际上树形功能和别的插件差不多,只是格式有点奇怪,所以这个也算是使用过的"最差"的一个树形插件,
不过还是因为其友好的UI,选择了坚持使用。
今年的七夕情人节已经来临,在此祝天下有情人终成眷属!
参考资料:
https://www.iteblog.com/ace/treeview.html
http://www.cnblogs.com/zgz21/p/5166871.html