javascript 如何使用带有父子关系的 JSON 数据创建带有复选框的树?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26827276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to create Tree with checkboxes using JSON data with Parent Child Relation?
提问by Deep Shah
I have JSON data and that JSON data has parent child relation . I Want to create tree structure from it. i found many plugins and libraries but i can't found my requirement . I am getting this JSON data using PHP script.
我有 JSON 数据并且该 JSON 数据具有父子关系。我想从中创建树结构。我找到了很多插件和库,但找不到我的要求。我正在使用 PHP 脚本获取此 JSON 数据。
Here is image that has tree structure that i want to create . i'm stuck at it.I know JSON is not as displayed in image but i only want to show you what a tree should look like .How to create tree like in image.All i want is javascript code to handle and create this type of structure of tree . Working example is must & much appreciated.
这是我想要创建的具有树结构的图像。我被困住了。我知道 JSON 不像图像中显示的那样,但我只想向您展示树应该是什么样子。如何像图像中那样创建树。我想要的是处理和创建这种类型的 javascript 代码树的结构。工作示例是必须的,非常感谢。
You can use JSON format as you like and tree should be collapsible.Also provide required JSON format for it.
您可以随意使用 JSON 格式,并且树应该是可折叠的。同时为其提供所需的 JSON 格式。
and my JSON data as follows :
和我的 JSON 数据如下:
{
"2":
{
"5": "Wrist Watch"
},
"5":
{
"9": "Men's"
},
"18":
{
"3": "Clothing"
},
"28":
{
"1": "Perfumes"
},
"29":
{
"7": "Laptop",
"10": "Tablets"
},
"30":
{
"8": "Mobile"
},
"31":
{
"2": "Books"
},
"33":
{
"6": "Electronics"
},
"34":
{
"4": "Home & Kitchen\n"
}
}
回答by Gone Coding
If you want to roll your own, the keyword in "trees" is recursion. It needs to support any depth of data and the code and data should bothsupport recursion.
如果你想自己滚动,“trees”中的关键字是recursion。它需要支持数据的任何深度和代码和数据应该都支持递归。
This means your JSON data should be a recursive structure, where each node looks the same (and looks something like this):
这意味着您的 JSON 数据应该是一个递归结构,其中每个节点看起来都一样(看起来像这样):
{
id: 1, // data id
title: "title", // display title
children: [ // list of children, each with this same structure
// list of child nodes
]
}
Note: I have changed the sample data to contain more depth as 2 levels never shows up recursion problems.
注意:我已更改示例数据以包含更多深度,因为 2 个级别从未出现递归问题。
e.g.:
例如:
{
id: 0,
title: "root - not displayed",
children: [{
id: 1,
title: "Option 1",
children: [{
id: 11,
title: "Option 11",
children: [{
id: 111,
title: "Option 111"
}, {
id: 112,
title: "Option 112"
}]
}, {
id: 12,
title: "Option 12"
}]
}, {
id: 2,
title: "Option 2",
children: [{
id: 21,
title: "Option 21"
}, {
id: 22,
title: "Option 22"
}]
}, {
id: 3,
title: "Option 3",
children: [{
id: 31,
title: "Option 31"
}, {
id: 32,
title: "Option 32"
}]
}]
}
The recursive function looks like this:
递归函数如下所示:
function addItem(parentUL, branch) {
for (var key in branch.children) {
var item = branch.children[key];
$item = $('<li>', {
id: "item" + item.id
});
$item.append($('<input>', {
type: "checkbox",
name: "item" + item.id
}));
$item.append($('<label>', {
for: "item" + item.id,
text: item.title
}));
parentUL.append($item);
if (item.children) {
var $ul = $('<ul>').appendTo($item);
addItem($ul, item);
}
}
}
JSFiddle:http://jsfiddle.net/0s0p3716/188/
JSFiddle:http : //jsfiddle.net/0s0p3716/188/
The code recurses the structure, adding new ULs and LIs (with checkbox etc ) as it goes. The top level call just provides the initial root starting points of both the display and the data.
代码递归结构,添加新的 UL 和 LI(带有复选框等)。顶层调用只提供显示和数据的初始根起点。
addItem($('#root'), data);
The end result looks like this:
最终结果如下所示:
If you want to toggle visibility, based on the checked state, use this:
如果要根据选中状态切换可见性,请使用以下命令:
$(':checkbox').change(function () {
$(this).closest('li').children('ul').slideToggle();
});
If you also want the labels to toggle the checkboxes, use this:
如果您还希望标签切换复选框,请使用以下命令:
$('label').click(function(){
$(this).closest('li').find(':checkbox').trigger('click');
});
Note: I have only provided the most basic of styling as that will typically be "to taste". Examples in links were shown in another answer.
注意:我只提供了最基本的样式,因为这通常是“品尝”。链接中的示例显示在另一个答案中。
-- updated:
- 更新:
amended: possible wrong ids for items 31 & 32?
修正:项目 31 和 32 的 ID 可能有误?
function for better selection and deselection(for parents cascading into child nodes):
更好的选择和取消选择的功能(对于级联到子节点的父节点):
$(function () {
addItem($('#root'), data);
$(':checkbox').click(function () {
$(this).find(':checkbox').trigger('click');
var matchingId = $(this).attr('id');
if ($(this).attr('checked'))
{
$('input[id*=' + matchingId +']').each(function() {
$(this).removeAttr('checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
else {
$('input[id*=' + matchingId +']').each(function() {
$(this).attr('checked', 'checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
});
$('label').click(function(){
$(this).closest('li').children('ul').slideToggle();
});
-- Update the fiddle with this as shown here(JsFiddle) and it will work better and also will allow you to click the text to expand without selecting at the same time - I know I find this far more useful. It will help (and this is personal preference) you to see what values and options are available without having to select the first.
-- 用这里显示的(JsFiddle)更新小提琴,它会更好地工作,并且还允许您单击文本以展开而不同时选择-我知道我发现这更有用。这将有助于(这是个人偏好)您无需选择第一个即可查看可用的值和选项。
回答by Wladimir Palant
The thing with programming is: existing libraries and tools rarely do exactly what you need. It's always up to you to convert the input data into exactly the format they expect and then the output data into the format you need. Occasionally this conversion requires more effort than writing your own code instead of a library function - this seems to be one of those occasions.
编程的问题是:现有的库和工具很少能完全满足您的需求。您始终可以将输入数据完全转换为他们期望的格式,然后将输出数据转换为您需要的格式。有时,这种转换比编写自己的代码而不是库函数需要更多的努力——这似乎是其中一种情况。
As @philosophocat already noted, the best way to present such a tree in HTML markup would be nested lists. All you need is iterate through the JSON data recursively and create the corresponding elements:
正如@philosophocat 已经指出的那样,在 HTML 标记中呈现这种树的最佳方式是嵌套列表。您只需要递归遍历 JSON 数据并创建相应的元素:
function createList(data)
{
var result = document.createElement("ul");
for (var key in data)
{
if (!data.hasOwnProperty(key) || key == "_title")
continue;
var value = data[key];
var item = createItem(key, typeof value == "string" ? value : value._title);
if (typeof value == "object")
item.appendChild(createList(value));
result.appendChild(item);
}
return result;
}
function createItem(value, title)
{
var result = document.createElement("li");
var checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("name", "selection");
checkbox.setAttribute("value", value);
result.appendChild(checkbox);
result.appendChild(document.createTextNode(title));
return result;
}
document.body.appendChild(createList(jsonData));
Note that the order in which the items appear is "random" here, as object keys are generally unordered. You can change the code above to sort the keys somehow, or you can change the data to use arrays and define an order. I also added a "_title"
property to the data to make sure the categories are labeled - your data doesn't have any labels at all for the categories.
请注意,项目出现的顺序在这里是“随机的”,因为对象键通常是无序的。您可以更改上面的代码以某种方式对键进行排序,或者您可以更改数据以使用数组并定义顺序。我还向"_title"
数据添加了一个属性,以确保对类别进行标记 - 您的数据根本没有任何类别标签。
Now you need to style the lists in such a way that they look like a tree. The obvious solution is using the list-style-image
CSS propertyto replace the usual bullet points by a grid lines image. However, that doesn't work for nested lists - there you need to show multiple images, vertical lines from the higher-level lists as well as the image actually belonging to the current list item.
现在您需要以一种看起来像一棵树的方式设置列表的样式。显而易见的解决方案是使用list-style-image
CSS 属性将常用的项目符号替换为网格线图像。但是,这不适用于嵌套列表 - 您需要显示多个图像、来自更高级别列表的垂直线以及实际属于当前列表项的图像。
This can be solved by using background images for the list items instead, these background images will be shown next to sublists as well then. Here are the example styles I've got:
这可以通过使用列表项的背景图像来解决,这些背景图像也将显示在子列表旁边。以下是我的示例样式:
ul
{
padding: 0;
list-style-type: none;
font-size: 14px;
}
li
{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAABkCAYAAABdELruAAAAP0lEQVR42u3PQQoAIAgEQP3/o6t7JAhdolkQD4sMZuwZazKKlGXniHRDOu6HfyKRSCQSiUQikUgkEolEIv0rTc/fNmQ78+lPAAAAAElFTkSuQmCC);
background-repeat: no-repeat;
padding-left: 13px;
}
li:last-child
{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAHUlEQVR42mNkwAT/gZiRAQ/AK0mKplGbqGETThoACFgJCVdBEqAAAAAASUVORK5CYII=);
}
li > ul
{
margin-left: 5px;
}
Note that this will still get ugly if the sublist is too high - the height of the background image I used is merely 100px. This can be solved by using a larger background image of course. A cleaner alternative would be using border-image-slice
CSS propertybut that one is currently only supported in Firefox.
请注意,如果子列表太高,这仍然会变得丑陋 - 我使用的背景图像的高度仅为 100 像素。这当然可以通过使用更大的背景图像来解决。一种更简洁的替代方法是使用border-image-slice
CSS 属性,但目前仅在 Firefox 中支持该属性。
Edit: This articlegoes into more detail on styling nested lists like a tree. While the approach is similar, it manages to avoid the image size issues I mentioned above by using a separate image for the vertical line which can be repeated vertically. On the downside, that approach looks like it might only work with solid lines and produce artifacts if applied to dotted lines.
编辑:本文更详细地介绍了像树一样设置嵌套列表的样式。虽然该方法类似,但它通过为垂直线使用单独的图像(可以垂直重复)来避免我上面提到的图像大小问题。不利的一面是,这种方法看起来可能只适用于实线,如果应用于虚线,则会产生伪影。
回答by Qullbrune
Use http://www.jstree.com/. This library provides each function I ever need when working with trees and javascript.
使用http://www.jstree.com/。这个库提供了我在使用树和 javascript 时需要的每个功能。
You simple have to change your json-response according to the given format (http://www.jstree.com/docs/json/):
您只需根据给定的格式(http://www.jstree.com/docs/json/)更改您的 json 响应:
{
id : "string" // will be autogenerated if omitted
text : "string" // node text
icon : "string" // string for custom
state : {
opened : boolean // is the node open
disabled : boolean // is the node disabled
selected : boolean // is the node selected
},
children : [] // array of strings or objects
li_attr : {} // attributes for the generated LI node
a_attr : {} // attributes for the generated A node
}
Set up the javascript and include all required files and there you go. I just skip repeating the documentation by referring to it: http://www.jstree.com/
设置 javascript 并包含所有必需的文件,然后就可以了。我只是通过引用它来跳过重复文档:http: //www.jstree.com/
回答by sbonkosky
I'm using DynaTree for an internal site at work and it works fantastic.
我正在将 DynaTree 用于工作中的内部站点,它的效果非常好。
- Download DynaTree
- Format your JSON as such (taking your screenshot as an example):
- 下载动态树
- 格式化您的 JSON(以您的屏幕截图为例):
{ "title": "Sports & Outdoors", "isFolder": true, "key": "0", "children": [ { "title": "Fitness Accessories", "key": "1", "isFolder": true, "children": [ { "title": "Fitness Accessories", "key": "2", "isFolder": true, "children": [ { "title": "Pedometer & Watches", "key": "3" } ] } ] } ] }
- Run this JS on page load:
- 在页面加载时运行此 JS:
$("#buildTree").dynatree({ onActivate: function (node) { // A DynaTreeNode object is passed to the activation handler // Note: we also get this event, if persistence is on, and the page is reloaded. leftActiveNodeKey = node.data.key; }, persist: false, checkbox: true, selectMode: 3, children: $.parseJSON(response.d) });
To get the selected nodes you can use:
var selectedNodes = $("#buildTree").dynatree("getTree").getSelectedNodes();
要获取所选节点,您可以使用:
var selectedNodes = $("#buildTree").dynatree("getTree").getSelectedNodes();
Dynatree is pretty customization, both in look and function. Read through the documentation for the settings you need.
Dynatree 在外观和功能上都是非常定制化的。通读文档以了解您需要的设置。
回答by Raphael
Check these sites.Hope this helps.
检查这些网站。希望这会有所帮助。
http://www.jstree.com/docs/json/
http://www.jstree.com/docs/json/
http://www.jeasyui.com/documentation/tree.php
http://www.jeasyui.com/documentation/tree.php
http://jqwidgets.com/jquery-widgets-demo/demos/jqxtree/index.htm#demos/jqxtree/checkboxes.htm
http://jqwidgets.com/jquery-widgets-demo/demos/jqxtree/index.htm#demos/jqxtree/checkboxes.htm
回答by CAtoOH
@Gone Coding's example is excellent, but the child check boxes will not show as 'uncheked' even though the checked attribute is removed, as rendered in Chrome. If you add,
@Gone Coding 的示例非常出色,但即使在 Chrome 中呈现的已选中属性已被删除,子复选框也不会显示为“未选中”。如果添加,
$(this).prop('checked', false);
to the code, so it reads as
到代码,所以它读作
$(function () {
addItem($('#root'), data);
$(':checkbox').click(function () {
var matchingId = $(this).attr('id');
if ($(this).attr('checked'))
{
$('input[id*=' + matchingId +']').each(function() {
$(this).removeAttr('checked');
$(this).prop('checked', false);
$(this).prop('checked', $(this).attr('checked'));
return;
});
}
else {
$('input[id*=' + matchingId +']').each(function() {
$(this).attr('checked', 'checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
});
$('label').click(function(){
$(this).closest('li').children('ul').slideToggle();
});
});
the child check boxes will fill or clear when the user makes a change.
当用户进行更改时,子复选框将填充或清除。