javascript和CSS按钮在首次单击和Flexbox上不起作用

时间:2018-07-08 04:15:33

标签: javascript css flexbox

背景: 我正在为艺术家做页面,但该网站出现了一些有趣的行为。

我使用flexbox而不是bootstrap进行布局,因为该站点很小,并且没有大量元素。 Flexbox非常适合布置站点,尤其是针对不同媒体大小的更改。

但是,在最小的媒体尺寸下,移动版式遇到了一些麻烦。我喜欢引导程序中可折叠菜单的外观,但是因为我没有使用引导程序,所以我从字体中获得了很棒的图标,现在我正尝试使用JavaScript和CSS手动处理可折叠菜单属性。但是,在不使用引导程序的情况下,我不确定为什么可扩展菜单仅在重复单击后才起作用,而不是在第一次单击时才起作用。

期望: 在最小的媒体查询中(窗口<768像素),我以所需的方式设置了默认的移动版式。标语位于页面的大约一半位置,并且汉堡菜单固定在浏览器的顶部。当我单击菜单按钮时,我期望的反应是使菜单链接出现在菜单按钮下方,并使页面横幅消失。

问题:  这种情况会发生并切换,但只有在单击多次后才可以。

问题: 1.是什么导致单击行为仅在单击几下后才能起作用? 2.为什么'none'的display属性不能应用于'nav-left'项目? 3.在显示菜单时,除了使用边距来抵消出现的菜单项外,是否有办法确保它们出现在汉堡包按钮区域下方? (即,我希望链接1-3出现在汉堡菜单下方)。

jsfiddle here

function menuToggle() {
  var x = document.getElementById('nav-right');
  var y = document.getElementsByClassName("nav-left");
  if (x.style.display == "none") {
    x.style.display = "flex";
    y.style.display = "none";
  } else {
    x.style.display = "none";
    y.style.display = "flex";
  }
}
* {
  margin: 0;
  padding: 0;
}

html,
body {
  background-color: gray;
  height: 100%;
  width: 100%;
}

.nav-left {
  font-family: 'Kristi', cursive;
  font-size: 5.5em;
  color: #e319b6;
  letter-spacing: 2px;
  margin: 0;
  padding: 0 0 0 50px;
}

.nav-left a {
  text-decoration: none;
  color: #e319b6;
}

.hamburger {
  display: none;
}

li a {
  text-decoration: none;
  color: white;
}

li a:hover {
  text-decoration: none;
  color: #e319b6;
}

li {
  padding: 50px 10px;
  list-style: none;
  font-family: 'Montserrat', sans-serif;
  font-size: 1.7em;
  font-weight: 100;
  color: white;
  display: inline-block;
}

@media (max-width:767px) {
  .hamburger {
    width: 100%;
    padding: 2% 0;
    display: flex;
    color: white;
    font-size: 2em;
    justify-content: center;
    background: rgba(0, 0, 0, .1);
    position: absolute;
    cursor: pointer;
    border: none;
  }
  .pagenav {
    width: 100%;
    display: flex;
    align-items: center;
    flex-direction: column;
  }
  .nav-left {
    width: 100%;
    display: flex;
    justify-content: center;
    order: 2;
    margin-top: 10%;
    padding: 0;
  }
  #nav-right {
    display: none;
    justify-content: center;
    width: 100%;
  }
  .nav {
    width: 100%;
  }
  nav ul {
    display: flex;
    flex-direction: column;
    width: 100%;
  }
  nav ul li {
    display: flex;
    justify-content: center;
    width: 100%;
  }
  nav ul li {}
  nav ul li:hover {
    background: rgba(0, 0, 0, .8);
  }
  nav ul li:hover a {
    color: #e319b6;
  }
}
<head>
  <meta charset="utf-8">
  <title></title>


  <!-- Font Awesome -->
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">


</head>

<body>

  <div class="pagenav">

    <div class="nav-left">
      placeholder
    </div>

    <button class="hamburger" onclick="menuToggle()">
                  <i class="fas fa-bars"></i>
              </button>

    <nav id="nav-right">
      <ul>
        <li><a href="reel.html">Link 1</a></li>
        <li><a href="">Link 2</a></li>
        <li><a href="">Link 3</a></li>
      </ul>

    </nav>

  </div>


</body>

2 个答案:

答案 0 :(得分:3)

问题出在HTML中,而不是您的函数中

您遇到的问题是if (x.style.display == "none")应该第一次通过,因为它是隐藏的吗?好吧,它没有通过,因为根据style属性,display不等于none,因此,您不能说它是隐藏的。要解决此问题,请执行以下操作:

<nav id='nav-right' style='display: none'>

现在您的代码知道#nav-right是隐藏的,并且在第一次单击时就可以使用。

选项2,修改代码:

您可以使用一次性切换变量。这样,第一次单击按钮将显示菜单,然后将toggle变量设置为false。像这样:

let firstMenuClickToggle = true

function menuToggle() {
  ...
  if (x.style.display == 'none' || firstMenuClickToggle) {
    firstMenuToggle = false
    ...

选项3,同时检查空字符串和'none'

就像@flen所说的那样,您可以在'none'旁边搜索一个空字符串,但是为什么不能同时搜索两者呢?

例如,尝试将您的if语句替换为以下内容:

if (!'none'.indexOf(x.style.display)) {

实际上,根据我在Benchmark.js上进行的测试,它比@flen的单独比较快得多,当每次运行10,000次时,相差近 5秒

之所以可行,是因为从技术上讲,两个字符串'''none''none'中都存在,因此,如果其中两个值都存在,它们将返回0。因此,我使用!运算符进行检查,!0将始终返回true,但其他任何数字(即!-1)都将返回false。

编辑:使其更具可读性

String.prototype.emptyOrEqualTo = function(string) {
  return string.indexOf(this)
}

// in your function
if (x.style.display.emptyOrEqualTo('none')) {

尽管通常不执行对String.prototype的修改,但它确实比大多数其他增加可读性的方法产生更高的可读性。实际上,您甚至可以在上面加上is,这将是一个句子。

display.isEmptyOrEqualTo('none')

现在您可以实际阅读它了:

如果显示为空或等于“无”


仅供参考,在您的JSFiddle中,y.styleundefined,因为您使用了.getElementsByClassName,但是返回了一个数组,但是没有得到返回数组的第一个索引。

另外一些注意事项:

  • 我建议使用比xy更多的描述性变量名称,因为它们没有传达其含义,您必须查找它们的定义行才能理解,这并不完全是“最佳实践” 。
  • 您可能应该将JavaScript移到一个单独的文件中,就像已经使用CSS一样。
  • 可选:我建议同时学习使用constlet
  • 继续前进,你做得很好。

答案 1 :(得分:3)

chbchb55已经解释了问题所在,但是我认为您不应该更改HTML来修复JavaScript代码中的错误。而是在此处将menuToggle函数更改为此:

function menuToggle() {
  var x = document.getElementById('nav-right');
  var y = document.getElementsByClassName("nav-left")[0]; //changed to get the first element of the HTMLCollection
  if (x.style.display == "none" || x.style.display === "") { //changed to also accept the original value, which is "" instead of "none"
    x.style.display = "flex";
    y.style.display = "none";
  } else {
    x.style.display = "none";
    y.style.display = "flex";
  }
}

请明确说明一下,让我改一下解决方法:第一次调用menuToggle函数时,它读取的是x.style.display,其值实际上是""而不是{{1} },正如您期望的那样。由于不是"none",因此它将运行"none"子句,然后继续将else分配给x.style.display,将"none"分配给y.style.display。这不应该发生,因为这表示您的菜单已关闭。因此,仅在第二次调用时才打开它,因为该函数的第一次调用运行了"flex"子句并关闭了(已经关闭)菜单。


附录
chbchb55还建议进行巧妙的优化,使用else甚至创建原型作为语法糖来使其更具可读性。我仍然出于两个原因反对使用此方法。

首先,它的可读性仍然不如if (!'none'.indexOf(x.style.display))。在这里,无论谁阅读代码,都可以立即看到我们正在检查2个条件,而仅检查这2个条件。使用if (x.style.display == "none" || x.style.display === "")尚不清楚我们是否也在检查indexOf,因此我们必须在评论中指定。我认为可读性更差。

第二,如果速度是一个问题,那么这实际上是最快的解决方案,用""代替if子句:else,然后执行{{1 }}子句。这样,if (x.style.display === "flex")将捕获elseelse以及其他任何内容。如果代码长度是一个问题,我们可以使用三元运算符来进一步改善:

x === ''

仍然,速度和长度在这里不是问题,因为现在是代码。如果改善1毫秒,我会印象深刻。我认为原始解决方案是最易读的解决方案,这就是为什么我仍然建议将其作为答案。不过,使用x == 'none'的想法非常聪明,如果我没记错的话,它比ES6 function menuToggle() { var x = document.getElementById('nav-right'); var y = document.getElementsByClassName("nav-left")[0]; //changed to get the first element of the HTMLCollection x.style.display === "flex" ? (x.style.display = "none", y.style.display = "flex") : (x.style.display = "flex", y.style.display = "none"); }

更快