2011-08-20 220 views
6

我的菜单项的数组,每个都包含名称和URL这样的URL路径结构嵌套UL菜单:创建基于菜单项

var menuItems = [ 
    { 
     name : "Store", 
     url : "/store" 
    }, 
    { 
     name : "Travel", 
     url : "/store/travel" 
    }, 
    { 
     name : "Gardening", 
     url : "/store/gardening" 
    }, 
    { 
     name : "Healthy Eating", 
     url : "/store/healthy-eating" 
    }, 
    { 
     name : "Cook Books", 
     url : "/store/healthy-eating/cook-books" 
    }, 
    { 
     name : "Single Meal Gifts", 
     url : "/store/healthy-eating/single-meal-gifts" 
    }, 
    { 
     name : "Outdoor Recreation", 
     url : "/store/outdoor-recreation" 
    }, 
    { 
     name : "Hiking", 
     url : "/store/outdoor-recreation/hiking" 
    }, 
    { 
     name : "Snowshoeing", 
     url : "/store/outdoor-recreation/hiking/snowshoeing" 
    }, 
    { 
     name : "Skiing", 
     url : "/store/outdoor-recreation/skiing" 
    }, 
    { 
     name : "Physical Fitness", 
     url : "/store/physical-fitness" 
    }, 
    { 
     name : "Provident Living", 
     url : "/store/provident-living" 
    } 
] 

我一直没有成功试图渲染这是一个嵌套的UL结构后面的URL路径结构,像这样一个无序列表:

<ul> 
    <li><a href="/store">Store</a> 
     <ul> 
     <li><a href="/store/travel">Travel</a></li> 
     <li><a href="/store/gardening">Gardening</a></li> 
     <li><a href="/store/healthy-eating">Healthy Eating</a> 
      <ul> 
      <li><a href="/store/healthy-eating/cook-books">Cook Books</a></li> 
      <li><a href="/store/healthy-eating/single-meal-gifts">Single Meal Gifts</a></li> 
      </ul> 
     </li> 
     <li><a href="/store/outdoor-recreation">Outdoor Recreation</a> 
      <ul> 
      <li><a href="/store/outdoor-recreation/hiking">Hiking</a> 
       <ul> 
       <li><a href="/store/outdoor-recreation/hiking/snowshoeing">Snowshoeing</a></li> 
       </ul> 
      </li> 
      <li><a href="/store/outdoor-recreation/skiing">Skiing</a></li> 
      </ul> 
     </li> 
     <li><a href="/store/physical-fitness">Physical Fitness</a></li> 
     <li><a href="/store/provident-living">Provident Living</a></li> 
     </ul> 
    </li> 
</ul> 

所有我见过有一个数据结构,反映了亲子关系(例如XML或开始实例JSON),但我有一个非常困难的时间拉出这个网址和使用它来呈现新的结构。

如果有人可以请指导我正确的方向使用jQuery如何做到这一点,我真的很感激它。我意识到我可能需要使用一些递归函数或jQuery模板,但这些东西对我来说还是有点新的。
谢谢

回答

6

我认为最好的办法是首先将你的数据结构转换为树中的一个,与父母/子女关系。由于UL本身具有树形结构,因此渲染此结构将更容易。

您可以使用这些夫妇的功能

// Add an item node in the tree, at the right position 
function addToTree(node, treeNodes) { 

    // Check if the item node should inserted in a subnode 
    for (var i=0; i<treeNodes.length; i++) { 
     var treeNode = treeNodes[i]; 

     // "/store/travel".indexOf('/store/') 
     if (node.url.indexOf(treeNode.url + '/') == 0) { 
      addToTree(node, treeNode.children); 

      // Item node was added, we can quit 
      return; 
     } 
    } 

    // Item node was not added to a subnode, so it's a sibling of these treeNodes 
    treeNodes.push({ 
     name: node.name, 
     url: node.url, 
     children: [] 
    }); 
} 

//Create the item tree starting from menuItems 
function createTree(nodes) { 
    var tree = []; 

    for (var i=0; i<nodes.length; i++) { 
     var node = nodes[i]; 
     addToTree(node, tree); 
    } 

    return tree; 
} 

var menuItemsTree = createTree(menuItems); 
console.log(menuItemsTree); 

转换的菜单项所得到的menuItemsTree会是这样

[ 
    { 
    "name":"Store", 
    "url":"/store", 
    "children":[ 
     { 
     "name":"Travel", 
     "url":"/store/travel", 
     "children":[ 

     ] 
     }, 
     { 
     "name":"Gardening", 
     "url":"/store/gardening", 
     "children":[ 

     ] 
     }, 
     { 
     "name":"Healthy Eating", 
     "url":"/store/healthy-eating", 
     "children":[ 
      { 
      "name":"Cook Books", 
      "url":"/store/healthy-eating/cook-books", 
      "children":[ 

      ] 
      }, 
      { 
      "name":"Single Meal Gifts", 
      "url":"/store/healthy-eating/single-meal-gifts", 
      "children":[ 

      ] 
      } 
     ] 
     }, 
     { 
     "name":"Outdoor Recreation", 
     "url":"/store/outdoor-recreation", 
     "children":[ 
      { 
      "name":"Hiking", 
      "url":"/store/outdoor-recreation/hiking", 
      "children":[ 
       { 
       "name":"Snowshoeing", 
       "url":"/store/outdoor-recreation/hiking/snowshoeing", 
       "children":[ 

       ] 
       } 
      ] 
      }, 
      { 
      "name":"Skiing", 
      "url":"/store/outdoor-recreation/skiing", 
      "children":[ 

      ] 
      } 
     ] 
     }, 
     { 
     "name":"Physical Fitness", 
     "url":"/store/physical-fitness", 
     "children":[ 

     ] 
     }, 
     { 
     "name":"Provident Living", 
     "url":"/store/provident-living", 
     "children":[ 

     ] 
     } 
    ] 
    } 
] 

你提到你已经有树木的HTML渲染器,右一个对象?如果您需要进一步帮助,请告诉我们!

+2

这工作得很好,但一个“例外”:如果有一个子节点没有定义父节点就会像父母/ mainnode添加。我不知道这是否是一种想要的副作用,但它可能是合理的。 – buschtoens

+0

对不起,但这不起作用,我试了几次你的代码。它适用于第一个节点,但当下一个兄弟节点中有子节点时,下一个兄弟节点的子节点将被添加到第一个节点的子节点列表中。 –

+0

@Davide,如何使用成形的HTML数据来渲染树?再次,递归函数 – 2017-08-23 08:04:21

0

尝试这样的事情。

function Directory(parentNode) { 
    //Structure for directories. Subdirectories container as a generic object, initially empty 
    this.hasSubdirectories = false; 
    this.subdirectories = {}; 

    //Render in steps. Until subdirectories or a link are added, all it needs is an LI and a blank anchor 
    this.nodeLi = document.createElement("li"); 
    parentNode.appendChild(this.nodeLi); 
    this.nodeA = document.createElement("a"); 
    this.nodeLi.appendChild(this.nodeA); 

    //if a subdirectory is added, this.nodeUl will be added at the same time. 
} 

Directory.prototype.setLabel = function (sLabel) { 
    this.nodeA.innerHTML = sLabel; 
} 

Directory.prototype.setLink = function (sLink) { 
    this.nodeA.href = sLink; 
} 

Directory.prototype.getSubdirectory = function (sPath) { 
    //if there were no previous subdirectories, the directory needs a new UL node. 
    if (!this.hasSubdirectories) { 
     this.nodeUl = document.createElement("ul"); 
     this.nodeLi.appendChild(this.nodeUl); 
     this.hasSubdirectories = true; 
    } 

    //split the path string into the base directory and the rest of the path. 
    var r = /^\/?(?:((?:\w|\s|\d)+)\/)(.*)$/; 
    var path = r.exec(sPath); 

    //if the desired path is in a subdirectory, find or create it in the subdirectories container. 

    var subDirName = path[1] || path[2]; 
    var subDir; 
    if (this.subdirectories[subDirName] === undefined) this.subdirectories[subDirName] = new Directory(this.nodeUl); 
    subDir = this.subdirectories[subDirName]; 

    if (path[1] && path[2]) { 
     return subDir.getSubdirectory(path[2]); 
    } else { 
     return subDir; 
    } 
} 

function main(whichNode, aMenuItems) { 
    //whichNode is the node that is to be the parent of the directory listing. 
    //aMenuItems is the array of menu items. 
    var i; 
    var l = aItems.length; 
    var topDir = new Directory(whichNode); 

    //for each menu item, add a directory and set its properties. 
    var dirToAdd; 
    for (i = 0; i < l; i++) { 
     dirToAdd = topDir.getSubdirectory(aMenuItems[i].url); 
     dirToAdd.setLabel(aMenuItems[i].name); 
     dirToAdd.setLink(aMenuItems[i].url); 
    } 

    //and that's it. 
} 

工作情况如何?

0

或许完整的jQuery插件http://jsfiddle.net/9FGRC/

(EDIT)

更新到以前的版本http://jsfiddle.net/9FGRC/1/

由于跳过此版本支持下列情况下

var menuItems = [ 
    { 
     name : "Store", 
     url : "/store" 
    }, 
    { 
     name : "Cook Books", 
     url : "/store/healthy-eating/cook-books" 
    }, 
    { 
     name : "Single Meal Gifts", 
     url : "/store/healthy-eating/single-meal-gifts" 
    } 
] 

{ 
     name : "Healthy Eating", 
     url : "/store/healthy-eating" 
    }, 

它会产生下面的HTML

<ul> 
    <li><a href="/store">Store</a> 
     <ul> 
      <li><a href="/store/healthy-eating/cook-books">Cook Books</a></li> 
      <li><a href="/store/healthy-eating/single-meal-gifts">Single Meal Gifts</a></li> 
     </ul> 
    </li> 
</ul> 

我想这不会是这样的,但可帮助别人的代码

2

12个简洁的线条:

var rootList = $("<ul>").appendTo("body"); 
var elements = {}; 
$.each(menuItems, function() { 
    var parent = elements[this.url.substr(0, this.url.lastIndexOf("/"))]; 
    var list = parent ? parent.next("ul") : rootList; 
    if (!list.length) { 
     list = $("<ul>").insertAfter(parent); 
    } 
    var item = $("<li>").appendTo(list); 
    $("<a>").attr("href", this.url).text(this.name).appendTo(item); 
    elements[this.url] = item; 
}); 

http://jsfiddle.net/gilly3/CJKgp/

2

尽管我喜欢gilly3的脚本,但脚本生成的列表与不同的el比最初询问的<li><ul>的嵌套嵌套。因此而不是


    <li><a href="/store">Store</a> 
    <ul> 
     <li><a href="/store/travel">Travel</a></li> 
     ... 
    </ul> 
    </li> 
它产生

    <li><a href="/store">Store</a> 
    </li> 
    <ul> 
     <li><a href="/store/travel">Travel</a></li> 
     ... 
    </ul>
这可能会导致工具或框架与这种生成菜单一起工作并产生带有动画的交互式菜单(例如superfish.js)不兼容。 所以我更新了12行脚本

var rootList = $("<ul>").appendTo("body"); 
var elements = {}; 
$.each(menuItems, function() { 
    var parent = elements[this.url.substr(0, this.url.lastIndexOf("/"))]; 
    var list = parent ? parent.children("ul") : rootList; 
    if (!list.length) { 
     list = $("<ul>").appendTo(parent); 
    } 
    var item = $("<li>").appendTo(list); 
    $("<a>").attr("href", this.url).text(this.name).appendTo(item); 
    elements[this.url] = item; 
}); 

http://jsfiddle.net/tomaton/NaU4E/