Skip to content

Instantly share code, notes, and snippets.

@w-log
Last active March 28, 2018 12:22
Show Gist options
  • Save w-log/91c7c36759a91013198851b1a6eb4b57 to your computer and use it in GitHub Desktop.
Save w-log/91c7c36759a91013198851b1a6eb4b57 to your computer and use it in GitHub Desktop.
모달창 예제
.modal {
background: #000;
width: 500px;
height: 100px;
transform: scale(0.7) ;
left: 0;
top: 0;
opacity: 0;
visibility: hidden;
position: fixed;
z-index: 200;
}
.modal-background {
position:fixed;
width: 100%;
height: 100%;
background: rgba(0,0,0, 0.75);
opacity: 0;
left:0;
top:0;
z-index: 199;
}
.modal-background.active {
opacity: 1;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="test-modal" class="modal"></div>
<button data-modal-trigger="test-modal" data-type="open">
모달열기
</button>
<button data-modal-trigger="test-modal" data-type="close">
모달닫기
</button>
<script src="./js/tweenLite.js"></script>
<script src="./js/es6-promise.js">
</body>
</html>
//required (Babel or es6) and TweenLite
(function(w, d) {
if(!(w && d)) {
return false;
}
const aClass = function(Ele, ClassName) {
if (Ele.classList && typeof ClassName === "string") {
Ele.classList.add(ClassName);
} else if (typeof Ele.className !== "undefined" && typeof ClassName === "string") {
Ele.className += " " + ClassName;
} else {
throw new Error("addClass의 인자는 (Element객체,'넣을클래스명') 으로 정의해야합니다.");
}
};
const rClass = function(Ele, ClassName) {
if (Ele.classList && typeof ClassName === "string") {
Ele.classList.remove(ClassName);
} else if (typeof Ele.className !== "undefined" && typeof ClassName === "string") {
Ele.className = Ele.className.replace(new RegExp("(^|\\b)(" + ClassName.split(' ').join("|") + ")(\\b|$)", "gi"), " ");
} else {
throw new Error("removeClass의 인자는 (Element객체,'넣을클래스명 [구분자 공백]') 으로 정의해야합니다.");
}
};
const hClass = function(Ele, ClassName) {
if (Ele.classList && typeof ClassName === "string") {
return Ele.classList.contains(ClassName);
} else if (typeof Ele.className !== "undefined" && typeof ClassName === "string") {
return new RegExp("(^|)" + ClassName + "(|$)", "gi").test(Ele.className);
} else {
throw new Error("hasClass의 인자는 (Element객체,'넣을클래스명') 으로 정의해야합니다.");
}
};
const raf = requestAnimationFrame;
const t = TweenLite;
const _staticModals = {};
const optionModel = {
duration: 0.5,
ease: Power3.easeOut
};
class Modal {
static getDirAttributeName() {
return 'data-modal-trigger';
}
static triggerModal(e) {
const targetEl = Modal.getModalTrigger(e.target || e.srcElement);
if(targetEl) {
const modalTarget = targetEl.getAttribute(Modal.getDirAttributeName());
const buttonType = targetEl.getAttribute('data-type');
const modalInstance = _staticModals[modalTarget];
if(!modalInstance) {
return false;
}
const promises = modalInstance.getTypeCallStack(buttonType).map(callback => typeof callback === 'function' && new Promise((res, rej) => callback.apply(this, [e, res, rej])) ).filter(_ => _);
Promise.all(promises)
.then(_ => Modal.lazyFrame(3))
.then(_ => {
const targetPostion = targetEl.getBoundingClientRect();
const position = modalInstance.getPosition(targetPostion);
typeof modalInstance[buttonType] === 'function' && modalInstance[buttonType](position);
})
.catch(err => {
modalInstance._el.innerHTML = `<h1 class="err-message">요청 처리도중 오류가 발생했습니다. 잠시후에 다시시도해주세요. (${err.message})</h1>`;
Modal.lazyFrame(3).then(_ => {
const targetPostion = targetEl.getBoundingClientRect();
const position = modalInstance.getPosition(targetPostion);
typeof modalInstance[buttonType] === 'function' && modalInstance[buttonType](position);
});
});
}
}
static getModalTrigger(el) {
while(el) {
if(el.hasAttribute(Modal.getDirAttributeName())) {
break;
}
el = el.parentElement;
}
return el;
}
static getNumberToArray(number) {
const arr = [];
for(let i = 0; i < number; i++) {
arr.push(i);
}
return arr;
}
static lazyFrame(frame = 0) {
let p = Promise.resolve();
const frameArr = this.getNumberToArray(frame);
frameArr.map(number => _ => new Promise( (res, rej) => raf(_ => res(number)) ))
.forEach(promiseFn => p = p.then(promiseFn));
return p;
}
constructor(elem, options) {
this._el = elem && typeof elem === 'string' ? document.querySelector(elem) : elem;
if(!this._el) {
throw new Error('invalid Selector OR HTMLElement !');
}
this.id = this._el.getAttribute('id');
if(!this.id) {
throw new Error('id Attribute Required!');
}
this.option = Object.assign({}, optionModel, options);
this._dim = document.createElement('div');
this._dim.setAttribute('data-modal-trigger', this.id);
this._dim.setAttribute('data-type', 'close');
if(this._dim.style.hasOwnProperty('-ms-transform')) {
this._dim.style['-ms-transform'] = `opacity ${this.option.duration * 1000}ms ease-out`;
}
this._dim.style.transition = `opacity ${this.option.duration * 1000}ms ease-out`;
this.openCallStack = [];
this.closeCallStack = [];
aClass(this._dim, 'modal-background');
_staticModals[this.id] = this;
}
open(position) {
raf(_ => {
document.body.style.overflow = 'hidden';
document.body.appendChild(this._dim);
t.to(this._el, 0, { x: position.x, y: position.y, onComplete: _ => {
this._el.setAttribute('data-x', position.x);
this._el.setAttribute('data-y', position.y);
const center = { x: (w.innerWidth / 2) - (this._el.offsetWidth / 2), y: (w.innerHeight / 2) - (this._el.offsetHeight / 2)};
t.to(this._el, this.option.duration, { visibility: 'visible', opacity: 1, scale: 1, x: center.x, y: center.y, ease: this.option.ease, zIndex: 400, onComplete: _ => aClass(this._el, 'open') });
Modal.lazyFrame(1).then(_ => aClass(this._dim, 'active'));
} });
});
}
close() {
t.to(this._el, this.option.duration, { opacity: 0, scale: 0.7, x: this._el.getAttribute('data-x'),y: this._el.getAttribute('data-y'), zIndex: -1, ease: this.option.ease, onComplete: _ => {
document.body.style.overflow = '';
this._el.visibility = 'hidden';
this._el.removeAttribute('data-x');
this._el.removeAttribute('data-y');
hClass(this._el, 'open') && rClass(this._el, 'open');
} });
hClass(this._dim, 'active') && rClass(this._dim, 'active');
setTimeout(_ => {
try {
this._dim.parentElement && this._dim.parentElement.removeChild(this._dim);
}catch(e) {
return false;
}
}, this.option.duration * 1000);
}
getId() {
return this.getId;
}
getPosition(targetPosition) {
const styleObj = w.getComputedStyle(this._el);
const width = this.getWidthToPixel(styleObj.width);
const scale = this.getScale(styleObj['-ms-transform'] ? styleObj['-ms-transform'] : styleObj.transform);
return { x: (targetPosition.left + targetPosition.width / 2) - (width / 2), y: targetPosition.top - (scale ? this._el.offsetHeight / 2 * (1 - scale.y) : 0) };
}
getWidthToPixel(styleString) {
const widthValue = parseInt(/(\-?)(\.?\d+)/g.exec(styleString)[0]);
const unit = styleString.replace(/(\-?)(\.?\d+)/g, '').replace(/\s+/g, '');
switch (unit) {
case '%':
return (w.innerWidth || 0) * (widthValue / 100);
break;
case 'px':
return widthValue;
break;
}
}
getScale(transform = '') {
let type = '';
switch(true) {
case transform.indexOf('matrix') >= 0:
type = 'matrix';
const matrixRegexp = /(?!([matrix\(]|[matrix3d\(])).*(?=\))/g;
const values = matrixRegexp.exec(transform)[0].replace(/\s/g, '').split(',');
return values.length === 6 ? { x: parseFloat(values[0]), y: parseFloat(values[3]) } : { x: parseFloat(values[0]), y: parseFloat(values[4]) };
break;
case transform.indexOf('scale') >= 0:
const scaleRegexp = /(?![scale\(]).*(?=\))/g;
const scaleValues = scaleRegexp.exec(transform)[0].replace(/\s/g, '').split(',');
return { x: parseFloat(scaleValues[0]), y: parseFloat(scaleValues[1]) };
}
}
addEventListener(type = 'open', callback) {
this.getTypeCallStack(type).push(callback);
}
getTypeCallStack(type) {
return type === 'open' ? this.openCallStack : this.closeCallStack;
}
removeEventListener(type = 'open', refFn) {
const callStack = this.getTypeCallStack(type).filter(functions => functions !== refFn);
type === 'open' ? this.openCallStack = callStack : this.closeCallStack = callStack;
}
}
w.addEventListener('click', Modal.triggerModal);
w.examples = w.examples || {};
w.examples.Modal = Modal;
})(window, document);
@w-log
Copy link
Author

w-log commented Mar 28, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment