簡體   English   中英

javascript和CSS按鈕在首次單擊和Flexbox上不起作用

[英]javascript and css button doesn't work on first click & Flexbox

背景:我正在為藝術家制作頁面,並且在該網站上遇到了一些有趣的行為。

我使用flexbox而不是bootstrap作為布局,因為該站點很小,並且沒有大量元素。 Flexbox非常適合布置站點,尤其是針對不同媒體大小的更改。

但是,在最小的媒體尺寸下,在移動布局中,我遇到了一些麻煩。 我喜歡引導程序中可折疊菜單的外觀,但是因為我沒有使用引導程序,所以我從字體中獲得了很棒的圖標,現在我正嘗試使用JavaScript和CSS手動處理可折疊菜單屬性。 但是,在不使用引導程序的情況下,我不確定為什么可擴展菜單僅在重復單擊后才起作用,而不是在第一次單擊時才起作用。

期望:在最小的媒體查詢中(窗口<768像素),我以所需的方式設置了默認的移動版式。 標語位於頁面的大約一半位置,並且漢堡菜單固定在瀏覽器的頂部。 當我單擊菜單按鈕時,我期望的反應是使菜單鏈接出現在菜單按鈕下方,並使頁面橫幅消失。

問題:這種情況會發生並切換,但只能在多次單擊后才能切換。

問題:1.是什么導致單擊行為僅在單擊幾下后才能起作用? 2.為什么'none'的display屬性不能應用於'nav-left'項目? 3.在顯示菜單時,除了使用邊距來抵消出現的菜單項外,是否有辦法確保它們出現在漢堡包按鈕區域下方? (即我希望鏈接1-3在出現時顯示在漢堡菜單下方)。

jsfiddle在這里

 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> 

問題出在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每運行10000次時,顯著高於@ FLEN的獨立的比較,差不多五個秒鍾差得更快。

之所以可行,是因為字符串'''none'在技​​術上'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在上面加上一個is ,這將是一個句子。

display.isEmptyOrEqualTo('none')

現在您實際上可以閱讀它:

如果顯示為空或等於“無”


僅供參考,在您的JSFiddle中, y.styleundefined因為您使用了.getElementsByClassName但是它返回一個數組,並且沒有獲得返回數組的第一個索引。

另外一些注意事項:

  • 我建議使用比xy更多的描述性變量名稱,因為它們不能傳達其含義,您必須查找它們的定義行才能理解,這並不完全是“最佳實踐”。
  • 您可能應該將JavaScript移到一個單獨的文件中,就像已經使用CSS一樣。
  • 可選:我建議您學習使用constlet
  • 繼續前進,您做得很棒。

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 ,讓我改一下解決方法:第一次調用menuToggle函數時,它將讀取x.style.display ,它的值實際上是""而不是您期望的"none" 由於它不是"none" ,因此它將運行else子句,然后繼續將x.style.display分配x.style.display "none"並將y.style.display"flex" 這不應該發生,因為這表示您的菜單已關閉。 因此,僅在第二次調用時才打開它,因為該函數的第一次調用運行了else子句並關閉了(已經關閉)菜單。


附錄
chbchb55還建議了一種巧妙的優化,使用if (!'none'.indexOf(x.style.display)) ,甚至創建原型作為語法糖來使其更具可讀性。 我仍然出於兩個原因反對使用此方法。

首先,它的可讀性仍然比if (x.style.display == "none" || x.style.display === "") 在這里,無論誰閱讀代碼,都可以立即看到我們正在檢查2個條件,僅檢查這兩個條件。使用indexOf尚不清楚我們是否也在檢查"" ,因此我們必須在注釋中指定此條件。 我認為可讀性更差。

其次,如果速度是一個問題,這實際上是最快的解決方案,用if代替else子句: if (x.style.display === "flex") ,然后執行else子句中的操作。 這樣, else將捕獲x === ''x == 'none'以及其他任何內容。 如果代碼長度是一個問題,我們可以使用三元運算符進一步改善:

 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"); } 

仍然,速度和長度在這里不是問題,因為現在是代碼。 如果改善1毫秒,我會印象深刻。 我認為原始解決方案是最易讀的解決方案,這就是為什么我仍然建議將其作為答案。 盡管如此,使用indexOf想法還是很聰明的,如果我沒記錯的話,它比ES6 includes的速度更快

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM