2011-08-20 174 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/