【问题标题】:HTML 5 Validation CustomizationHTML 5 验证自定义
【发布时间】:2022-11-23 01:33:44
【问题描述】:

我想要一个表格:

  1. 以自定义格式而不是默认样式显示验证消息。
  2. 一次显示所有无效字段气泡,而不是一次显示一个。

    现在,我受困于无聊的特定于浏览器的消息外观,在我更正最后一个错误之前我看不到下一个错误。这是一个非常糟糕的用户体验,所以寻找一些关于如何解决这个问题的建议。

    这是我当前的 JavaScript 代码:

    const contactUsForm = document.querySelector('#Form');
    
    if (contactUsForm) {
    
        function Validate() {
        
            validatedFields = contactUsForm.querySelectorAll('[data-validation-required],[data-validation-format]');
            validatedFields.forEach(field => {
                /* RegEx patterns */
                const emailPattern = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;
                    
                if (field.getAttribute('type') === 'email')
                {
                    field.setAttribute('pattern', emailPattern);
                }
    
    
                if (field.validity.valueMissing) {
                    field.setCustomValidity(field.dataset.validationRequired);
                }
                else if (field.validity.patternMismatch) {
                    field.setCustomValidity(field.dataset.validationFormat);
                }
                else {
                    field.setCustomValidity('');
                }
    
                
                field.reportValidity();
                contactUsForm.checkValidity();
    
    
                /* Recheck on field value change */
                field.addEventListener('change', function() {
                    field.setCustomValidity('');
                    Validate();
                });
            });
        }
    
        Validate();
        
        
        contactUsForm.addEventListener('submit', function(e) {
            e.preventDefault;
            
            if (e.checkValidity() == false) {
                return false;
            }
            else {
                // form.submit()
            }
        });
    
    }
    
    

【问题讨论】:

    标签: javascript html validation


    【解决方案1】:

    样式验证气泡/工具提示曾经是 Chrome 独有的功能,但已被删除。 有关它的更多信息,请访问: How do you style the HTML5 form validation messages?

    然而,您可以创建自己的工具提示或气泡来显示验证消息.通过使用一个 div 容器和一个 span 以及一点点 CSS,您可以创建一个具有几乎任何您可以想象的外观的气泡。

    .ttCont {
      position: relative;
      display: inline-block;
    }
    .ttCont .ttText {
      display: inline-block;
      visibility: hidden;
      min-width: 200px;
      background-color: darkblue;
      color: #fff;
      text-align: center;
      border-radius: 6px;
      padding: 5px;
      opacity: 0;
      transition: opacity 0.5s;
    
      /* Place bubble to the right of container */
      position: absolute;
      z-index: 1;
      top: 5px;
      left: 105%;
    }
    .ttCont .ttText::after {
      content: " ";
      position: absolute;
      top: 50%;
      right: 100%; /* To the left of the bubble */
      margin-top: -5px;
      border-width: 5px;
      border-style: solid;
      border-color: transparent darkblue transparent transparent;
    }
    .ttCont .ttText.active{
      visibility: visible;
      opacity: 1;
    }

    现在使用自定义气泡意味着您可能需要使用更少的 ValidityState API,但是您仍然可以使用相同的方法验证您的字段。除了使用 field.reportValidity(),您还可以创建一个自定义函数,在每个字段验证时显示一个气泡

    function customReportValidatity(elem, type) {
      let msg = "";
      ///check if validity is based on required or mismatch///
      switch (type) {
        case 'required':
          msg = $(elem).attr('data-validation-required');
          ///without jQuery
          // msg = elem.dataset.validationRequired;
          break;
        case 'format':
          msg = $(elem).attr('data-validation-format');
          ///without jQuery
          // msg = elem.dataset.validationFormat;
          break;
        default:
          break;
      }
      ///make popup appear///
    
      let ttText = $(elem).parent().children('.ttText');
      $(ttText).text(msg);
      $(ttText).addClass('active');
    
      ///without jQuery
      // let ttText = elem.parentElement.querySelector('.ttText');
      // ttText.innerText = msg;
      // ttText.classList.add('active');
    
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>

    使用该样式和自定义函数,您可以将其应用于您愿意应用的任何表单的现有代码。在这种情况下,我制作了一个示例表单,其中包含需要的姓名和电子邮件,而不需要描述。

    const contactUsForm = document.querySelector('#Form');
    const submitBtn = document.querySelector('#submitBtn');
    
    if (contactUsForm) {
      function customReportValidatity(elem, type) {
        let msg = "";
        ///check if validity is based on required or mismatch///
        switch (type) {
          case 'required':
            msg = $(elem).attr('data-validation-required');
            ///without jQuery
            // msg = elem.dataset.validationRequired;
            break;
          case 'format':
            msg = $(elem).attr('data-validation-format');
            ///without jQuery
            // msg = elem.dataset.validationFormat;
            break;
          default:
            break;
        }
        ///make popup appear///
    
        let ttText = $(elem).parent().children('.ttText');
        $(ttText).text(msg);
        $(ttText).addClass('active');
    
        ///without jQuery
        // let ttText = elem.parentElement.querySelector('.ttText');
        // ttText.innerText = msg;
        // ttText.classList.add('active');
    
      }
    
      function Validate() {
        let isValid = true;
    
        /* RegEx patterns */
        const emailPattern = /^((([a-z]|d|[!#$%&'*+-/=?^_`{|}~]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])+(.([a-z]|d|[!#$%&'*+-/=?^_`{|}~]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])+)*)|((")(((( |	)*(
    ))?( |	)+)?(([--]|!|[#-[]|[]-~]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(\([-	
    -]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))))*((( |	)*(
    ))?( |	)+)?(")))@((([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])*([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))).)+(([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])*([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])))$/i;
    
        let validatedFields = contactUsForm.querySelectorAll('[data-validation-required],[data-validation-format]');
        validatedFields.forEach(field => {
    
          if (field.getAttribute('type') === 'email') {
            field.setAttribute('pattern', emailPattern);
          }
    
          if (field.validity.valueMissing) {
            field.setCustomValidity(field.dataset.validationRequired);
            customReportValidatity(field, 'required');
            isValid = false;
          } else if (field.validity.typeMismatch) {
            //using typeMismatch instead of patternMismatch because the regex is not working for emails
            field.setCustomValidity(field.dataset.validationFormat);
            customReportValidatity(field, 'format');
            isValid = false;
          }
    
          contactUsForm.checkValidity();
    
    
          /// Recheck on field value change ///
          field.addEventListener('change', function() {
            $('.ttText').removeClass('active');
    
            ///without jquery
            /*document.querySelectorAll('.ttText').forEach((tt)=>{
              tt.classList.remove('active');
            });*/
    
            Validate();
          });
    
        });
        return isValid;
      }
    
      submitBtn.addEventListener('click', function(e) {
        e.preventDefault();
        e.stopPropagation();
    
        if (Validate()) {
          // contactUsForm.submit();
          //you can use this output to check if the form will submit
          console.log("Form Submitted!");
        } else {
          return false;
        }
    
      });
    
    }
    .ttCont {
      position: relative;
      display: inline-block;
    }
    
    .ttCont .ttText {
      display: inline-block;
      visibility: hidden;
      min-width: 200px;
      background-color: darkblue;
      color: #fff;
      text-align: center;
      border-radius: 6px;
      padding: 5px;
      opacity: 0;
      transition: opacity 0.5s;
      position: absolute;
      z-index: 1;
      top: 5px;
      left: 105%;
    }
    
    .ttCont .ttText::after {
      content: " ";
      position: absolute;
      top: 50%;
      right: 100%;
      margin-top: -5px;
      border-width: 5px;
      border-style: solid;
      border-color: transparent darkblue transparent transparent;
    }
    
    .ttCont .ttText.active {
      visibility: visible;
      opacity: 1;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
    <form id="Form">
      <div class="ttCont">
        <label for="name">Name</label><br/>
        <input type="text" name="name" required data-validation-required="Name is required!" /><br/>
        <span class="ttText"></span>
      </div>
      <br/><br/>
    
      <div class="ttCont">
        <label for="email">Email</label><br/>
        <input type="email" name="email" required data-validation-required="Email is required" data-validation-format="Email must have the format similar to example@email.com!" /><br/>
        <span class="ttText"></span>
      </div>
      <br/><br/>
    
      <div class="ttCont">
        <label for="desc">Description</label><br/>
        <input type="text" name="desc" data-validation-required="Description is required!" /><br/>
        <span class="ttText"></span>
      </div>
      <br/><br/>
    
      <button type="button" id="submitBtn">Submit</button>
    </form>

    您可以在此处阅读有关如何创建和处理自定义工具提示的更多信息:

    【讨论】:

    • 太棒了,这让我朝着正确的方向前进。出于某种原因,我唯一似乎不起作用的部分是我的正则表达式(如您所述)。我将单独追逐。全部解决后,我将发布最终解决方案。
    猜你喜欢
    • 2015-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-01
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多