9

这是我使用的标记:

<input type="text" form="myform" name="inp1" />
<form id="myform" name="myform">
    ...        
</form>

现在我意识到它不适用于旧 IE,因此我正在寻找 HTML 5 polyfill。

有人知道涵盖此 HTML5 功能的某个 polyfill 吗?

4

6 回答 6

12

我编写了这个 polyfill,通过在提交表单时复制字段来模拟这种功能,在 IE6 中进行了测试,它运行良好。

(function($) {
  /**
   * polyfill for html5 form attr
   */

  // detect if browser supports this
  var sampleElement = $('[form]').get(0);
  var isIE11 = !(window.ActiveXObject) && "ActiveXObject" in window;
  if (sampleElement && window.HTMLFormElement && (sampleElement.form instanceof HTMLFormElement || sampleElement instanceof window.HTMLFormElement) && !isIE11) {
    // browser supports it, no need to fix
    return;
  }

  /**
   * Append a field to a form
   *
   */
  $.fn.appendField = function(data) {
    // for form only
    if (!this.is('form')) return;

    // wrap data
    if (!$.isArray(data) && data.name && data.value) {
      data = [data];
    }

    var $form = this;

    // attach new params
    $.each(data, function(i, item) {
      $('<input/>')
        .attr('type', 'hidden')
        .attr('name', item.name)
        .val(item.value).appendTo($form);
    });

    return $form;
  };

  /**
   * Find all input fields with form attribute point to jQuery object
   * 
   */
  $('form[id]').submit(function(e) {
    // serialize data
    var data = $('[form='+ this.id + ']').serializeArray();
    // append data to form
    $(this).appendField(data);
  }).each(function() {
    var form = this,
      $fields = $('[form=' + this.id + ']');

    $fields.filter('button, input').filter('[type=reset],[type=submit]').click(function() {
      var type = this.type.toLowerCase();
      if (type === 'reset') {
        // reset form
        form.reset();
        // for elements outside form
        $fields.each(function() {
          this.value = this.defaultValue;
          this.checked = this.defaultChecked;
        }).filter('select').each(function() {
          $(this).find('option').each(function() {
            this.selected = this.defaultSelected;
          });
        });
      } else if (type.match(/^submit|image$/i)) {
        $(form).appendField({name: this.name, value: this.value}).submit();
      }
    });
  });


})(jQuery);
于 2014-11-02T04:47:22.107 回答
8

The polyfill above doesn't take into account the Edge browser. I have amended it to use feature detection, which I have tested in IE7+, Edge, Firefox (mobile/desktop), Chrome (mobile/desktop), Safari (mobile/desktop), and Android browser 4.0.

(function($) {
    /**
     * polyfill for html5 form attr
     */

    // detect if browser supports this
    var SAMPLE_FORM_NAME = "html-5-polyfill-test";
    var sampleForm = $("<form id='" + SAMPLE_FORM_NAME + "'/>");
    var sampleFormAndHiddenInput = sampleForm.add($("<input type='hidden' form='" + SAMPLE_FORM_NAME + "'/>"));     
    sampleFormAndHiddenInput.prependTo('body'); 
    var sampleElementFound = sampleForm[0].elements[0];
    sampleFormAndHiddenInput.remove();
    if (sampleElementFound) {
        // browser supports it, no need to fix
        return;
    }

    /**
     * Append a field to a form
     *
     */
    $.fn.appendField = function(data) {
      // for form only
      if (!this.is('form')) return;

      // wrap data
      if (!$.isArray(data) && data.name && data.value) {
        data = [data];
      }

      var $form = this;

      // attach new params
      $.each(data, function(i, item) {
        $('<input/>')
          .attr('type', 'hidden')
          .attr('name', item.name)
          .val(item.value).appendTo($form);
      });

      return $form;
    };

    /**
     * Find all input fields with form attribute point to jQuery object
     * 
     */
    $('form[id]').submit(function(e) {
      // serialize data
      var data = $('[form='+ this.id + ']').serializeArray();
      // append data to form
      $(this).appendField(data);
    }).each(function() {
      var form = this,
        $fields = $('[form=' + this.id + ']');

      $fields.filter('button, input').filter('[type=reset],[type=submit]').click(function() {
        var type = this.type.toLowerCase();
        if (type === 'reset') {
          // reset form
          form.reset();
          // for elements outside form
          $fields.each(function() {
            this.value = this.defaultValue;
            this.checked = this.defaultChecked;
          }).filter('select').each(function() {
            $(this).find('option').each(function() {
              this.selected = this.defaultSelected;
            });
          });
        } else if (type.match(/^submit|image$/i)) {
          $(form).appendField({name: this.name, value: this.value}).submit();
        }
      });
    });


  })(jQuery);
于 2016-10-20T21:03:20.813 回答
2

我改进了 patstuart 的 polyfill,这样:

  • 现在可以多次提交表单,例如使用目标属性时(以前重复了外部字段)

  • 重置按钮现在可以正常工作

这里是:

(function($) {
/**
 * polyfill for html5 form attr
 */

// detect if browser supports this
var SAMPLE_FORM_NAME = "html-5-polyfill-test";
var sampleForm = $("<form id='" + SAMPLE_FORM_NAME + "'/>");
var sampleFormAndHiddenInput = sampleForm.add($("<input type='hidden' form='" + SAMPLE_FORM_NAME + "'/>"));     
sampleFormAndHiddenInput.prependTo('body'); 
var sampleElementFound = sampleForm[0].elements[0];
sampleFormAndHiddenInput.remove();
if (sampleElementFound) {
    // browser supports it, no need to fix
    return;
}

/**
 * Append a field to a form
 *
 */
var CLASS_NAME_POLYFILL_MARKER = "html-5-polyfill-form-attr-marker";
$.fn.appendField = function(data) {
  // for form only
  if (!this.is('form')) return;

  // wrap data
  if (!$.isArray(data) && data.name && data.value) {
    data = [data];
  }

  var $form = this;

  // attach new params
  $.each(data, function(i, item) {
    $('<input/>')
      .attr('type', 'hidden')
      .attr('name', item.name)
      .attr('class', CLASS_NAME_POLYFILL_MARKER)
      .val(item.value).appendTo($form);
  });

  return $form;
};

/**
 * Find all input fields with form attribute point to jQuery object
 * 
 */
$('form[id]').submit(function(e, origSubmit) {
  // clean up form from last submit
  $('.'+CLASS_NAME_POLYFILL_MARKER, this).remove();
  // serialize data
  var data = $('[form='+ this.id + ']').serializeArray();
  // add data from external submit, if needed:
  if (origSubmit && origSubmit.name)
    data.push({name: origSubmit.name, value: origSubmit.value})
  // append data to form
  $(this).appendField(data);
})

//submit and reset behaviour
$('button[type=reset], input[type=reset]').click(function() {
  //extend reset buttons to fields with matching form attribute
  // reset form
  var formId = $(this).attr("form");
  var formJq = $('#'+formId);
  if (formJq.length)
    formJq[0].reset();
  // for elements outside form
  if (!formId)
    formId = $(this).closest("form").attr("id");
  $fields = $('[form=' + formId + ']');
  $fields.each(function() {
    this.value = this.defaultValue;
    this.checked = this.defaultChecked;
  }).filter('select').each(function() {
    $(this).find('option').each(function() {
      this.selected = this.defaultSelected;
    });
  });
});
$('button[type=submit], input[type=submit], input[type=image]').click(function() {
  var formId = $(this).attr("form") || $(this).closest("form").attr("id");
  $('#'+formId).trigger('submit', this);  //send clicked submit as extra parameter
});

})(jQuery);

于 2017-07-24T14:54:48.370 回答
1

在阅读了 webshim 的文档之后,它似乎有一个 polyfill。

http://afarkas.github.io/webshim/demos/demos/webforms.html

于 2013-07-19T09:25:59.287 回答
1

我需要一些时间来发送此 polyfill 的更新,因为它不适用于 MS Edge。

我添加 2 行来修复它:

      var isEdge = navigator.userAgent.indexOf("Edge");
      if (sampleElement && window.HTMLFormElement && sampleElement.form instanceof HTMLFormElement && !isIE11 && isEdge == -1) {
        // browser supports it, no need to fix
        return;
      }

更新:Edge 现在支持它: https ://caniuse.com/#feat=form-attribute

于 2016-02-03T09:35:30.837 回答
1

我基于上述 polyfill 制作了一个原生 JavaScript polyfill,并将其上传到 GitHub:https ://github.com/Ununnilium/form-attribute-polyfill 。我还添加了一个自定义事件来处理提交由 JavaScript 而不是直接由浏览器处理的情况。我只是在 IE 11 上测试了代码,所以请在使用前自行检查。轮询应该由更有效的检测功能代替。

function browserNeedsPolyfill() {
    var TEST_FORM_NAME = "form-attribute-polyfill-test";
    var testForm = document.createElement("form");
    testForm.setAttribute("id", TEST_FORM_NAME);
    testForm.setAttribute("type", "hidden");
    var testInput = document.createElement("input");
    testInput.setAttribute("type", "hidden");
    testInput.setAttribute("form", TEST_FORM_NAME);
    testForm.appendChild(testInput);
    document.body.appendChild(testInput);
    document.body.appendChild(testForm);
    var sampleElementFound = testForm.elements.length === 1;
    document.body.removeChild(testInput);
    document.body.removeChild(testForm);
    return !sampleElementFound;
}

// Ideas from jQuery form attribute polyfill https://stackoverflow.com/a/26696165/2372674
function executeFormPolyfill() {
    function appendDataToForm(data, form) {
        Object.keys(data).forEach(function(name) {
            var inputElem = document.createElement("input");
            inputElem.setAttribute("type", "hidden");
            inputElem.setAttribute("name", name);
            inputElem.value = data[name];
            form.appendChild(inputElem);
        });
    }

    var forms = document.body.querySelectorAll("form[id]");
    Array.prototype.forEach.call(forms, function (form) {
        var fields = document.querySelectorAll('[form="' + form.id + '"]');
        var dataFields = [];
        Array.prototype.forEach.call(fields, function (field) {
            if (field.disabled === false && field.hasAttribute("name")) {
                dataFields.push(field);
            }
        });
        Array.prototype.forEach.call(fields, function (field) {
            if (field.type === "reset") {
                field.addEventListener("click", function () {
                    form.reset();
                    Array.prototype.forEach.call(dataFields, function (dataField) {
                        if (dataField.nodeName === "SELECT") {
                            Array.prototype.forEach.call(dataField.querySelectorAll('option'), function (option) {
                                option.selected = option.defaultSelected;
                            });
                        } else {
                            dataField.value = dataField.defaultValue;
                            dataField.checked = dataField.defaultChecked;
                        }
                    });
                });
            } else if (field.type === "submit" || field.type === "image") {
                field.addEventListener("click", function () {
                    var obj = {};
                    obj[field.name] = field.value;
                    appendDataToForm(obj, form);
                    form.dispatchEvent(eventToDispatch);
                });
            }
        });
        form.addEventListener("submit", function () {
            var data = {};
            Array.prototype.forEach.call(dataFields, function (dataField) {
                data[dataField.name] = dataField.value;
            });
            appendDataToForm(data, form);
        });
    });
}

// Poll for new forms and execute polyfill for them
function detectedNewForms() {
    var ALREADY_DETECTED_CLASS = 'form-already-detected';
    var newForms = document.querySelectorAll('form:not([class="' + ALREADY_DETECTED_CLASS + '"])');
    if (newForms.length !== 0) {
        Array.prototype.forEach.call(newForms, function (form) {
            form.className += ALREADY_DETECTED_CLASS;
        });
        executeFormPolyfill();
    }
    setTimeout(detectedNewForms, 100);
}


// Source: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
function polyfillCustomEvent() {
    if (typeof window.CustomEvent === "function") {
        return false;
    }

    function CustomEvent(event, params) {
        params = params || {bubbles: false, cancelable: false, detail: undefined};
        var evt = document.createEvent('CustomEvent');
        evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
        return evt;
    }

    CustomEvent.prototype = window.Event.prototype;
    window.CustomEvent = CustomEvent;
}

if (browserNeedsPolyfill()) {
    polyfillCustomEvent();   // IE is missing CustomEvent

    // This workaround is needed if submit is handled by JavaScript instead the browser itself
    // Source: https://stackoverflow.com/a/35155789/2372674
    var eventToDispatch = new CustomEvent("submit", {"bubbles": true, "cancelable": true});
    detectedNewForms();   // Poll for new forms and execute form attribute polyfill for new forms
}
于 2018-03-01T06:31:00.357 回答