【问题标题】:How to make dropdown menu with some specific details如何制作带有一些特定细节的下拉菜单
【发布时间】:2019-06-17 01:52:57
【问题描述】:

我想制作一些包含一些细节的高级下拉菜单。

这都是关于 javascript,只有 js,没有框架

我这里有两个下拉菜单,一个是服务,另一个是项目。这里的问题是我希望当我单击服务时,服务显示的子菜单,当我单击项目时,项目显示的子菜单和服务隐藏的子菜单,当我在两者之外单击时,子菜单也隐藏。我尝试了一些代码,但没有像我预期的那样工作。谢谢各位!

<nav>
    <h1 class="logo">Hiep</h1>
    <ul class="menu">
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li>
            <a href="#">Serices</a>
            <ul class="sub-menu">
                <li><a href="#">Service 1</a></li>
                <li><a href="#">Service 2</a></li>
                <li><a href="#">Service 3</a></li>
                <li><a href="#">Service 4</a></li>
            </ul>
        </li>
        <li><a href="#">Contact</a></li>
        <li>
            <a href="#">Projects</a>
            <ul class="sub-menu">
                <li><a href="#">Project 1</a></li>
                <li><a href="#">Project 2</a></li>
                <li><a href="#">Project 3</a></li>
                <li><a href="#">Project 4</a></li>
            </ul>
        </li>
    </ul>
</nav>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

ul {
    list-style: none;
}

a {
    text-decoration: none;
    color: #fff;
}

nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 20px;
    background: #000;
}

h1 {
    color: #fff;
    text-transform: uppercase;
}
.menu {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.menu li {
    position: relative;
}

.menu a {
    padding: 25px;
    display: block;
    }
    .menu a:hover {
        background: #fff;
        color: #333;
    }

.menu .sub-menu {
    position: absolute;
    top: 100%;
    background: #000;
    width: 130%;
    left: 0;
    display: none;
}

演示:https://jsfiddle.net/zoamkdru/4/

【问题讨论】:

  • 你说没有javascript?如果是这样,您如何使用 html 和 css 定位点击事件?
  • 抱歉,刚刚编辑。纯js
  • 好吧,其实我只是用 css :hover 事件写了一个答案。
  • 我已经更新了我的答案并提出了一个纯 js 并且没有更多的 css:hover。

标签: javascript html css


【解决方案1】:

只是一个简单的示例,说明如何完成。我通常会使用 jQuery 来标记选择器。自从我上次使用 vanilla js 以来已经有一段时间了。这是我能做的最好的。

var serviceTab = document.getElementById('serviceTab');
var projectTab = document.getElementById('projectTab');
var serviceSubMenu = document.getElementById('serviceSubMenu');
var projectSubMenu = document.getElementById('projectSubMenu');
var serviceSubMenuDisplayStatus = 0;
var projectSubMenuDisplayStatus = 0;

var content = document.getElementById('contentHere');


serviceTab.onclick = function() {

  if (serviceSubMenuDisplayStatus == 1) {
    serviceSubMenu.style.display = "none";
    serviceSubMenuDisplayStatus = 0;

  } else {
    serviceSubMenu.style.display = "block";
    serviceSubMenuDisplayStatus = 1;
    projectSubMenu.style.display = "none";
    projectSubMenuDisplayStatus = 0;
  }
}

projectTab.onclick = function() {

  if (projectSubMenuDisplayStatus == 1) {
    projectSubMenu.style.display = "none";
    projectSubMenuDisplayStatus = 0;
  } else {
    projectSubMenu.style.display = "block";
    projectSubMenuDisplayStatus = 1;
    serviceSubMenu.style.display = "none";
    serviceSubMenuDisplayStatus = 0;
  }
}

content.onclick = function() {
  if (serviceSubMenuDisplayStatus == 1) {
    serviceSubMenu.style.display = "none";
    serviceSubMenuDisplayStatus = 0;

  }
  if (projectSubMenuDisplayStatus == 1) {
    projectSubMenu.style.display = "none";
    projectSubMenuDisplayStatus = 0;
  } else {
    //do nothing. 
  }
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

ul {
  list-style: none;
}

a {
  text-decoration: none;
  color: #fff;
}

nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20px;
  background: #000;
}

h1 {
  color: #fff;
  text-transform: uppercase;
}

.menu {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.menu li {
  position: relative;
}

.menu a {
  padding: 25px;
  display: block;
}

.menu a:hover {
  background: #fff;
  color: #333;
}

.menu .sub-menu {
  position: absolute;
  top: 100%;
  background: #000;
  width: 130%;
  left: 0;
  display: none;
}
<nav>
  <h1 class="logo">Hiep</h1>
  <ul class="menu">
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li>
      <a href="#" id="serviceTab">Services</a>
      <!-- Add some ID here.  -->
      <ul class="sub-menu" id="serviceSubMenu">
        <!-- Add some ID here.  -->
        <li><a href="#">Service 1</a></li>
        <li><a href="#">Service 2</a></li>
        <li><a href="#">Service 3</a></li>
        <li><a href="#">Service 4</a></li>
      </ul>
    </li>
    <li><a href="#">Contact</a></li>
    <li>
      <a href="#" id="projectTab">Projects</a>
      <!-- Add some ID here.  -->
      <ul class="sub-menu" id="projectSubMenu">
        <!-- Add some ID here.  -->
        <li><a href="#">Project 1</a></li>
        <li><a href="#">Project 2</a></li>
        <li><a href="#">Project 3</a></li>
        <li><a href="#">Project 4</a></li>
      </ul>
    </li>
  </ul>
</nav>

<div id="contentHere">
  click here
</div>

【讨论】:

  • 这里的问题是当我点击下拉菜单外的其他链接时,下拉菜单仍然存在。我希望它在单击其他链接或外部时隐藏。谢谢。无论如何,我想看看你的 jquery 方式。非常感谢!
  • @HiepNguyen 如果您不介意在 jQuery 中提供解决方案,我会编辑您的问题以提及这一点。 “这都是关于 JavaScript 的……”在我看来,这有点不鼓励使用 JS 以外的任何东西。
  • 是的,请使用 jquery。谢谢
  • @nhk96 请帮帮我。
  • @HiepNguyen 用纯 js 在下面查看我的答案。
【解决方案2】:

试过':focus-within'。它可能与某些浏览器不兼容。

 .menu > li:focus-within ul {
    display: block !important;
 }

* {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}

ul {
	list-style: none;
}

a {
	text-decoration: none;
}

nav {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 0 20px;
	background: #000;
}

h1 {
	color: #fff;
	text-transform: uppercase;
}

.menu {
	display: flex;
	justify-content: space-between;
	align-items: center;
}

.menu li {
	position: relative;
}

.menu a {
	padding: 20px;
	display: block;
	color: #fff;
}

.menu a:hover {
  background: #fff;
  color: #333;
}

.menu .sub-menu {
    position: absolute;
    top: 100%;
    background: #000;
    width: 130%;
    left: 0;
    display: none;
}

.menu > li:focus-within ul {
   display: block !important;
}
<nav>
	<h1 class="logo">Hiep</h1>
	<ul class="menu">
		<li><a href="#">Home</a></li>
		<li><a href="#">About</a></li>
		<li>
			<a href="#">Services</a>
			<ul class="sub-menu">
				<li><a href="#">Service 1</a></li>
				<li><a href="#">Service 2</a></li>
				<li><a href="#">Service 3</a></li>
				<li><a href="#">Service 4</a></li>
			</ul>
		</li>
		<li><a href="#">Contact</a></li>
		<li>
			<a href="#">Projects</a>
			<ul class="sub-menu">
				<li><a href="#">Project 1</a></li>
				<li><a href="#">Project 2</a></li>
				<li><a href="#">Project 3</a></li>
				<li><a href="#">Project 4</a></li>
			</ul>
		</li>
	</ul>
</nav>

【讨论】:

  • 只有服务和项目有下拉菜单
  • 这个方法很好,但是这里的问题是当点击子菜单中的链接时,子菜单消失了。我希望它还在。谢谢
  • 更新为使用:focus-within 选择器。
【解决方案3】:

只有 Hhtml 和 CSS 以及纯 Javascript...我匆忙地做了这件事。可能还有许多其他方法可以执行此操作。但我使用data-active = true || false 属性来设置切换值。

使用 jquery 时,相同的解决方案会更短...但我确信这就是您在 VanillaJS 中寻找的。​​p>

运行 sn-p 并检查它是如何运行的

(function()
{
    //Note JSON.pasrse("true" || "false") is used to convert string bool to actual bool datatype
    var dropdownTogglers = document.querySelectorAll("a.dropdown-toggler"); //get a list of toggle buttons
    var toggleElementsIds = ["services", "projects"]; //create a list of elements id to be toggled
    var otherLinks = document.querySelectorAll(".link");


    //helper function for getting an element by id
    function _id(id) {
        return document.getElementById(id);
    }

    //Target all other links
    for (var i = 0; i < otherLinks.length; i++) {
        otherLinks[i].addEventListener("click", function () {
            for (var i = 0; i < toggleElementsIds.length; i++) {
                _id(toggleElementsIds[i]).style.display = "none";
                _id(toggleElementsIds[i]).setAttribute("data-active", false);
            }
        });
    }
    _id("content-container").addEventListener("click", function () {
        for (var i = 0; i < toggleElementsIds.length; i++) {
            _id(toggleElementsIds[i]).style.display = "none";
            _id(toggleElementsIds[i]).setAttribute("data-active", false);
        }
    });

    //for all toggler buttons found,
    for(var i = 0; i < dropdownTogglers.length; i++)
    {
        //add a click event to that button
        dropdownTogglers[i].addEventListener("click",
            //get even as parameter
            function(event)
            {
                //use event to know which button is being clicked
                var el = event.target || src.target;

                //check if the button clicked is for services
                if (el.getAttribute("data-el") == toggleElementsIds[0])
                {
                    //check the current state of "data-active" of the services
                    if (!JSON.parse(_id(el.getAttribute("data-el")).getAttribute("data-active"))) {
                        //at this point services "data-active" is false
                        //set it to true
                        _id(el.getAttribute("data-el")).setAttribute("data-active", true);
                        //and ensure that the other toggling elements are hidden, or set to false
                        _id(toggleElementsIds[1]).setAttribute("data-active", false);
                    } else {
                        //at this point the services data-val was true
                        //set it to false
                        _id(el.getAttribute("data-el")).setAttribute("data-active", false);
                    }

                //check if the button clicked is for projects
                } else if (el.getAttribute("data-el") == toggleElementsIds[1])
                {
                    //check the current state of "data-active" of the projects
                    if (!JSON.parse(_id(el.getAttribute("data-el")).getAttribute("data-active"))) {
                        //at this point projects "data-active" is false
                        //set it to true
                        _id(el.getAttribute("data-el")).setAttribute("data-active", true);
                        //and ensure that the other toggling elements are hidden, or set to false
                        _id(toggleElementsIds[0]).setAttribute("data-active", false);
                    } else {
                        //at this point the projects data-val was true
                        //set it to false
                        _id(el.getAttribute("data-el")).setAttribute("data-active", false);

                    }
                }
                //after setting all data-active values, change their display status based on their values
                //call the toggle funtion
                ToggleOperations();
            }
        );
    }

    //perform toggle operations,
    //this function just sets css display properties of toggleElements based on their "data-active" true or false
    function ToggleOperations() {
        //Target all toggle elements
        for (var i = 0; i < dropdownTogglers.length; i++) {
            //if this toggle element "data-val" is true
            if (JSON.parse(_id(toggleElementsIds[i]).getAttribute("data-active")))
            {
                //set its display to block
                _id(toggleElementsIds[i]).style.display = "block";
            } else
            //if this toggle element "data-val" is false
            {
                //set the display to none
                _id(toggleElementsIds[i]).style.display = "none";
            }
        }
    }
})();
html, body{
    display: block;
    position: relative;
    height: 100%;
    width: 100%;
}
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

ul {
    list-style: none;
}

a {
    text-decoration: none;
}

nav {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 20px;
    background: #000;
    z-index: 9000;
}

h1 {
    color: #fff;
    text-transform: uppercase;
}
.menu {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.menu li {
    position: relative;
}

.menu a {
    padding: 20px;
    display: block;
    color: #fff;
}
.menu a:hover {
    background: #fff;
    color: #333;
}
.menu .sub-menu {
    position: absolute;
    top: 100%;
    background: #000;
    width: 130%;
    left: 0;
    display: none;
}
<nav>
    <h1 class="logo">Hiep</h1>
    <ul class="menu">
        <li><a href="#" class="link">Home</a></li>
        <li><a href="#" class="link">About</a></li>
        <li>
            <a class="dropdown-toggler" data-el="services">Serices</a>
            <ul class="sub-menu" id="services" data-active="false">
                <li><a href="#">Service 1</a></li>
                <li><a href="#">Service 2</a></li>
                <li><a href="#">Service 3</a></li>
                <li><a href="#">Service 4</a></li>
            </ul>
        </li>
        <li><a href="#" class="link">Contact</a></li>
        <li >
            <a class="dropdown-toggler" data-el="projects">Projects</a>
            <ul class="sub-menu" id="projects" data-active="false">
                <li><a href="#">Project 1</a></li>
                <li><a href="#">Project 2</a></li>
                <li><a href="#">Project 3</a></li>
                <li><a href="#">Project 4</a></li>
            </ul>
        </li>
    </ul>
</nav>
<div id="content-container" 
     style="width: 100%;
            height: 100%;
            background-color: whitesmoke;">

</div>

【讨论】:

  • 谢谢,但我不想悬停它,我想要点击事件。看起来很复杂。
  • 我还添加了一些cmets,以便您可以理解JS代码。让我知道你的想法,如果你觉得这个方法不适合你的场景,我会使用其他方法。
  • 可以,但是说实话代码真的很复杂,我只是个初学者。你可以改用jquery吗?谢谢。
  • 好吧。这并不复杂。我认为我第一次使用列表并且必须索引 [0] 使您更难看到发生了什么。但是你必须学会​​编写好的代码。看起来很长的代码并不一定很复杂。我将发布一个 jquery 解决方案。
猜你喜欢
  • 2012-06-26
  • 1970-01-01
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 2021-09-12
  • 1970-01-01
  • 2010-10-09
  • 2018-12-11
相关资源
最近更新 更多