【问题标题】:CSS Animation Issue - Button AnimationCSS 动画问题 - 按钮动画
【发布时间】:2022-01-29 13:25:18
【问题描述】:

我有以下代码:

var basicTimeline = anime.timeline({
  autoplay: false,
});

var pathEls = $(".check");
for (var i = 0; i < pathEls.length; i++) {
  var pathEl = pathEls[i];
  var offset = anime.setDashoffset(pathEl);
  pathEl.setAttribute("stroke-dashoffset", offset);
}

basicTimeline
  .add({
    targets: ".text",
    duration: 1,
    opacity: "0"
  })
  .add({
    targets: ".button",
    duration: 1300,
    height: 20,
    width: 81,
    backgroundColor: "#717F7E",
    border: "0",
    zIndex: 0,
    borderRadius: 100
  })
  .add({
    targets: ".progress-bar",
    duration: 2000,
    width: 81,
    easing: "linear"
  })
  .add({
    targets: ".button",
    width: 0,
    duration: 1
  })
  .add({
    targets: ".progress-bar",
    width: 40,
    height: 39,
    delay: 500,
    duration: 750,
    borderRadius: 80,
    backgroundColor: "#71DFBE",
    left: 20
  })
  .add({
    targets: pathEl,
    strokeDashoffset: [offset, 0],
    duration: 200,
    easing: "easeInOutSine"
  });


$(".button").click(playButtonAnim);

$(".text").click(playButtonAnim);

function playButtonAnim() {
  basicTimeline.play();
}

//error animation
const form = document.forms.myform;
form.onsubmit = e => {
  e.preventDefault()
  let data = Object.fromEntries(new FormData(form).entries())

  console.log(data)

  let validationOK = true
  for (let entrie in data) {
    if (!form[entrie].checkValidity()) {
      validationOK = false
      form[entrie].classList.add('shakingErr')
      setTimeout(() => {
        form[entrie].classList.remove('shakingErr')
      }, 820)
    }
  }
  if (validationOK) {
    fetch(form.action, {
        method: form.method,
        body: JSON.stringify(data),
        headers: {
          Accept: 'application/json'
        }
      })
      .finally(() => {
        window.location = "thankyou.html"
      })
  }
}
/* Contact Form */

input[type=text],
[type=email],
select,
textarea {
  width: 100%;
  padding: 12px;
  border: 1px solid #555;
  margin-top: 6px;
  margin-bottom: 16px;
  resize: vertical;
}

input[type="text"]:focus,
input[type="email"]:focus,
#subject:focus {
  background: var(--bgFormElsFocus);
  transform: scale(1.02);
  transition: transform 0.2s ease-in-out;
}

.contactform {
  position: relative;
  border-radius: 50px;
  background-color: #f2f2f2;
  padding: 5px;
  z-index: 2;
  display: block;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: auto;
  margin-top: 1%;
  width: 100%;
  animation-name: gradient;
  animation-duration: 3s;
  animation-iteration-count: infinite;
}

.contactform:hover {
  animation-name: gradient;
  animation-duration: 15s;
  animation-iteration-count: infinite;
}

.column {
  float: center;
  width: 50%;
  margin-top: 6px;
  padding: 20px;
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.row:after {
  content: "";
  display: table;
  clear: both;
}

@media screen and (max-width: 600px) {
  .column,
  input[type=submit] {
    width: auto;
    margin-top: 0;
  }
}

.shakingErr {
  border-color: red;
  animation: shake 0.82s forwards;
}

@keyframes shake {
  10%,
  90% {
    transform: translate3d(-1px, 0, 0);
  }
  20%,
  80% {
    transform: translate3d(2px, 0, 0);
  }
  30%,
  50%,
  70% {
    transform: translate3d(-4px, 0, 0);
  }
  40%,
  60% {
    transform: translate3d(4px, 0, 0);
  }
}


/* fancy button styles */

.buttonWrapper {
  height: 39px;
  width: 81px;
  position: relative;
}

.button {
  background: #2B2D2F;
  height: 39px;
  width: 81px;
  text-align: center;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  cursor: pointer;
  border-radius: 4px;
  z-index: 10;
}

.text {
  font: .8rem/1 poppins;
  color: #71DFBE;
  position: absolute;
  top: 50%;
  transform: translateY(-52%);
  left: 0;
  right: 0;
  cursor: pointer;
}

.progress-bar {
  position: absolute;
  height: 20px;
  width: 0;
  left: 40px;
  top: 50%;
  border-radius: 200px;
  transform: translateY(-50%) translateX(-50%);
  background: black;
}

svg {
  width: 15px;
  position: absolute;
  top: 50%;
  left: 20px;
  transform: translateY(-50%) translateX(-8px);
}

.check {
  fill: none;
  stroke: #FFFFFF;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>replit</title>
  <link href="style.css" rel="stylesheet" type="text/css" />
  <link href="https://fonts.googleapis.com/css?family=Poppins:600" rel="stylesheet">
  <link href="https://fonts.googleapis.com/css?family=Poppins:600" rel="stylesheet">
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.0.2/anime.js">
  </script>

</head>

<body>
  <!-- start contact section -->
  <section id="contact">
    <div class="container" data-aos="fade-up">
      <div class="contactform">
        <div style="text-align:center">
          <div class="section-title">
            <h2><br />Get In Touch</h2>
          </div>
          <p>Feel Free To Reach Out To Me Through This Form! </p>
        </div>
        <div class="row">
          <div class="column">
            <form name="myform" action="https://formspree.io/f/xrg123232jbqpq" id="my-form" method="POST" novalidate>
              <label for="firstname">First Name</label>
              <input type="text" id="first name" name="firstname" placeholder="Your First Name.." required>
              <label for="lastname">Last Name</label>
              <input type="text" id="lastname" name="lastname" placeholder="Your Last Name.." required>
              <label for="email">Email:</label>
              <input type="email" id="email" name="email" placeholder="Your Email.." required>
              <label for="subject">Subject</label>
              <textarea id="subject" name="subject" placeholder="Lets Collaborate.." style="height:170px" required></textarea>
              <!-- <input type="submit" value="Submit"> -->
              <div class='buttonWrapper'>
                <div class="button">
                  <div class="text">Submit</div>
                </div>
                <div class="progress-bar"></div>
                <svg x="0px" y="0px" viewBox="0 0 25 30" style="enable-background:new 0 0 25 30;">
                  <path class="check" class="st0" d="M2,19.2C5.9,23.6,9.4,28,9.4,28L23,2" />
                </svg>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </section>
  <script src="script.js"></script>
</body>

</html>

我面临的唯一问题是,即使我在从 CSS 调用 shakingErr 类的 JS 中有错误动画代码,但当用户单击提交时动画似乎不起作用/错误的字段。我怎样才能使当用户单击提交按钮时,联系表单有一个摇晃的错误按钮。

请注意,当您单击提交按钮时,按钮上还会播放动画?我不希望当用户单击空白字段上的提交按钮时播放该动画。我只想在用户填写输入字段中的所有信息后播放动画。

有什么建议吗?

预期输出

https://watch.screencastify.com/v/D2VXp3493XZXl3Lmh7yR

如您所见,每当用户尝试单击空/错误字段(电子邮件)上的提交按钮时,就会播放错误动画。此外,当用户单击空/错误字段上的提交按钮时,不应播放按钮动画。一旦字段被填满并且正确,它应该会播放。

有什么建议吗?

【问题讨论】:

    标签: javascript html jquery css sass


    【解决方案1】:

    首先,出于语义原因,我建议将提交按钮的 HTML 更改为类似的内容。

    <button class="button" type="submit">
       <div class="text">Submit</div>
    </button>
    

    那么,用户点击提交按钮后发生的情况会被认为是:

    $(".button").click(function(e) {
      e.preventDefault();
      let validationOK = true;
      
      // validate data
      const form = document.forms.myform;
        let data = Object.fromEntries(new FormData(form).entries())
        for (let entrie in data) {
          if (!form[entrie].checkValidity()) {
            validationOK = false;
    
            // error animation
            form[entrie].classList.add('shakingErr')
            setTimeout(() => {
              form[entrie].classList.remove('shakingErr')
            }, 820)
          }
        }
        
      if (validationOK) {
        basicTimeline.play();
    
        // your submit action
      }
    });
    

    var basicTimeline = anime.timeline({
      autoplay: false,
    });
    
    var pathEls = $(".check");
    for (var i = 0; i < pathEls.length; i++) {
      var pathEl = pathEls[i];
      var offset = anime.setDashoffset(pathEl);
      pathEl.setAttribute("stroke-dashoffset", offset);
    }
    
    basicTimeline
      .add({
        targets: ".text",
        duration: 1,
        opacity: "0"
      })
      .add({
        targets: ".button",
        duration: 1300,
        height: 20,
        width: 81,
        backgroundColor: "#717F7E",
        border: "0",
        zIndex: 0,
        borderRadius: 100
      })
      .add({
        targets: ".progress-bar",
        duration: 2000,
        width: 81,
        easing: "linear"
      })
      .add({
        targets: ".button",
        width: 0,
        duration: 1
      })
      .add({
        targets: ".progress-bar",
        width: 40,
        height: 39,
        delay: 500,
        duration: 750,
        borderRadius: 80,
        backgroundColor: "#71DFBE",
        left: 20
      })
      .add({
        targets: pathEl,
        strokeDashoffset: [offset, 0],
        duration: 200,
        easing: "easeInOutSine"
      });
    
    
    $(".button").click(function(e) {
      e.preventDefault();
      let validationOK = true;
      
      const form = document.forms.myform;
        let data = Object.fromEntries(new FormData(form).entries())
        for (let entrie in data) {
          if (!form[entrie].checkValidity()) {
            validationOK = false
            form[entrie].classList.add('shakingErr')
            setTimeout(() => {
              form[entrie].classList.remove('shakingErr')
            }, 820)
          }
        }
        
      if (validationOK) {
        basicTimeline.play();
        
        // submit action
        fetch(form.action, {
            method: form.method,
            body: JSON.stringify(data),
            headers: {
              Accept: 'application/json'
            }
          })
          .finally(() => {
            window.location = "thankyou.html"
          })
      }
    });
    /* Contact Form */
    
    input[type=text],
    [type=email],
    select,
    textarea {
      width: 100%;
      padding: 12px;
      border: 1px solid #555;
      margin-top: 6px;
      margin-bottom: 16px;
      resize: vertical;
    }
    
    input[type="text"]:focus,
    input[type="email"]:focus,
    #subject:focus {
      background: var(--bgFormElsFocus);
      transform: scale(1.02);
      transition: transform 0.2s ease-in-out;
    }
    
    .contactform {
      position: relative;
      border-radius: 50px;
      background-color: #f2f2f2;
      padding: 5px;
      z-index: 2;
      display: block;
      margin-left: auto;
      margin-right: auto;
      margin-bottom: auto;
      margin-top: 1%;
      width: 100%;
      animation-name: gradient;
      animation-duration: 3s;
      animation-iteration-count: infinite;
    }
    
    .contactform:hover {
      animation-name: gradient;
      animation-duration: 15s;
      animation-iteration-count: infinite;
    }
    
    .column {
      float: center;
      width: 50%;
      margin-top: 6px;
      padding: 20px;
      display: block;
      margin-left: auto;
      margin-right: auto;
    }
    
    .row:after {
      content: "";
      display: table;
      clear: both;
    }
    
    @media screen and (max-width: 600px) {
      .column,
      input[type=submit] {
        width: auto;
        margin-top: 0;
      }
    }
    
    form .shakingErr {
      border-color: red;
      animation: shake 0.82s forwards;
    }
    
    @keyframes shake {
      10%,
      90% {
        transform: translate3d(-1px, 0, 0);
      }
      20%,
      80% {
        transform: translate3d(2px, 0, 0);
      }
      30%,
      50%,
      70% {
        transform: translate3d(-4px, 0, 0);
      }
      40%,
      60% {
        transform: translate3d(4px, 0, 0);
      }
    }
    
    
    /* fancy button styles */
    
    .buttonWrapper {
      height: 39px;
      width: 81px;
      position: relative;
    }
    
    .button {
      background: #2B2D2F;
      height: 39px;
      width: 81px;
      text-align: center;
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      left: 0;
      cursor: pointer;
      border-radius: 4px;
      z-index: 10;
    }
    
    .text {
      font: .8rem/1 poppins;
      color: #71DFBE;
      position: absolute;
      top: 50%;
      transform: translateY(-52%);
      left: 0;
      right: 0;
      cursor: pointer;
    }
    
    .progress-bar {
      position: absolute;
      height: 20px;
      width: 0;
      left: 40px;
      top: 50%;
      border-radius: 200px;
      transform: translateY(-50%) translateX(-50%);
      background: black;
    }
    
    svg {
      width: 15px;
      position: absolute;
      top: 50%;
      left: 20px;
      transform: translateY(-50%) translateX(-8px);
    }
    
    .check {
      fill: none;
      stroke: #FFFFFF;
      stroke-width: 3;
      stroke-linecap: round;
      stroke-linejoin: round;
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>replit</title>
      <link href="style.css" rel="stylesheet" type="text/css" />
      <link href="https://fonts.googleapis.com/css?family=Poppins:600" rel="stylesheet">
      <link href="https://fonts.googleapis.com/css?family=Poppins:600" rel="stylesheet">
      <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.0.2/anime.js">
      </script>
    
    </head>
    
    <body>
      <!-- start contact section -->
      <section id="contact">
        <div class="container" data-aos="fade-up">
          <div class="contactform">
            <div style="text-align:center">
              <div class="section-title">
                <h2><br />Get In Touch</h2>
              </div>
              <p>Feel Free To Reach Out To Me Through This Form! </p>
            </div>
            <div class="row">
              <div class="column">
                <form name="myform" action="https://formspree.io/f/xrg123232jbqpq" id="my-form" method="POST" novalidate>
                  <label for="firstname">First Name</label>
                  <input type="text" id="first name" name="firstname" required placeholder="Your First Name.." required>
                  <label for="lastname">Last Name</label>
                  <input type="text" id="lastname" name="lastname" placeholder="Your Last Name.." required>
                  <label for="email">Email:</label>
                  <input type="email" id="email" name="email" placeholder="Your Email.." required>
                  <label for="subject">Subject</label>
                  <textarea id="subject" name="subject" placeholder="Lets Collaborate.." style="height:170px" required></textarea>
                  <!-- <input type="submit" value="Submit"> -->
                  <div class='buttonWrapper'>
                    <button class="button" type="submit">
                      <div class="text">Submit</div>
                    </button>
                    <div class="progress-bar"></div>
                    <svg x="0px" y="0px" viewBox="0 0 25 30" style="enable-background:new 0 0 25 30;">
                      <path class="check" class="st0" d="M2,19.2C5.9,23.6,9.4,28,9.4,28L23,2" />
                    </svg>
                  </div>
                </form>
              </div>
            </div>
          </div>
        </div>
      </section>
      <script src="script.js"></script>
    </body>
    
    </html>

    输入的 border-color 更新不会突出显示。

    这是一个 CSS 问题,错误 CSS 被默认输入样式覆盖。

    我们可以通过像这样更改选择器来使错误样式更强。

    form .shakingErr {
      border-color: red;
      animation: shake 0.82s forwards;
    }
    

    【讨论】:

    • 嘿,似乎有一个很小的问题。单击提交按钮时,前两个字段不会以红色突出显示。
    • 你说得对,我看到了,但这不是这个问题的重点,所以我忽略了它。无论如何,我刚刚更新了解决 CSS 问题的答案。
    • 嘿,你能帮我解决一个小问题吗?当你点击提交按钮并播放动画时,你可以看到当复选标记标志向左移动时,标志的背景中有一个小东西。我怎样才能删除它?
    猜你喜欢
    • 1970-01-01
    • 2014-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多