在输入事件侦听器上切换点击处理函数 — Javascript

Toggling A Click Handler Function On an Input Event Listener — Javascript

我正在设置一个表单,该表单通过 PHP 提交到 MySQL 数据库,并且出于安全原因进行了 server-side 验证。我希望使用 JavasScript 处理前端验证消息,因为站点上有许多类似的表单,并且希望将这些链接到 input 事件侦听器。

在下面的代码中,提交按钮有一个 preventDefault() 方法,直到标题超过 10 个字符。我读到添加和删除 preventDefault 的最佳方法是通过我正在使用的点击处理函数。

默认情况下,button 上有一个 .prevent-default class,当输入通过验证时,它会被删除。

我遇到的问题

如果在输入的字符少于 10 个时提交表单,preventDefault 和错误消息会起作用,当然,如果输入的字符超过 10 个,表单将按预期提交。

但是,当最初输入超过 10 个字符,然后用户删除一些字符使计数回到 10 以下时,表单仍然在前端提交?我希望它再次失败,在单击提交按钮后显示相同的错误消息。

我认为解决方案是切换 checkValidations() 功能。不过我好像做不到。

注意: 一些元素使用 forEach 循环,因为在整个站点上将有多个表单实例。

CodePen Link: https://codepen.io/thechewy/pen/GROEmoN

var dmForm = document.querySelector("form"),
    
// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"), 
dmTitle = document.querySelector("#dm-title"),
    
// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")

// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
    evt.preventDefault()
    if(dmTitle.value.length < 10) {
        dmTitleError.classList.add('warning')
        dmTitleError.textContent = "Title must be more than 10 characters"
    }
}

// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
  preventSubmit.forEach(item => {
    item.addEventListener('click', clickHandler, false)
})
  
  // removes warning when the user types more than 10 characters
  if (dmForm) {
    dmTitle.addEventListener('input', () => {
      if( dmTitle.value.length > 10) {
        dmTitleError.classList.remove('warning')
        dmTitleError.textContent = ""
        
        // call the function that removes the preventDefault method
        checkValidations()
      }
    })
  }

function checkValidations(){
  if (dmTitle.value.length > 10) {
    preventSubmit.forEach(item => {
      item.removeEventListener('click', clickHandler, false)
      item.classList.remove('prevent-submit')
    })
  }
}
  
} // end of 'if (preventSubmit)' statement
body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

input,
button {
  padding: 0.5rem;
}

.js-error-message.warning {
    background: #cc1f1f;
    transition: background .5s;
    padding: 0.2rem 0.5rem;
    margin-top: 0.5rem;
    display: inline-block;
    position: absolute;
    bottom: -5rem;
}
<form method="post">
  <div class="input-wrapper">
    <input id="dm-title" name="dm-title">
    <p class="js-error-message js-dm-title-error"></p>
  </div>
  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>

看起来你每次都需要删除验证,如果检测到错误,只需执行preventDefault

var dmForm = document.querySelector("form"),
    
// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"), 
dmTitle = document.querySelector("#dm-title"),
    
// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")

// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
    
    if(dmTitle.value.length < 10) {
        dmTitleError.classList.add('warning')
        dmTitleError.textContent = "Title must be more than 10 characters"
evt.preventDefault(); // <-- prevent from sending and show warning
    }
}

// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
  preventSubmit.forEach(item => {
    item.addEventListener('click', clickHandler, false)
})
  
  // removes warning when the user types more than 10 characters
  if (dmForm) {
    dmTitle.addEventListener('input', () => {
      if( dmTitle.value.length > 10) {
        dmTitleError.classList.remove('warning')
        dmTitleError.textContent = ""
      }
        
        
    })
  }

  
  
} // end of 'if (preventSubmit)' statement
body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

input,
button {
  padding: 0.5rem;
}

.js-error-message.warning {
    background: #cc1f1f;
    transition: background .5s;
    padding: 0.2rem 0.5rem;
    margin-top: 0.5rem;
    display: inline-block;
    position: absolute;
    bottom: -5rem;
}
<form method="post">
  <div class="input-wrapper">
    <input id="dm-title" name="dm-title">
    <p class="js-error-message js-dm-title-error"></p>
  </div>
  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>

如果使用内置的 DOM Constraint Validation API :

则更容易实现

let form = document.querySelector("form");
let error = document.querySelector(".js-dm-title-error")
let title = document.getElementById('dm-title');

title.setAttribute("minLength", '10');

title.addEventListener('input', function(e) {
  if (!title.validity.valid) {
    // if you want to nag on every character entered
    //showError("Title must be more than 10 characters");
  } else {
    showError('');
  }
});

form.addEventListener('submit', function(event) {
  // check each field
  if (!title.validity.valid) {
    showError("Title must be more than 10 characters");
    event.preventDefault();
    return false;
  }

  // mimicking form submit
  output.innerHTML += `Sending ${title.value}...<br>`;
  event.preventDefault();
  return false;
});

function showError(msg) {
  if (msg) {
    error.classList.add('warning')
    error.textContent = msg;
  } else {
    error.classList.remove('warning');
  }
}
body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
}

input {
  display: block;
  margin-right: 0.5rem;
  border-radius: 0.3rem;
}

input:invalid {
  background-color: rgb(255, 220, 220);
}

input:invalid:required {
  border: 1px dashed red;
}

input:valid {
  background-color: rgb(211, 255, 211);
}

.js-error-message {
  display: none;
  position: absolute;
  top: 100%;
}

.js-error-message.warning {
  display: inline-block;
  padding: .2rem;
  width: 169px;
  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;
  box-sizing: border-box;
}
<form method="post" novalidate>
  <div class="input-wrapper">
    <input id="dm-title" name="dm-title" required>
    <div class="js-error-message js-dm-title-error"></div>
  </div>
  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form><br>
<div id=output></div>

检查form.onsubmit事件会更合适。

https://codepen.io/_yigitt/pen/JjOpmPW

form1.onsubmit = function () {
    if (inputFirstName.value.length < 10) {
        p_error.classList.add("warning");
        p_error.textContent = "Title must be more than 10 characters";
        return false;
    }
};

inputFirstName.oninput = function () {
    if (this.value.length > 10) {
        p_error.classList.remove("warning");
        p_error.textContent = "";
    }
};

所需的验证已内置 -- 不需要 JavaScript。当出现真正的错误时,闪烁错误消息是更好的用户体验。当您刚开始输入时,看到有关未满足要求的消息弹出,这让人很恼火。最好只在提交事件中显示错误消息。

下例中的输入有两个属性:

  • minlength="11" 提交时如果输入的字符少于或等于 10 个,表单将停止提交并弹出错误消息。

  • required提交时如果input为空,表单将停止提交并弹出错误信息

此外,在这个简单的验证中没有奇怪的行为(例如输入 12 个字符,删除 5 个字符并成功提交)。同样在示例中,数据被发送到实时测试服务器并且 iframe 在那里显示服务器响应。

<!DOCTYPE html>
<html lang="en">

<head>
  <title></title>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <style>
    *,
    *::before,
    *::after {
      box-sizing: border-box;
    }
    
     :root {
      font: 1ch/1.25 'Segoe UI';
    }
    
    html,
    body {
      width: 100%;
      min-height: 100%;
      margin: 0;
      padding: 0;
    }
    
    body {
      display: flex;
      flex-flow: row nowrap;
      justify-content: center;
      align-items: center;
      font-size: 2.5rem;
    }
    
    main {
      width: 100%;
      height: 100%;
      margin: 0 auto;
    }
    
    input,
    output,
    button {
      display: inline-block;
      font-size: 100%;
    }
    
    input,
    output {
      font-family: Consolas;
      line-height: 1.15;
    }
    
    button {
      width: max-content;
      padding: 2px 4px;
      border-radius: 4px;
    }
  </style>
</head>

<body>
  <main>
    <form action='https://httpbin.org/post' method="post" target='response'>
      <fieldset>
        <legend>Direct Message</legend>
        <input id="message" name="message" minlength='11' required>
        <button name='btn'>Send Message</button>
      </fieldset>
      <fieldset>
        <legend>Server Response</legend>
        <iframe name='response'></iframe>
      </fieldset>
    </form>
  </main>
  <script></script>
</body>

</html>