jQuery: 绑定点击事件后无法取消选中复选框

jQuery: Not able to uncheck checkbox after binding click event

使用 jQuery 验证插件作为基础,我创建了一个函数来验证字段而不使用表单。该函数还将事件绑定到表单元素以执行即时验证。

在某些情况下无法使用表单标签,因此创建了此功能。

除了复选框在第二次选中后无法选中外,一切似乎都正常工作。

请有人告诉我我做错了什么。

  

<html>
<head>
    <title></title>
</head>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
    jQuery(document).ready(function() {
        jQuery('#submit').click(function(){
            var options = {
                'name' : {
                    required: true
                },
                'email' : {
                    required: true,
                    email: true
                },
                'number' : {
                    required: true,
                    digits: true
                },
                'select' : {
                    required: true
                },
                'select-multiple' : {
                    required: true
                },
                'radio' : {
                    required: true
                },
                'checkbox' : {
                    required: true
                },
                'checkbox-single' : {
                    required: true
                },
                'multiple-emails' : {
                    required: true,
                    multipleEmails: true
                }
            };
        
            if(customValidation(options)){
                alert('Form validated!');
            }else{
                alert('Form not validated!');
            }
        });
    });

    function customValidation(options, bindEvents){
        var fieldsValid = true;
        bindEvents = (typeof bindEvents === 'undefined') ? true : bindEvents;
        var errorDiv = jQuery('#errorDiv');
        
        jQuery.each(options, function(elementIdorName, rules){
            var element = (jQuery('#' + elementIdorName).length) ? jQuery('#' + elementIdorName) : jQuery('input[name=' + elementIdorName + ']:first');
            var elementType = element.prop('type');
            var elementName = element.prop('name');
         
            var elementValid = true;
         
            // First remove any validation errors
            jQuery('.error-' + elementName).hide();
         
            jQuery.each(rules, function(rule, ruleOption){
                // Required
                if(rule == 'required' && ruleOption == true){
                    // Select
                    if(elementType && (elementType.toLowerCase() === 'select' || elementType.toLowerCase() === 'select-one' || elementType.toLowerCase() === 'select-mulitple')){
                        var val = element.val();
                        if(val && val.length > 0){
                            // Do nothing
                        }
                        else{
                            elementValid = false;
                        }
                    }
           
                    // Checkbox and Radio
                    if((/radio|checkbox/i).test(elementType)){
                        if(jQuery('input[name=' + elementName + ']:checked').length > 0){
                            // Do nothing
                        }
                        else{
                            elementValid = false;
                        }
                    }
           
                    // Text, Email, Number and Textarea
                    if(jQuery.trim(element.val()).length > 0){
                        // Do nothing
                    }
                    else{
                        elementValid = false;
                    }
           
                    if(!elementValid){
                        fieldsValid = false;
                        if(jQuery('.error-' + elementName).length == 0) {
                            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                        }
                        else{
                            jQuery('.error-' + elementName).show();
                        }
                    }
                }
          
                // Email
                if(rule == 'email' && ruleOption == true){
                    if((/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/).test(element.val())){
                        // Do nothing
                    }
                    else{
                        elementValid = false;
                    }
           
                    if(!elementValid){
                        fieldsValid = false;
                        if(jQuery('.error-' + elementName).length == 0) {
                            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                        }
                        else{
                            jQuery('.error-' + elementName).show();
                        }
                    }
                }
          
                // Number
                if(rule == 'number' && ruleOption == true){
                    if((/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/).test(element.val())){
                        // Do nothing
                    }
                    else{
                        elementValid = false;
                    }
           
                    if(!elementValid){
                        fieldsValid = false;
                        if(jQuery('.error-' + elementName).length == 0) {
                            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                        }
                        else{
                            jQuery('.error-' + elementName).show();
                        }
                    }
                }
          
                // Digits
                if(rule == 'digits' && ruleOption == true){
                    if((/^\d+$/).test(element.val())){
                        // Do nothing
                    }
                    else{
                        elementValid = false;
                    }
           
                    if(!elementValid){
                        fieldsValid = false;
                        if(jQuery('.error-' + elementName).length == 0) {
                            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                        }
                        else{
                            jQuery('.error-' + elementName).show();
                        }
                    }
                }
          
                // Multiple Emails
                if(rule == 'multipleEmails' && ruleOption == true){
                    var emailsArr = element.val().replace(/\s/g, '').split(/,|;/);

                    for(var i = 0; i < emailsArr.length; i++){
                        if((/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/).test(emailsArr[i])){
                            // Do nothing
                        }
                        else{
                            elementValid = false;
                        }
                    }
           
                    if(!elementValid){
                        fieldsValid = false;
                        if(jQuery('.error-' + elementName).length == 0) {
                            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                        }
                        else{
                            jQuery('.error-' + elementName).show();
                        }
                    }
                }
            });
         
            if(bindEvents){
                var currentOption = {};
                currentOption[elementIdorName] = rules;
          
                // Bind events to validate on the fly
                switch(elementType){
                    case 'text':
                    case 'email':
                    case 'number':
                    case 'textarea':
                        element.unbind('keyup.customValidation-' + elementName).bind('keyup.customValidation-' + elementName, function(e){
                            return customValidation(currentOption, false);
                        });
                        break;
                    case 'radio':
                    case 'checkbox':
                        jQuery('input[name=' + elementIdorName + ']').each(function (){
                            jQuery(this).unbind('click.customValidation-' + elementName).bind('click.customValidation-' + elementName, function(e){
                                return customValidation(currentOption, false);
                            });
                        });
                        break;
                    case 'select':
                    case 'select-one':
                    case 'select-multiple':
                        element.unbind('change.customValidation-' + elementName).bind('change.customValidation-' + elementName, function(e){
                            return customValidation(currentOption, false);
                        });
                        break;
                }
            }
        });
        
        return fieldsValid;
    }
</script>
<body>
    <div id="errorDiv">
    </div>
    <br />
    <br />
    <input type="text" name="name" id="name" />
    <br />
    <br />
    <input type="email" name="email" id="email" />
    <br />
    <br />
    <input type="number" name="number" id="number" />
    <br />
    <br />
    <select name="select" id="select">
        <option></option>
        <option>Option 1</option>
        <option>Option 2</option>
        <option>Option 3</option>
    </select>
    <br />
    <br />
    <select name="select-multiple" id="select-multiple" multiple>
        <option></option>
        <option>Option 1</option>
        <option>Option 2</option>
        <option>Option 3</option>
        <option>Option 4</option>
        <option>Option 5</option>
        <option>Option 6</option>
    </select>
    <br />
    <br />
    <input type="radio" name="radio" />Yes
       <input type="radio" name="radio" />No
       <br />
    <br />
    <input type="checkbox" name="checkbox" />Yes
       <input type="checkbox" name="checkbox" />No
       <br />
    <br />
    <input type="checkbox" name="checkbox-single" id="checkbox-single" />No
       <br />
    <br />
    <textarea name="multiple-emails" id="multiple-emails"></textarea>
    <br />
    <br />
    <button id="submit">Submit</button>
</body>
</html>

Example on JSFiddle

jQuery(document).ready(function() {
  jQuery('#submit').click(function() {
    var options = {
      'name': {
        required: true
      },
      'email': {
        required: true,
        email: true
      },
      'number': {
        required: true,
        digits: true
      },
      'select': {
        required: true
      },
      'select-multiple': {
        required: true
      },
      'radio': {
        required: true
      },
      'checkbox': {
        required: true
      },
      'checkbox-single': {
        required: true
      },
      'multiple-emails': {
        required: true,
        multipleEmails: true
      }
    };

    if (customValidation(options)) {
      alert('Form validated!');
    } else {
      alert('Form not validated!');
    }
  });
});

function customValidation(options, bindEvents) {
  /***
  Function is based on jQuery Validation Plugin v1.13.1 but doesn't require a <form> tag
 
  Add custom validations in this function as required
  
  Currently supported validations are:
  
  Required - Field cannot be blank
  Email - Validates an email address
  Mutliple Emails - Validates mutliple email addresses
  Number - Validates a decimal number
  Digits - Validates digits only
  
  Todo:
  
  Equal To validation
  Allow specifying parent element for Checkbox and Radio elements to apply an error class
  Allow specifying custom error and success functions through function parameter and individual options   
 ***/

  var fieldsValid = true;
  bindEvents = (typeof bindEvents === 'undefined') ? true : bindEvents;
  var errorDiv = jQuery('#errorDiv');

  jQuery.each(options, function(elementIdorName, rules) {
    var element = (jQuery('#' + elementIdorName).length) ? jQuery('#' + elementIdorName) : jQuery('input[name=' + elementIdorName + ']:first');
    var elementType = element.prop('type');
    var elementName = element.prop('name');

    var elementValid = true;

    // First remove any validation errors
    jQuery('.error-' + elementName).hide();

    jQuery.each(rules, function(rule, ruleOption) {
      // Required
      if (rule == 'required' && ruleOption == true) {
        // Select
        if (elementType && (elementType.toLowerCase() === 'select' || elementType.toLowerCase() === 'select-one' || elementType.toLowerCase() === 'select-mulitple')) {
          var val = element.val();
          if (val && val.length > 0) {
            // Do nothing
          } else {
            elementValid = false;
          }
        }

        // Checkbox and Radio
        if ((/radio|checkbox/i).test(elementType)) {
          if (jQuery('input[name=' + elementName + ']:checked').length > 0) {
            // Do nothing
          } else {
            elementValid = false;
          }
        }

        // Text, Email, Number and Textarea
        if (jQuery.trim(element.val()).length > 0) {
          // Do nothing
        } else {
          elementValid = false;
        }

        if (!elementValid) {
          fieldsValid = false;
          if (jQuery('.error-' + elementName).length == 0) {
            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
          } else {
            jQuery('.error-' + elementName).show();
          }
        }
      }

      // Email
      if (rule == 'email' && ruleOption == true) {
        if ((/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/).test(element.val())) {
          // Do nothing
        } else {
          elementValid = false;
        }

        if (!elementValid) {
          fieldsValid = false;
          if (jQuery('.error-' + elementName).length == 0) {
            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
          } else {
            jQuery('.error-' + elementName).show();
          }
        }
      }

      // Number
      if (rule == 'number' && ruleOption == true) {
        if ((/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/).test(element.val())) {
          // Do nothing
        } else {
          elementValid = false;
        }

        if (!elementValid) {
          fieldsValid = false;
          if (jQuery('.error-' + elementName).length == 0) {
            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
          } else {
            jQuery('.error-' + elementName).show();
          }
        }
      }

      // Digits
      if (rule == 'digits' && ruleOption == true) {
        if ((/^\d+$/).test(element.val())) {
          // Do nothing
        } else {
          elementValid = false;
        }

        if (!elementValid) {
          fieldsValid = false;
          if (jQuery('.error-' + elementName).length == 0) {
            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
          } else {
            jQuery('.error-' + elementName).show();
          }
        }
      }

      // Multiple Emails
      if (rule == 'multipleEmails' && ruleOption == true) {
        var emailsArr = element.val().replace(/\s/g, '').split(/,|;/);

        for (var i = 0; i < emailsArr.length; i++) {
          if ((/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/).test(emailsArr[i])) {
            // Do nothing
          } else {
            elementValid = false;
          }
        }

        if (!elementValid) {
          fieldsValid = false;
          if (jQuery('.error-' + elementName).length == 0) {
            errorDiv.append('<div class="error-' + elementName + '">' + elementName + '</div>');
          } else {
            jQuery('.error-' + elementName).show();
          }
        }
      }
    });

    if (bindEvents) {
      var currentOption = {};
      currentOption[elementIdorName] = rules;

      // Bind events to validate on the fly
      switch (elementType) {
        case 'text':
        case 'email':
        case 'number':
        case 'textarea':
          element.unbind('keyup.customValidation-' + elementName).bind('keyup.customValidation-' + elementName, function(e) {
            return customValidation(currentOption, false);
          });
          break;
        case 'radio':
        case 'checkbox':
          jQuery('input[name=' + elementIdorName + ']').each(function() {
            jQuery(this).unbind('click.customValidation-' + elementName).bind('change.customValidation-' + elementName, function(e) {
              console.log(e);
              return customValidation(currentOption);
            });
          });
          break;
        case 'select':
        case 'select-one':
        case 'select-multiple':
          element.unbind('change.customValidation-' + elementName).bind('change.customValidation-' + elementName, function(e) {
            return customValidation(currentOption, false);
          });
          break;
      }
    }
  });

  return fieldsValid;
}

正如@Sandeeproop 正确指出的那样,即时事件是 return false,不允许取消选中复选框。我需要做的只是 return 单击事件中的任何内容。在下面更新了我的代码,还更新了 JSFiddle 示例。

<html>
    <head>
        <title></title>
    </head>
    <style>
        #errorContainer { color: #ff0000; }
    </style>
    <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
    <script>
        jQuery(document).ready(function() {
            jQuery('#submit').click(function(){
                var options = {
                    'name' : {
                        required: true
                    },
                    'email' : {
                        required: true,
                        email: true
                    },
                    'number' : {
                        required: true,
                        digits: true
                    },
                    'select' : {
                        required: true
                    },
                    'select-multiple' : {
                        required: true
                    },
                    'radio' : {
                        required: true
                    },
                    'checkbox' : {
                        required: true
                    },
                    'checkbox-single' : {
                        required: true
                    },
                    'multiple-emails' : {
                        required: true,
                        multipleEmails: true
                    }
                };

                if(customValidation(options)){
                    alert('Form validated!');
                }else{
                    alert('Form not validated!');
                }
            });
        });

        function customValidation(options){
            var fieldsValid = true;
            var errorMessages = jQuery('#errorMessages');

            jQuery.each(options, function(elementIdorName, rules){
                var element = (jQuery('#' + elementIdorName).length) ? jQuery('#' + elementIdorName) : jQuery('input[name=' + elementIdorName + ']:first');
                var elementType = element.prop('type');
                var elementName = element.prop('name');

                var elementValid = true;

                // First remove any validation errors
                jQuery('.error-' + elementName).hide();

                jQuery.each(rules, function(rule, ruleOption){
                    // Required
                    if(rule == 'required' && ruleOption == true){
                        // Select
                        if(elementType && (elementType.toLowerCase() === 'select' || elementType.toLowerCase() === 'select-one' || elementType.toLowerCase() === 'select-mulitple')){
                            var val = element.val();
                            if(val && val.length > 0){
                                // Do nothing
                            }else{
                                elementValid = false;
                            }
                        }

                        // Checkbox and Radio
                        if((/radio|checkbox/i).test(elementType)){
                            if(jQuery('input[name=' + elementName + ']:checked').length > 0){
                                // Do nothing
                            }else{
                                elementValid = false;
                            }
                        }

                        // Text, Email, Number and Textarea
                        if(jQuery.trim(element.val()).length > 0){
                            // Do nothing
                        }else{
                            elementValid = false;
                        }

                        if(!elementValid){
                            fieldsValid = false;
                            if(jQuery('.error-' + elementName).length == 0) {
                                errorMessages.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                            }else{
                                jQuery('.error-' + elementName).show();
                            }
                        }
                    }

                    // Email
                    if(rule == 'email' && ruleOption == true){
                        if((/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/).test(element.val())){
                            // Do nothing
                        }else{
                            elementValid = false;
                        }

                        if(!elementValid){
                            fieldsValid = false;
                            if(jQuery('.error-' + elementName).length == 0) {
                                errorMessages.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                            }else{
                                jQuery('.error-' + elementName).show();
                            }
                        }
                    }

                    // Number
                    if(rule == 'number' && ruleOption == true){
                        if((/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/).test(element.val())){
                            // Do nothing
                        }else{
                            elementValid = false;
                        }

                        if(!elementValid){
                            fieldsValid = false;
                            if(jQuery('.error-' + elementName).length == 0) {
                                errorMessages.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                            }else{
                                jQuery('.error-' + elementName).show();
                            }
                        }
                    }

                    // Digits
                    if(rule == 'digits' && ruleOption == true){
                        if((/^\d+$/).test(element.val())){
                            // Do nothing
                        }else{
                            elementValid = false;
                        }

                        if(!elementValid){
                            fieldsValid = false;
                            if(jQuery('.error-' + elementName).length == 0) {
                                errorMessages.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                            }else{
                                jQuery('.error-' + elementName).show();
                            }
                        }
                    }

                    // Multiple Emails
                    if(rule == 'multipleEmails' && ruleOption == true){
                        var emailsArr = element.val().replace(/\s/g, '').split(/,|;/);

                        for(var i = 0; i < emailsArr.length; i++){
                            if((/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/).test(emailsArr[i])){
                                // Do nothing
                            }else{
                                elementValid = false;
                            }
                        }

                        if(!elementValid){
                            fieldsValid = false;
                            if(jQuery('.error-' + elementName).length == 0) {
                                errorMessages.append('<div class="error-' + elementName + '">' + elementName + '</div>');
                            }else{
                                jQuery('.error-' + elementName).show();
                            }
                        }
                    }
                });

                var currentOption = {};
                currentOption[elementIdorName] = rules;

                // Bind events to validate on the fly
                switch(elementType){
                    case 'text':
                    case 'email':
                    case 'number':
                    case 'textarea':
                        element.unbind('keyup.customValidation-' + elementName).bind('keyup.customValidation-' + elementName, function(e){
                            customValidation(currentOption);
                        });
                    break;
                    case 'radio':
                    case 'checkbox':
                        jQuery('input[name=' + elementIdorName + ']').each(function (){
                            jQuery(this).unbind('click.customValidation-' + elementName).bind('click.customValidation-' + elementName, function(e){
                                customValidation(currentOption);
                            });
                        });
                    break;
                    case 'select':
                    case 'select-one':
                    case 'select-multiple':
                        element.unbind('change.customValidation-' + elementName).bind('change.customValidation-' + elementName, function(e){
                            customValidation(currentOption);
                        });
                    break;
                }
            });

            return fieldsValid;
        }
    </script>
    <body>
        <div id="errorContainer">
            <div>The following field have errors:</div>
            <div id="errorMessages"></div>
        </div>
        <br /><br />
        <input type="text" name="name" id="name" />
        <br /><br />
        <input type="email" name="email" id="email" />
        <br /><br />
        <input type="number" name="number" id="number" />
        <br /><br />
        <select name="select" id="select">
            <option></option>
            <option>Option 1</option>
            <option>Option 2</option>
            <option>Option 3</option>
        </select>
        <br /><br />
        <select name="select-multiple" id="select-multiple" multiple>
            <option></option>
            <option>Option 1</option>
            <option>Option 2</option>
            <option>Option 3</option>
            <option>Option 4</option>
            <option>Option 5</option>
            <option>Option 6</option>
        </select>
        <br /><br />
        <input type="radio" name="radio" />Yes
        <input type="radio" name="radio" />No
        <br /><br />
        <input type="checkbox" name="checkbox" />Yes
        <input type="checkbox" name="checkbox" />No
        <br /><br />
        <input type="checkbox" name="checkbox-single" id="checkbox-single" />No
        <br /><br />
        <textarea name="multiple-emails" id="multiple-emails"></textarea>
        <br /><br />
        <button id="submit">Submit</button>
    </body>
</html>

更新了 JSFiddle 上的示例:http://jsfiddle.net/wwwescape/sdhjpave/