polyfill이란?
#
Polyfill
ployfill(폴리필)이란?
- 특정 기능(javascript, HTML5, CSS3 등…)이 지원되지 않는 브라우저를 위해 사용할 수 있는 코드 조각이나 플러그인
- 오래된 브라우저에서 빌드없이 ES6같은 최근 문법을 사용할 때 쓰인다. 즉, 오래된 브라우저와 호환성때문에 쓰인다.
사용법
- CDN
- 인터넷에 치면 나오는 코드 블럭들
을 추가해주면 된다.
예시
- HTML5에 있는 placeholder를 추가해주기위한 코드 블럭(엄청 길다…)
//
// HTML5 Placeholder Attribute Polyfill (Simple)
//
// Author: James Brumond <james@jbrumond.me> (http://www.jbrumond.me)
//
(function(window, document, undefined) {
// Don't run the polyfill if it isn't needed
if ('placeholder' in document.createElement('input')) {
document.placeholderPolyfill = function() { /* no-op */ };
document.placeholderPolyfill.active = false;
return;
}
// Fetch NodeLists of the needed element types
var inputs = document.getElementsByTagName('input');
var textareas = document.getElementsByTagName('textarea');
//
// Define the exposed polyfill methods for manual calls
//
document.placeholderPolyfill = function(elems) {
elems = elems ? validElements(elems) : validElements(inputs, textareas);
each(elems, polyfillElement);
};
// Expose whether or not the polyfill is in use (false means native support)
document.placeholderPolyfill.active = true;
// Run automatically
document.placeholderPolyfill();
// -------------------------------------------------------------
// Use mutation events for auto-updating
if (document.addEventListener) {
document.addEventListener('DOMAttrModified', document.placeholderPolyfill);
document.addEventListener('DOMNodeInserted', document.placeholderPolyfill);
}
// Use onpropertychange for auto-updating
else if (document.attachEvent && 'onpropertychange' in document) {
document.attachEvent('onpropertychange', document.placeholderPolyfill);
}
// No event-based auto-update
else {
// pass
}
// -------------------------------------------------------------
// Add some basic default styling for placeholders
firstStylesheet().addRule('.-placeholder', 'color: #888;', 0);
// -------------------------------------------------------------
//
// Polyfill a single, specific element
//
function polyfillElement(elem) {
// If the element is already polyfilled, skip it
if (elem.__placeholder != null) {
// Make sure that if the placeholder is already shown, that it is at least up-to-date
if (elem.__placeholder) {
elem.value = getPlaceholder();
}
return;
}
// Keep track of placeholder changes so we can fire off updates correctly
var currentPlaceholder = getPlaceholderFor(elem);
function getPlaceholder() {
return currentPlaceholder = getPlaceholderFor(elem);
}
// Is there already a value in the field? If so, don't replace it with the placeholder
if (elem.value) {
elem.__placeholder = false;
if (elem.value === getPlaceholder()) {
doShowPlaceholder();
}
} else {
showPlaceholder();
}
// Define the events that cause these functions to be fired
addEvent(elem, 'keyup', checkPlaceholder);
addEvent(elem, 'keyDown', checkPlaceholder);
addEvent(elem, 'blur', checkPlaceholder);
addEvent(elem, 'focus', hidePlaceholder);
addEvent(elem, 'click', hidePlaceholder);
// Use mutation events for auto-updating
if (elem.addEventListener) {
addEvent(elem, 'DOMAttrModified', updatePlaceholder);
}
// Use onpropertychange for auto-updating
else if (elem.attachEvent && 'onpropertychange' in elem) {
addEvent(elem, 'propertychange', updatePlaceholder);
}
// No event-based auto-update
else {
// pass
}
function updatePlaceholder() {
// Run this asynchronously to make sure all needed updates happen before we run checks
setTimeout(function() {
var old = currentPlaceholder;
var current = getPlaceholder();
// If the placeholder attribute has changed
if (old !== current) {
// If the placeholder is currently shown
if (elem.__placeholder) {
elem.value = current;
}
}
// Make sure that elem.__placeholder stays acurate, even if the placeholder or value are
// manually changed via JavaScript
if (elem.__placeholder && elem.value !== current) {
elem.__placeholder = false;
}
}, 0);
}
function checkPlaceholder() {
if (elem.value) {
hidePlaceholder();
} else {
showPlaceholder();
}
}
function showPlaceholder() {
if (! elem.__placeholder && ! elem.value) {
doShowPlaceholder();
}
}
function doShowPlaceholder() {
elem.__placeholder = true;
elem.value = getPlaceholder();
addClass(elem, '-placeholder');
}
function hidePlaceholder() {
if (elem.__placeholder) {
elem.__placeholder = false;
elem.value = '';
removeClass(elem, '-placeholder');
}
}
}
// -------------------------------------------------------------
//
// Build a list of valid (can have a placeholder) elements from the given parameters
//
function validElements() {
var result = [ ];
each(arguments, function(arg) {
if (typeof arg.length !== 'number') {
arg = [ arg ];
}
result.push.apply(result, filter(arg, isValidElement));
});
return result;
}
//
// Check if a given element supports the placeholder attribute
//
function isValidElement(elem) {
var tag = (elem.nodeName || '').toLowerCase();
return (tag === 'textarea' || (tag === 'input' && (elem.type === 'text' || elem.type === 'password')));
}
// -------------------------------------------------------------
function addEvent(obj, event, func) {
if (obj.addEventListener) {
obj.addEventListener(event, func, false);
} else if (obj.attachEvent) {
obj.attachEvent('on' + event, func);
}
}
function removeEvent(obj, event, func) {
if (obj.removeEventListener) {
obj.removeEventListener(event, func, false);
} else if (obj.detachEvent) {
obj.detachEvent('on' + event, func);
}
}
// -------------------------------------------------------------
function each(arr, func) {
if (arr.forEach) {
return arr.forEach(func);
}
for (var i = 0, c = arr.length; i < c; i++) {
func.call(null, arr[i], i, arr);
}
}
function filter(arr, func) {
if (arr.filter) {
return arr.filter(func);
}
var result = [ ];
for (var i = 0, c = arr.length; i < c; i++) {
if (func.call(null, arr[i], i, arr)) {
result.push(arr[i]);
}
}
return result;
}
// -------------------------------------------------------------
var regexCache = { };
function classNameRegex(cn) {
if (! regexCache[cn]) {
regexCache[cn] = new RegExp('(^|\\s)+' + cn + '(\\s|$)+', 'g');
}
return regexCache[cn];
}
function addClass(elem, cn) {
elem.className += ' ' + cn;
}
function removeClass(elem, cn) {
elem.className = elem.className.replace(classNameRegex(cn), ' ');
}
// -------------------------------------------------------------
// Internet Explorer 10 in IE7 mode was giving me the wierest error
// where e.getAttribute('placeholder') !== e.attributes.placeholder.nodeValue
function getPlaceholderFor(elem) {
return elem.getAttribute('placeholder') || (elem.attributes.placeholder && elem.attributes.placeholder.nodeValue);
}
// -------------------------------------------------------------
// Get the first stylesheet in the document, or, if there are none, create/inject
// one and return it.
function firstStylesheet() {
var sheet = document.styleSheets && document.styleSheets[0];
if (! sheet) {
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.appendChild(document.createTextNode(''));
document.head.appendChild(style);
sheet = style.sheet;
}
return sheet;
}
}(window, document));