• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

使用JavaScript构建多级动画移动菜单

今天,我们将讨论如何在不使用任何库的情况下,仅使用纯 javascript 来创建三级深度滑动移动菜单。默认情况下,我们一打开菜单就会出现第一个。另外两个将根据要求以幻灯片动画形式出现。

准备好迎接另一个挑战了吗?

我们的多级菜单

检查下面笔上的菜单实现:

See the Pen  How to Build an Animated Multilevel Mobile Menu With JavaScript by Envato Tuts+ (@tutsplus)  on CodePen.

1.定义 html 标记

我们的移动菜单的标记将包含以下元素:

  • 一个里面 header有一个。nav

  • 我们页面的main主要内容所在的位置。

在 里面nav,我们会放两个divs。第一个将有header-bar课程,而第二个将有menu-wrapper一个。

遗嘱包括.header-bar三个要素:

  • 切换菜单

  • 公司标志

  • 该公司的推特账号

在 中.menu-wrapper,我们将div在类中放置三个 s list-wrapper。为简单起见,我们将它们称为面板。注意事项:

  • 在第一个面板中,我们将指定包含父菜单项和子菜单项的菜单结构。为此,我们将使用带有嵌套无序列表的典型标记。

  • 第二个和第三个面板将包含一个后退按钮和一个空div的sub-menu-wrapper. 更多关于他们的工作:

    • 后退按钮将帮助我们上一层楼。也就是说,从三级到二级,从二级到一级。

    • 第二.sub-menu-wrapper个面板的 将包含第二级链接。同理,.sub-menu-wrapper第三个面板的 将保存第三级链接。我们将通过 JavaScript 动态插入这些链接。

考虑到以上所有内容,出现以下标记:


<header class="page-header">

  <nav>

    <div class="header-bar">

      <button class="toggle-menu" type="button">

        MENU

      </button>

      <a href="" class="brand">BRAND</a>

      <a href="" class="social" target="_blank" title="">

        <svg xmlns="https://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">

          <path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z" />

        </svg>

      </a>

    </div>

    <div class="menu-wrapper">

      <div class="list-wrapper">

        <ul class="menu level-1">

          <li>

            <a href="" class="nested">Categories </a>

            <ul class="sub-menu level-2">

              <li>

                <a href="" class="nested">Living Room </a>

                <ul class="sub-menu level-3">...</ul>

              </li>

              <li>

                <a href="">Dining Room</a>

              </li>

              ...

            </ul>

          </li>

          <li>

            <a href="" class="nested">Featured Products</a>

            <ul class="sub-menu level-2">...</ul>

          </li>

          ...

        </ul>

      </div>

      <div class="list-wrapper">

        <button type="button" class="back-one-level">

          <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">

            <path d="M16.67 0l2.83 2.829-9.339 9.175 9.339 9.167-2.83 2.829-12.17-11.996z" />

          </svg>

          <span>Back</span>

        </button>

        <div class="sub-menu-wrapper"></div>

      </div>

      <div class="list-wrapper">

        <button type="button" class="back-one-level">

          <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">

            <path d="M16.67 0l2.83 2.829-9.339 9.175 9.339 9.167-2.83 2.829-12.17-11.996z" />

          </svg>

          <span>Back</span>

        </button>

        <div class="sub-menu-wrapper"></div>

      </div>

    </div>

  </nav>

</header>

 

<main class="page-main">...</main>

2.指定主要样式

现在让我们专注于移动菜单的标题样式。

为简单起见,我不会介绍所有样式,但可以通过单击演示项目的 css 选项卡随意查看它们。

需要注意的一些事项:

  • 标题将是一个固定定位的元素,最大宽度为 600 像素。

  • 将.header-bar具有 60px 的固定高度。

  • 将.menu-wrapper绝对定位并位于.header-bar. 此外,它将具有等于视口高度减去.header-bar' 高度的高度。最后,它最初会被隐藏。


使用JavaScript构建多级动画移动菜单  第1张


相关样式:

/*CUSTOM VARIABLES HERE*/

 

.page-header {

  position: fixed;

  top: 0;

  left: 50%;

  transform: translateX(-50%);

  width: 100%;

  max-width: 600px;

  margin: 0 auto;

  color: var(--white);

}

 

.page-header .header-bar {

  display: flex;

  justify-content: space-between;

  align-items: center;

  height: 60px;

  padding: 0 20px;

  background: var(--header-bar-bg);

}

 

.page-header .menu-wrapper {

  display: none;

  position: absolute;

  top: 60px;

  left: 0;

  width: 100%;

  height: calc(100vh - 60px);

  overflow: hidden;

}

让我们继续面板样式。

  • 他们都将获得父母的身高并拥有overflow-y: auto. 此属性确保滚动条将在其中有很多菜单链接的情况下出现。

  • 尤其是第二个和第三个面板默认情况下将绝对定位并超出屏幕。

相关样式:


/*CUSTOM VARIABLES HERE*/

 

.page-header .list-wrapper {

  height: 100%;

  padding: 30px 20px;

  overflow-y: auto;

  background: var(--menu-bg);

}

 

.page-header .list-wrapper:nth-child(2),

.page-header .list-wrapper:nth-child(3) {

  position: absolute;

  top: 0;

  left: 0;

  right: 0;

  transform: translateX(100%);

  backface-visibility: hidden;

  transition: transform 0.5s;

}

接下来,我们将隐藏第一个和第三个面板中的所有嵌套菜单:


.page-header .list-wrapper:nth-child(1) > ul > li > .sub-menu,

.page-header .list-wrapper:nth-child(2) .level-3 {

  display: none;

}

接下来,我们将为移动菜单链接设置一些样式,特别是:

  • 打开嵌套菜单的链接将带有下划线。

  • 为了指示链接处于活动状态或悬停状态,我们将为其赋予不同的颜色和字符。


使用JavaScript构建多级动画移动菜单  第2张


相关样式:

/*CUSTOM VARIABLES HERE*/

 

.page-header .menu-wrapper a {

  display: inline-block;

  position: relative;

  padding: 5px 0;

}

 

.page-header .menu-wrapper a.nested {

  text-decoration: underline;

}

 

.page-header .menu-wrapper a:hover,

.page-header .menu-wrapper a.is-active {

  color: var(--orange);

}

 

.page-header .menu-wrapper a:hover::before,

.page-header .menu-wrapper a.is-active::before {

  content: "✦";

  position: absolute;

  top: 50%;

  right: -20px;

  transform: translateY(-50%);

  color: var(--orange);

}

 

.page-header .back-one-level {

  display: flex;

  align-items: center;

  margin-bottom: 40px;

}

最后,我们将为后退按钮指定一些简单的样式。


使用JavaScript构建多级动画移动菜单  第3张

他们来了:


/*CUSTOM VARIABLES HERE*/

 

.page-header .back-one-level {

  display: flex;

  align-items: center;

  margin-bottom: 40px;

}

 

.page-header .back-one-level svg {

  fill: var(--white);

  margin-right: 10px;

}

3.添加javaScript

设置样式后,是时候讨论使用幻灯片动画显示嵌套菜单级别所需的操作了。 

切换菜单

这是一个动画 GIF,说明了菜单的切换状态:

使用JavaScript构建多级动画移动菜单  第4张

每次单击切换按钮时,我们都会执行以下操作:

  1. 通过类切换菜单的可见性is-visible。如果它被隐藏,它将出现,反之亦然。

  2. 检查菜单是否关闭。如果满足此条件,我们将执行以下操作:

    1. is-visible如果有的话,从第二个和第三个面板中删除该类。

    2. is-active如果存在此类元素,请从活动菜单链接中删除该类。

这是所需的 JavaScript 代码:

const pageHeader = document.queryselector(".page-header");

const toggleMenu = pageHeader.querySelector(".toggle-menu");

const menuWrapper = pageHeader.querySelector(".menu-wrapper");

const listWrapper2 = pageHeader.querySelector(".list-wrapper:nth-child(2)");

const listWrapper3 = pageHeader.querySelector(".list-wrapper:nth-child(3)");

const isVisibleClass = "is-visible";

const isActiveClass = "is-active";

 

toggleMenu.addeventListener("click", function () {

  // 1

  menuWrapper.classList.toggle(isVisibleClass);

  // 2

  if (!this.classList.contains(isVisibleClass)) {

    // 1

    listWrapper2.classList.remove(isVisibleClass);

    listWrapper3.classList.remove(isVisibleClass);

    // 2

    const menuLinks = menuWrapper.querySelectorAll(".is-active");

    for (const menuLink of menuLinks) {

      menuLink.classList.remove(isActiveClass);

    }

  }

});

以及相关样式:


.page-header .menu-wrapper.is-visible {

  display: block;

}

 

.page-header .list-wrapper:nth-child(2),

.page-header .list-wrapper:nth-child(3) {

  transition: transform 0.5s;

}

 

.page-header .list-wrapper:nth-child(2).is-visible,

.page-header .list-wrapper:nth-child(3).is-visible {

  transform: none;

}

开放二级

这是一个动画 GIF,说明了二级菜单的显示方式:


使用JavaScript构建多级动画移动菜单  第5张

每次我们单击第一级(可见的)菜单链接时,我们都会检查它是否有嵌套菜单作为兄弟。如果满足此条件,我们将执行以下操作:

  1. 阻止其默认操作。

  2. 将is-active班级分配给它。

  3. 创建其兄弟的深层副本。

  4. 将这个新创建的节点附加到.sub-menu-wrapper第二个面板中。

  5. 用幻灯片动画显示第二个面板。

这是所需的 JavaScript 代码:

...

 

for (const level1Link of level1Links) {

  level1Link.addEventListener("click", function (e) {

    const siblingList = level1Link.nextElementSibling;

    if (siblingList) {

      // 1

      e.preventDefault();

      // 2

      this.classList.add(isActiveClass);

      // 3

      const cloneSiblingList = siblingList.clonenode(true);

      // 4

      subMenuWrapper2.innerHTML = "";

      subMenuWrapper2.append(cloneSiblingList);

      // 5

      listWrapper2.classList.add(isVisibleClass);

    }

  });

以及动画的相关样式:

.page-header .list-wrapper:nth-child(2) {

  transition: transform 0.5s;

}

 

.page-header .list-wrapper:nth-child(2).is-visible {

  transform: none;

}

三级开放

这是一个动画 GIF,说明了第三级菜单的显示方式:

使用JavaScript构建多级动画移动菜单  第6张

请记住,默认情况下,第二个面板中没有任何内容.sub-menu-wrapper。在上一节中,我们描述了它如何通过执行深拷贝来接收内容。 

这是生成的标记的示例:


使用JavaScript构建多级动画移动菜单  第7张

接下来,我们必须在有人单击二级菜单链接时立即执行一些操作。然而,棘手的是这些链接是动态生成的,并不是初始 dom 的一部分。也就是说,该click事件不适用于这些元素:(

令人高兴的是,解决方案很简单。感谢事件委托,我们将click事件附加到作为 DOM 一部分的父面板。然后,通过该target事件的属性,我们将检查发生事件的元素,以确保这些元素是与子菜单兄弟的链接。

假设这些是目标元素,对于它们中的每一个,我们将执行以下操作(类似于上一节):

  1. 阻止其默认操作。

  2. 将is-active班级分配给它。

  3. 创建其兄弟的(深)副本。请注意,无论我们是否进行深拷贝,都不会有任何变化,因为我们的菜单包含三个级别。 

  4. 将这个新创建的节点附加到.sub-menu-wrapper第三个面板中。

  5. 用幻灯片动画显示第三个面板。

这是所需的 JavaScript 代码:

...

 

listWrapper2.addEventListener("click", function (e) {

  const target = e.target;

  if (target.tagName.toLowerCase() === "a" && target.nextElementSibling) {

    const siblingList = target.nextElementSibling;

    // 1

    e.preventDefault();

    // 2

    target.classList.add(isActiveClass);

    // 3

    const cloneSiblingList = siblingList.cloneNode(true);

    // 4

    subMenuWrapper3.innerHTML = "";

    subMenuWrapper3.append(cloneSiblingList);

    // 5

    listWrapper3.classList.add(isVisibleClass);

  }

});

以及动画的相关样式:

.page-header .list-wrapper:nth-child(3) {

  transition: transform 0.5s;

}

 

.page-header .list-wrapper:nth-child(3).is-visible {

  transform: none;

}

返回一级

这是一个动画 GIF,说明了后退按钮的工作原理:

使用JavaScript构建多级动画移动菜单  第8张

每次单击后退按钮时,我们将执行以下操作:

  1. 找到目标后退按钮的父面板并删除其is-visible类。

  2. 从父面板的前一个兄弟的活动链接中删除is-active该类。 

这是所需的 JavaScript 代码:

...

 

for (const backOneLevelBtn of backOneLevelBtns) {

  backOneLevelBtn.addEventListener("click", function () {

    // 1

    const parent = this.closest(".list-wrapper");

    parent.classList.remove(isVisibleClass);

    // 2

    parent.previousElementSibling

      .querySelector(".is-active")

      .classList.remove(isActiveClass);

  });

}

再一次,这个动作有一些伴随的 CSS 样式。

结论

在本教程中,我们利用一些常见的 CSS 样式和 JavaScript DOM 的 api 创建了一个多级移动菜单。最重要的是,我们的初始标记包含用于创建菜单的简单嵌套列表。这意味着我们可以将其转换为动态的,并利用 CMS 的功能,如 wordpress,只需进行一些修改。


文章目录
  • 我们的多级菜单
  • 1.定义 html 标记
    • 2.指定主要样式
    • 3.添加javaScript
    • 切换菜单
    • 开放二级
    • 三级开放
    • 返回一级
  • 结论