纯JS从左到右的切换动画

3

我是一名编码新手,正在学习原生JS。我用一个从左到右移动的圆圈创建了这个抽屉导航,但是有一个问题。我在这里上传了当前状态:http://setup.industries/masquarade/

让我困惑的问题:

  • 第一次点击汉堡包图标时不会打开抽屉,而且动画也会切换。我怀疑问题出在 if(open) 上,因为 open 变量没有真正捕获切换状态 open = header.style.width == '0%' 在初始错误之后,它就可以正常工作了。这对我来说真的很难理解。

如果您有其他更好的代码提示或指出我的不良实践,我很愿意学习。

--

编辑1:我已经将完整代码添加到了这个问题中。我不确定如何使椭圆形可见,我直接链接到托管的URL。

      // open sidenav //

      function openNav() {
        let header = document.getElementById("header");
        let open = header.style.width == '0%'
        let width = document.body.clientWidth;
        var ellipse = document.getElementById("ellipse");

        function moveEllipseRight() {
          ellipse.animate([
          // keyframes
          { transform: 'translateX(0px)' },
          { transform:  'translateX('+ width + 'px)' }
        ], {
          // timing options
          duration: 500,
          iterations: 1,
          easing: 'ease-in-out',
          fill: 'forwards'
        });}

        function moveEllipseLeft() {
          ellipse.animate([
          // keyframes
          { transform:  'translateX('+ width + 'px)' },
          { transform: 'translateX(0px)' }
        ], {
          // timing options
          duration: 500,
          iterations: 1,
          easing: 'ease-in-out',
          fill: 'forwards'
        });}

        // open sidenav //

        if (open) {
            header.style.width = "100%";
             moveEllipseRight();
        } else {
             header.style.width = '0%';
             moveEllipseLeft();
           }
         }

//  if (open) {
//   ellipse.classList.remove("ellipse_left");
//    ellipse.classList.add("ellipse_right");
//  } else {
//    ellipse.classList.remove("ellipse_right");
//    ellipse.classList.add("ellipse_left");
//  }

//  let ellipse = document.getElementById("ellipse");
//  let pos = 0;
//  let id = setInterval(frame, 5);


 //  function myMove() {
 //    console.log('Hello')
 //    var ellipse = document.getElementById("ellipse");
 //    var pos = -200;
 //    var id = setInterval(frame, 1);
 //    let width = document.body.clientWidth; // - $('#mydiv').width();
 //
 //        function frame() {
 //          if (pos == width - 200) {
 //            clearInterval(id);
 //          } else {
 //            pos++;
 //            ellipse.style.left = pos + "px";
 //          }
 //        }
 //    }


// information tabs //

function openTab(evt, tab) {
  var i, tabcontent, tablinks;
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }
  document.getElementById(tab).style.display = "block";
  evt.currentTarget.className += " active";
}
html, body {
    max-width: 100%;
    overflow-x: hidden;
}
body {
    background: black;
    color: white;
    font-family: 'Helvetica Neue', sans-serif;
    font-size: 1.2em;
    line-height: 1.4em;
}

a {
  color: white;
}

.clear {
  clear: both; float: none; height: 40px;
}

/* Ellipse */

#ellipse {
  position: absolute;
  top: 120px;
  z-index:99;
  animation: 3s linear 0s slide 1;
  left: -200px;
}

/*
.ellipse_left {left: -200px;}
.ellipse_right {right: -200px;}
*/


/* Masquarede Logo */

img.masquarade_events {
  opacity: 0.3;
  position: absolute;
  bottom: 20px;
  right: 20px;
}

img.masquarade_events:hover {
  opacity: 0.9;
}


/* Content */

.content {
  margin: 150px 0 0 300px;
  width: 700px;
  height: 400px;
}

@media screen and (max-width: 992px) {
  .content {
    margin: 150px 0 0 0;
    width: 700px;
    height: 400px;
  }
}

.date {
  font-weight: bold;
  margin-bottom: -10px;
}

.location {
}

ul.lineup {
  list-style-position: inside;
  padding: 0;
  list-style-type: none;
  width: 100%
  overflow: hidden;
  margin-bottom: 100px;
}

ul.lineup li {
  margin-right: 50px;
  line-height: 2.5em;
  float: left;
}


/* Buttons */

a.button {
  margin-right: 10px;
  padding: 10px 50px 10px 50px;
  text-decoration: none;
  border-radius: 200px;
  font-size: 0.7em;
  transition: 0.3s;
}

a.white {
  background: white;
  color: black;
}

a.white:hover {
  color: white;
  background: #D90E46;
}

a.black {
  border: 2px white solid;
  color: white;
}

a.black:hover {
  border: 2px #FCF454 solid;
  color: #FCF454;
}

/* Header  */

header {
  position: absolute;
  background-color: black;
  top:0;
  left:0;
  width: 0;
  height: 100%;
  z-index: 1;
}

/* Navigation  */

header nav {
  position: absolute;
  top: 100px;
  right:300px;
}

nav ul {
  list-style-position: inside;
  width: 400px;
  padding: 0;
  list-style-type: none;
  font-size: 1em;
}

nav ul li{
  border-bottom: 1px solid white;
  padding: 10px 0 10px 0;
}

nav ul li:hover{
  font-weight: bold;
  padding: 10px 0 10px 10px;
}

li.active {
  font-weight: bold;
}

nav ul li:first-child{
/*  border-top: 1px solid white;*/
}

nav ul li a{
  text-decoration: none;
}

nav ul h2{
  margin-bottom: 10px;
}

.tabcontent {
  display: none;
}

/* Header Icon */

img.icon {
  position: absolute;
  z-index: 999;
  top:60px;
  right:70px;
}

/* Display */

.display {
  width: 400px;
  height: 400px;
  position: absolute;
  top: 100px;
  right:750px;
}

.display p {
  margin:0 30px 30px 0;
}
<!doctype html>
<html lang="en">
  <head>
    <!-- SETUP Industries - FUNCTIONAL DESIGN -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- <link rel="shortcut icon" type="image/png" href="favicon.png"/> -->


    <!-- CSS -->
    <link rel="stylesheet" type="text/css" href="assets/style.css" />
   <link href="https://fonts.googleapis.com/css?family=Heebo:400,700,900" rel="stylesheet">

    <!-- JS -->
    <script src="assets/javascript.js"></script>


    <title>Masquarade Classix 2019</title>
  </head>
  <body>

  <!-- Navigation -->

    <!-- Icon -->
    <img onclick="openNav()"id="icon" src="http://setup.industries/masquarade/assets/icon.svg" class="icon" width="40" alt="Expand Navigation" />
    <header id="header">

      <nav>
        <ul>
          <h2>Information</h2>
          <li class="tablinks" onmouseover="openTab(event, 'Tickets')"><a href="#">Tickets and pricing </a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Location')"><a href="#">Location</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Transportation')"><a href="#">Transportation</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Amenities')"><a href="#">Ameneties</li>
          <li class="tablinks" onmouseover="openTab(event, 'HouseRules')"><a href="#">House rules</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'TermsAndConditions')"><a href="#">Terms and conditions</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Contact')"><a href="#">Contact</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Partners')"><a href="#">Partners</a></li>
        </ul>
      </nav>


<div class="display">


      <div id="Tickets" class="tabcontent">
          <h2>Tickets and pricing</h2>
          <p>Saturday day tickets cost 45 EUR incl. service costs and 21% BTW. You can buy tickets online via the button below or at one of the resellers listed below.</p>
          <a href="#" class="button white">Buy Tickets</a>
          <br><br>
          <p style="font-size:0.8em;"> <strong>Paperpoint</strong><br>
            3930 Hamont-achel<br><br>
            <strong>Dag en nachtwinkel </strong><br>
            3900 Overpelt<br><br>
            <strong>VDM bvba, Q8 tankstation</strong> <br>
            Peer<br><br>
            <strong>Frituur De Kromme Draai</strong> <br>
            Eksel<br><br>
            <strong>’t frituurke</strong> <br>
            Haag 22, 3910 Achel<br></p>
      </div>

      <div id="Location" class="tabcontent">
          <h2>Location</h2>
      </div>

      <div id="Transportation" class="tabcontent">
          <h2>Transportation</h2>
      </div>

      <div id="Amenities" class="tabcontent">
          <h2>Amenities</h2>
      </div>

      <div id="HouseRules" class="tabcontent">
          <h2>House Rules</h2>
      </div>

      <div id="TermsAndConditions" class="tabcontent">
          <h2>Terms And Conditions</h2>
      </div>

      <div id="Contact" class="tabcontent">
          <h2>Contact</h2>
      </div>

      <div id="Partners" class="tabcontent">
          <h2>Partners</h2>
      </div>



</div>


    </header>
  <!-- Navigation End -->
<div class="container">
    <div id="ellipse" class="ellipse_left">
      <img src="assets/ellipse.svg" alt="ellipse" width="400" height="400"/>
    </div>
    <img class="masquarade_events" src="assets/masquarade_events.png" alt="Masquarade Events" width="125" height=""/>
<div class="content">

    <p class="date">25 mei 2019</p>
    <p class="location">Hennemeeuwis Neerpelt</p>
    <h1>Masquarade Classix </h1>
    <ul class="lineup">
        <li>Nina Kraviz</li>
        <li>Recondite</li>
        <li>Mind Against</li>
        <li>Âme</li>
        <li>Vince Watson</li>
        <li>Kölsch</li>
        <li>Rodriguez Jr. </li>
        <li></li>
    </ul>
<div class="clear"></div>

    <a href="#" class="button white">Buy Tickets</a>
    <a href="#" class="button black">More Information</a>

</div>
</div>

  </body>
</html>


请将您的完整代码,包括HTML和CSS,添加到问题中。 - Jack Bashford
你有一个 Promise 的问题,动画总是异步的。 - Mister Jojo
@FZs 点击="openNav()" 在汉堡菜单图标上。 - SaroGFX
不要检查宽度是否为“0%”,我个人会在元素上添加一个类“open”。然后检查元素的类是否包括open。 - Sølve T.
2个回答

1

你的逻辑有误。只需改变100%/0%的顺序即可解决问题。

改进提示:

  1. 使用类而不是实际的CSS来检查元素状态。(当元素打开时添加一个“open”类,并在关闭时删除它)
  2. 通过执行上述操作,您可以将宽度的操作移动到CSS类“open”中:header.open {width: 100%}
  3. 通过使用“`”并将变量封装在${}中,您可以消除许多“+”,例如:{ transform: `translateX(${width}px)` }

可以在片段中看到:

// open sidenav //

      function openNav() {
        let header = document.getElementById("header");
        let open = header.className.includes('open')
        let width = document.body.clientWidth;
        var ellipse = document.getElementById("ellipse");

        function moveEllipseRight() {
          ellipse.animate([
          // keyframes
          { transform: 'translateX(0)' },
          { transform:  `translateX(${width}px)` }
        ], {
          // timing options
          duration: 500,
          iterations: 1,
          easing: 'ease-in-out',
          fill: 'forwards'
        });}

        function moveEllipseLeft() {
          ellipse.animate([
          // keyframes
          { transform:  `translateX(${width}px)` },
          { transform: 'translateX(0)' }
        ], {
          // timing options
          duration: 500,
          iterations: 1,
          easing: 'ease-in-out',
          fill: 'forwards'
        });}

        // open sidenav //

        if (open) {
             moveEllipseLeft();
             header.classList.remove("open");
        } else {
             moveEllipseRight();
             header.classList.add("open");
           }
         }


// information tabs //

function openTab(evt, tab) {
  var i, tabcontent, tablinks;
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }
  document.getElementById(tab).style.display = "block";
  evt.currentTarget.className += " active";
}
html, body {
    max-width: 100%;
    overflow-x: hidden;
}
body {
    background: black;
    color: white;
    font-family: 'Helvetica Neue', sans-serif;
    font-size: 1.2em;
    line-height: 1.4em;
}

a {
  color: white;
}

.clear {
  clear: both; float: none; height: 40px;
}

/* Ellipse */

#ellipse {
  position: absolute;
  top: 120px;
  z-index:99;
  animation: 3s linear 0s slide 1;
  left: -200px;
}

/*
.ellipse_left {left: -200px;}
.ellipse_right {right: -200px;}
*/


/* Masquarede Logo */

img.masquarade_events {
  opacity: 0.3;
  position: absolute;
  bottom: 20px;
  right: 20px;
}

img.masquarade_events:hover {
  opacity: 0.9;
}


/* Content */

.content {
  margin: 150px 0 0 300px;
  width: 700px;
  height: 400px;
}

@media screen and (max-width: 992px) {
  .content {
    margin: 150px 0 0 0;
    width: 700px;
    height: 400px;
  }
}

.date {
  font-weight: bold;
  margin-bottom: -10px;
}

.location {
}

ul.lineup {
  list-style-position: inside;
  padding: 0;
  list-style-type: none;
  width: 100%
  overflow: hidden;
  margin-bottom: 100px;
}

ul.lineup li {
  margin-right: 50px;
  line-height: 2.5em;
  float: left;
}


/* Buttons */

a.button {
  margin-right: 10px;
  padding: 10px 50px 10px 50px;
  text-decoration: none;
  border-radius: 200px;
  font-size: 0.7em;
  transition: 0.3s;
}

a.white {
  background: white;
  color: black;
}

a.white:hover {
  color: white;
  background: #D90E46;
}

a.black {
  border: 2px white solid;
  color: white;
}

a.black:hover {
  border: 2px #FCF454 solid;
  color: #FCF454;
}

/* Header  */

header {
  position: absolute;
  background-color: black;
  top:0;
  left:0;
  width: 0;
  height: 100%;
  z-index: 1;
}
/* Header animation css  */
header.open {
  width: 100%;
}

/* Navigation  */

header nav {
  position: absolute;
  top: 100px;
  right:300px;
}

nav ul {
  list-style-position: inside;
  width: 400px;
  padding: 0;
  list-style-type: none;
  font-size: 1em;
}

nav ul li{
  border-bottom: 1px solid white;
  padding: 10px 0 10px 0;
}

nav ul li:hover{
  font-weight: bold;
  padding: 10px 0 10px 10px;
}

li.active {
  font-weight: bold;
}

nav ul li:first-child{
/*  border-top: 1px solid white;*/
}

nav ul li a{
  text-decoration: none;
}

nav ul h2{
  margin-bottom: 10px;
}

.tabcontent {
  display: none;
}

/* Header Icon */

img.icon {
  position: absolute;
  z-index: 999;
  top:60px;
  right:70px;
}

/* Display */

.display {
  width: 400px;
  height: 400px;
  position: absolute;
  top: 100px;
  right:750px;
}

.display p {
  margin:0 30px 30px 0;
}
<!doctype html>
<html lang="en">
  <head>
    <!-- SETUP Industries - FUNCTIONAL DESIGN -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- <link rel="shortcut icon" type="image/png" href="favicon.png"/> -->


    <!-- CSS -->
    <link rel="stylesheet" type="text/css" href="assets/style.css" />
   <link href="https://fonts.googleapis.com/css?family=Heebo:400,700,900" rel="stylesheet">

    <!-- JS -->
    <script src="assets/javascript.js"></script>


    <title>Masquarade Classix 2019</title>
  </head>
  <body>

  <!-- Navigation -->

    <!-- Icon -->
    <img onclick="openNav()"id="icon" src="http://setup.industries/masquarade/assets/icon.svg" class="icon" width="40" alt="Expand Navigation" />
    <header id="header">

      <nav>
        <ul>
          <h2>Information</h2>
          <li class="tablinks" onmouseover="openTab(event, 'Tickets')"><a href="#">Tickets and pricing </a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Location')"><a href="#">Location</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Transportation')"><a href="#">Transportation</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Amenities')"><a href="#">Ameneties</li>
          <li class="tablinks" onmouseover="openTab(event, 'HouseRules')"><a href="#">House rules</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'TermsAndConditions')"><a href="#">Terms and conditions</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Contact')"><a href="#">Contact</a></li>
          <li class="tablinks" onmouseover="openTab(event, 'Partners')"><a href="#">Partners</a></li>
        </ul>
      </nav>


<div class="display">


      <div id="Tickets" class="tabcontent">
          <h2>Tickets and pricing</h2>
          <p>Saturday day tickets cost 45 EUR incl. service costs and 21% BTW. You can buy tickets online via the button below or at one of the resellers listed below.</p>
          <a href="#" class="button white">Buy Tickets</a>
          <br><br>
          <p style="font-size:0.8em;"> <strong>Paperpoint</strong><br>
            3930 Hamont-achel<br><br>
            <strong>Dag en nachtwinkel </strong><br>
            3900 Overpelt<br><br>
            <strong>VDM bvba, Q8 tankstation</strong> <br>
            Peer<br><br>
            <strong>Frituur De Kromme Draai</strong> <br>
            Eksel<br><br>
            <strong>’t frituurke</strong> <br>
            Haag 22, 3910 Achel<br></p>
      </div>

      <div id="Location" class="tabcontent">
          <h2>Location</h2>
      </div>

      <div id="Transportation" class="tabcontent">
          <h2>Transportation</h2>
      </div>

      <div id="Amenities" class="tabcontent">
          <h2>Amenities</h2>
      </div>

      <div id="HouseRules" class="tabcontent">
          <h2>House Rules</h2>
      </div>

      <div id="TermsAndConditions" class="tabcontent">
          <h2>Terms And Conditions</h2>
      </div>

      <div id="Contact" class="tabcontent">
          <h2>Contact</h2>
      </div>

      <div id="Partners" class="tabcontent">
          <h2>Partners</h2>
      </div>



</div>


    </header>
  <!-- Navigation End -->
<div class="container">
    <div id="ellipse" class="ellipse_left">
      <img src="assets/ellipse.svg" alt="ellipse" width="400" height="400"/>
    </div>
    <img class="masquarade_events" src="assets/masquarade_events.png" alt="Masquarade Events" width="125" height=""/>
<div class="content">

    <p class="date">25 mei 2019</p>
    <p class="location">Hennemeeuwis Neerpelt</p>
    <h1>Masquarade Classix </h1>
    <ul class="lineup">
        <li>Nina Kraviz</li>
        <li>Recondite</li>
        <li>Mind Against</li>
        <li>Âme</li>
        <li>Vince Watson</li>
        <li>Kölsch</li>
        <li>Rodriguez Jr. </li>
        <li></li>
    </ul>
<div class="clear"></div>

    <a href="#" class="button white">Buy Tickets</a>
    <a href="#" class="button black">More Information</a>

</div>
</div>

  </body>
</html>


1
元素的style属性的值可以通过JavaScript或内联样式属性来设置,CSS不会为您设置该值。因此,如果您使用CSS来为标题设置宽度,则header.style.width的初始值将为空字符串,使得表达式header.style.width == '0%'为假。
您可以添加console.log(document.getElementById('header').style.width)来检查值。
因此,第一次单击汉堡包时,条件语句中的else块总是会运行。
在第一次单击汉堡包后,document.getElementById('header').style.width现在通过JavaScript进行设置,因此随后的单击将按预期进行。
要解决问题,您可以使用内联样式属性来设置标题的宽度,或者可以使用JavaScript获取样式。
const headerWidth = getComputedStyle(document.getElementById('header')).width;
const open = headerWidth === '0px' || headerWidth === '0%';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接