动态水平导航栏,当这些导航项目正常换行时,导航项目“溢出”到“更多”下拉列表中

问题描述 投票:0回答:1

我正在尝试修改这个小提琴https://jsfiddle.net/xobea9cm/,因为它几乎具有我所追求的确切功能,除了html的语义不是很好。

简而言之,我想要像这样的水平导航

|header and hero                                 |
|nav item 1   nav item 2    nav item 3   MORE v  |
|body copy                                       |

在“更多”中将有“导航项 4”和“导航项 5”。它会随着屏幕尺寸的变化而变化。当您减小浏览器宽度时,“导航项 3”将移至“更多”,当您增加浏览器宽度时,当水平空间允许时,“更多”中的导航项将流出。

原始版本的 html 是“divitus”,看起来像:

<nav class="nav">
    <div id="menu" class="menu">
        <div class="menuitem">One</div>
        <div class="menuitem">Two</div>
        <div class="menuitem">Three</div>
        <div class="menuitem">Four</div>
        <div class="menuitem">Five</div>
        <div class="menuitem">Six</div>
        
        <div class="more-items">
            <div id="more" class="more-item menuitem">More</div>
            <div class="menuitem">Seven</div>
            <div class="menuitem">Eight</div>
            <div class="menuitem">Nine</div>
        </div>
    </div>
</nav>

我的版本在这里:https://jsfiddle.net/oywkdr6e/我的html当前看起来像:

<nav class="nav-more">
    <ul class="nav-more-menu">
        <li class="nav-more-menu-item">nav item one</li>
        <li class="nav-more-menu-item"><a href="#two">nav item two</a></li>
        <li class="nav-more-menu-item"><a href="#three">nav item three</a></li>
        <li class="nav-more-menu-item"><a href="#four">nav item four</a></li>
        <li class="nav-more-menu-item"><a href="#five">nav item five</a></li>
        <li class="nav-more-menu-item"><a href="#six">nav item six</a></li>
        
        <li class="more">
            <!--THIS IS WHAT I'M TRYING TO CHANGE-->
            <li class="more-trigger nav-more-menu-item">More</li>
            <li class="nav-more-menu-item"><a href="#seven">nav item seven</a></li>
            <li class="nav-more-menu-item"><a href="#eight">nav item eight</a></li>
        </li>
    </ul>
</nav>

我想要的是这个:

<nav class="nav-more">
    <ul class="nav-more-menu">
        <li class="nav-more-menu-item">nav item one</li>
        <li class="nav-more-menu-item"><a href="#two">nav item two</a></li>
        <li class="nav-more-menu-item"><a href="#three">nav item three</a></li>
        <li class="nav-more-menu-item"><a href="#four">nav item four</a></li>
        <li class="nav-more-menu-item"><a href="#five">nav item five</a></li>
        <li class="nav-more-menu-item"><a href="#six">nav item six</a></li>
        
        <li class="more">
            <!--THIS IS WHAT I WANT-->
            <button class="more-trigger">More</button>
            <ul class="more-items">
                <li class="nav-more-menu-item"><a href="#seven">nav item seven</a></li>
                <li class="nav-more-menu-item"><a href="#eight">nav item eight</a></li>
            </ul>
        </li>
    </ul>
</nav>

当前的功能在悬停在

<li class="more">
上时显示“更多”菜单,但我最终希望在按钮触发器上可以使用该菜单以实现可访问性,因此我只需显示/隐藏该按钮的同级
<ul class="more-items">
并将其定位为下拉菜单。

我已经尝试了几次更新 JS 以使用新的标记,但我似乎总是在同一个地方结束。在页面加载时,它看起来不错,但是当我调整浏览器宽度时,我的 DOM 会在每个调整大小事件上附加

<ul class="more-items">

如何修复此问题以输出所需的标记?更新 DOM 时我没有得到一些东西。这是JS:

const parser = new DOMParser();

function dealWithMenu(navMoreMenu) {
  //console.log('dealWithMenu()');
  let navLIs = navMoreMenu.querySelectorAll('li');
  let moreLI = parser.parseFromString('<li class="more"></li>', 'text/html').body.firstChild;
  //console.log('navLIs:', navLIs);
  //console.log('moreLI:', moreLI);
  //console.log('navMoreMenu:', navMoreMenu);

  let count = 0;

  for (var i = navLIs.length; i--;) {
    let $this = navLIs[i];

    //show at least two nav items
    if (count >= navLIs.length - 2) {
      continue;
    }

    //if trailing nav item offsetTop value is different than first nav item, trailing nav item has wrapped to a new line, so move into "more" dropdown
    if ($this.offsetTop > navLIs[0].offsetTop || moreLI.offsetTop > navLIs[0].offsetTop) {
      navMoreMenu.appendChild(moreLI);
      moreLI.insertBefore($this, moreLI.firstChild);
      count++;
    } else {
      i = 0;
    }
  }

  //we have overflow nav items in "more" dropdown
  if (moreLI.children.length) {
    console.log('moreLI.children.length', moreLI.children.length);
    moreLI.insertBefore(
      parser.parseFromString('<li class="more-trigger nav-more-menu-item">More</li>', 'text/html').body.firstChild,
      moreLI.firstChild
    );
  }

  moreLI.addEventListener('click', (e) => {
    console.log('more click:', e.target);
  });
}

function shorterMenu() {
  //console.log('shorterMenu()');
  const navMoreMenu = document.querySelector('.nav-more-menu');
  const moreLI = navMoreMenu.querySelector('.more');
  const moreTrigger = navMoreMenu.querySelector('.more-trigger');
  //console.log('moreLI:', moreLI);
  //console.log('moreTrigger:', moreTrigger);

  moreTrigger?.remove();    

  if (moreLI != undefined && moreLI.children?.length > 0) {
    Array.from(moreLI.children).forEach(child => moreLI.parentElement.appendChild(child));
    moreLI.remove();
  }

  dealWithMenu(navMoreMenu);
}

shorterMenu();
window.addEventListener('resize', () => shorterMenu());
javascript dom drop-down-menu navigation appendchild
1个回答
0
投票

dealWithMenu()

  • 添加更多
    <ul>
    并获取对其的引用:
    let moreLI = parser.parseFromString('<li class="more"><ul class="more-items"></ul></li>', 'text/html').body.firstChild;
    const [moreList] = moreLI.children;
    
  • for
    navLIs
    循环中,将溢出元素追加到
    moreList
    中:
    moreList.appendChild($this);
    
  • 修改 DOM 的逻辑基于
    moreList
    if (moreList.children.length) {
      console.log('moreLI.children.length', moreList.children.length);
    
  • 将触发元素更改为所需的
    <button>
    元素:
    moreLI.insertBefore(
      parser.parseFromString('<button class="more-trigger">More</button>', 'text/html').body.firstChild,
      moreLI.firstChild
    );
    

shorterMenu()

  • 获取更多菜单中
    <li>
    元素的列表:
    const moreLI = navMoreMenu.querySelector('.more');
    const moreElements = moreLI?.querySelectorAll('li');
    
  • 有条件地向后移动
    <li>
    元素并根据
    moreLI
    变量删除
    moreElements
    if (moreLI != undefined && moreElements?.length > 0) {
      moreElements.forEach(child => navMoreMenu.appendChild(child));
      moreLI.remove();
    }
    

const parser = new DOMParser();

function dealWithMenu(navMoreMenu) {
  //console.log('dealWithMenu()');
  let navLIs = navMoreMenu.querySelectorAll('li');
  let moreLI = parser.parseFromString('<li class="more"><ul class="more-items"></ul></li>', 'text/html').body.firstChild;
  const [moreList] = moreLI.children;
  //console.log('navLIs:', navLIs);
  //console.log('moreLI:', moreLI);
  //console.log('navMoreMenu:', navMoreMenu);

  let count = 0;

  for (var i = navLIs.length; i--;) {
    let $this = navLIs[i];

    //show at least two nav items
    if (count >= navLIs.length - 2) {
      continue;
    }

    //if trailing nav item offsetTop value is different than first nav item, trailing nav item has wrapped to a new line, so move into "more" dropdown
    if ($this.offsetTop > navLIs[0].offsetTop || moreLI.offsetTop > navLIs[0].offsetTop) {
      navMoreMenu.appendChild(moreLI);
      moreList.appendChild($this);
      count++;
    } else {
      i = 0;
    }
  }

  //we have overflow nav items in "more" dropdown
  if (moreList.children.length) {
    console.log('moreLI.children.length', moreList.children.length);
    moreLI.insertBefore(
      parser.parseFromString('<button class="more-trigger">More</button>', 'text/html').body.firstChild,
      moreLI.firstChild
    );
  }

  moreLI.addEventListener('click', (e) => {
    console.log('more click:', e.target);
  });
}

function shorterMenu() {
  //console.log('shorterMenu()');
  const navMoreMenu = document.querySelector('.nav-more-menu');
  const moreLI = navMoreMenu.querySelector('.more');
  const moreElements = moreLI?.querySelectorAll('li');
  const moreTrigger = navMoreMenu.querySelector('.more-trigger');
  //console.log('moreLI:', moreLI);
  //console.log('moreTrigger:', moreTrigger);

  moreTrigger?.remove();    

  if (moreLI != undefined && moreElements?.length > 0) {
    moreElements.forEach(child => navMoreMenu.appendChild(child));
    moreLI.remove();
  }

  dealWithMenu(navMoreMenu);
}

shorterMenu();
window.addEventListener('resize', () => shorterMenu());
html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: #ccc;
}

header {
  background: #fff;
  height: 100px;
  width: 100%;
  position: fixed;
  top: 0;
  border: 2px solid red;
  z-index: 10;
}

header,
.hero {
  display: flex;
}

header p,
.hero p {
  margin: auto;
}

.hero {
  background: #999;
  width: 100%;
  height: 300px;
}

main {
  border: 2px solid blue;
  background: #fff;
  height: 2000px;
  max-width: 1200px;
  margin: 100px auto 2rem auto;
}


.nav-more {
  border: 1px solid red;
  background: #efefef;
  padding: 1.5rem 6rem;
  position: sticky;
  top: 100px;
  display: flex;
}

.nav-more-menu {
  border: 1px solid blue;
  display: inline-flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-more-menu-item {
  /*border: 1px solid white;*/
  /*background: black;*/
  /*color: white;*/
  padding: 5px 10px;
}

.nav-more-menu-item a {
  /*color: white;*/
}


.more {
  background: dodgerblue;
  color: white;
  max-width: 200px;
}

.more:hover {
  background: deepskyblue;
}

.more li {
  display: none;
}

.more li:first-of-type {
  display: block;
  cursor: pointer;
}

.more:hover>li {
  display: block;
}
<header><p>fixed header</p></header>
        
<main>
  <div class="hero"><p>hero</p></div>

  <nav class="nav-more">
    <ul class="nav-more-menu">
      <li class="nav-more-menu-item">nav item one</li>
      <li class="nav-more-menu-item"><a href="#two">nav item two</a></li>
      <li class="nav-more-menu-item"><a href="#three">nav item three</a></li>
      <li class="nav-more-menu-item"><a href="#four">nav item four</a></li>
      <li class="nav-more-menu-item"><a href="#five">nav item five</a></li>
      <li class="nav-more-menu-item"><a href="#six">nav item six</a></li>
      <li class="nav-more-menu-item"><a href="#seven">nav item seven</a></li>
      <li class="nav-more-menu-item"><a href="#eight">nav item eight</a></li>
    </ul>
  </nav>

  <div style="padding:0 6rem;">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

    <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur.</p>

    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

    <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur.</p>
  </div>
</main>

© www.soinside.com 2019 - 2024. All rights reserved.