使用D3构建数据驱动侧边导航遇报错:无法处理嵌套数据
解决D3数据驱动侧边导航的嵌套数据问题
错误原因分析
你遇到的Uncaught TypeError: undefined is not iterable错误主要来自三个问题:
- 拼写错误:数据里的嵌套字段是
hasPages,但代码里写成了d.hasItems,导致取到undefined - 逻辑错误:给所有侧边栏项都添加了下拉容器,包括没有子页面的
Notifications和Messages - 结构错误:下拉菜单(
ul.sidebar-dropdown)应该作为li.sidebar-item的子元素,而不是嵌套在<a>标签里
修正后的完整代码
const sidenavData = [ { 'name': 'Header name 1', 'type': 'header' }, { 'name': 'Menu item 1', 'type': 'item', 'hasPages': [ { 'name': 'Page 1' }, { 'name': 'Page 2' }, ] }, { 'name': 'Menu item 2', 'type': 'item', 'hasPages': [ { 'name': 'Report 1' }, { 'name': 'Report 2' }, { 'name': 'Report 3' }, ] }, { 'name': 'Header name 2', 'type': 'header' }, { 'name': 'Notifications', 'type': 'item' }, { 'name': 'Messages', 'type': 'item' }, ]; // 选择顶层导航容器 var nav = d3.select('ul.sidebar-nav'); // 创建顶层li元素(包含header和item) const topLevelItems = nav .selectAll('li') .data(sidenavData) .enter() .append('li') .attr('class', d => d.type === 'header' ? 'sidebar-header' : 'sidebar-item'); // 处理header的文本 topLevelItems.filter(d => d.type === 'header') .text(d => d.name); // 处理普通item:添加a标签 const sidebarItems = topLevelItems.filter(d => d.type === 'item') .append('a') .attr('class', 'sidebar-link') .text(d => d.name); // 处理有子页面的item:添加下拉菜单 sidebarItems.filter(d => d.hasPages) // 回到父元素li,添加下拉ul .each(function(d) { d3.select(this.parentNode) .append('ul') .attr('class', 'sidebar-dropdown') .selectAll('li') .data(d.hasPages) .enter() .append('li') .attr('class', 'sidebar-item') .append('a') .attr('class', 'sidebar-link') .text(page => page.name); });
关键修正点说明
- 字段名修正:把
d.hasItems改为d.hasPages,匹配数据结构 - 条件渲染下拉:通过
filter(d => d.hasPages)只给有子页面的项添加下拉容器 - 修正DOM结构:使用
this.parentNode回到父级li元素,将下拉ul作为li的子元素,符合期望的HTML结构 - 分层处理元素:拆分顶层元素、header、普通item、下拉菜单的创建逻辑,让代码更清晰
内容的提问来源于stack exchange,提问作者Rob Wissink
相关产品推荐
相关产品推荐

