[JS] 50. 대화상자 띄우기
대화상자 띄우기 (1)
html
<section id="s14">
<h1>14. 대화상자 띄우기</h1>
<div>
<a class="btn-del" href="">삭제하기</a>
</div>
<div class="screen">
<div class="dlg">
<div class="view">
정말 삭제하시겠습니까?
</div>
<div class="action-panel">
<a href="" class="btn btn-strong">OK</a>
<a href="" class="btn ml-2">CANCEL</a>
</div>
</div>
</div>
</section>
css
#s14 .screen{
position: absolute;
left:0;
top:0;
background-color: rgba(0, 0, 0, 0.486);
width: 100vw;
height: 100vh;
//opacity: 0.5;
//opacity로 하면 컨텐츠로 반투명이 되서 다른 방법으로 해결하자.
display: flex;
justify-content: center;
align-items: center;
}
#s14 .dlg{
background-color: #fff;
padding: 20px;
position: relative;
top: -100px;
border-radius: 10px;
}
#s14 .action-panel{
padding-top:20px;
}
우선 창이 뜨도록 해보자.
먼저 html에서 상자 안의 내용을 주석처리하자.
<section id="s14">
<h1>14. 대화상자 띄우기</h1>
<div>
<a class="btn-del" href="">삭제하기</a>
</div>
<!-- <div class="screen">
<div class="dlg">
<div class="view">
정말 삭제하시겠습니까?
</div>
<div class="action-panel">
<a href="" class="btn btn-strong">OK</a>
<a href="" class="btn ml-2">CANCEL</a>
</div>
</div>
</div> -->
</section>
주석처리한 내용을 아래로 옮겨보자.
window.addEventListener("load", function(){
var section = document.querySelector("#s14");
var delButton = section.querySelector(".btn-del");
delButton.onclick = function(e){
e.preventDefault();
var html = '<div class="screen"> \
<div class="dlg"> \
<div class="view"> \
정말 삭제하시겠습니까? \
</div> \
<div class="action-panel"> \
<a href="" class="btn btn-strong">OK</a> \
<a href="" class="btn ml-2">CANCEL</a> \
</div> \
</div> \
</div>';
section.insertAdjacentHTML("beforeend", html);
// css 적용때문에 document.body. 대신 section을 써보자.
}
};
안의 내용에서 줄바꿈을 하려면 \
을 쓰면 된다.
(단, 그 뒤로는 공백이 없어야한다.)
insertAdjacentHTML로 내용을 삽입해주자.
insertAdjacentHTML 참고
https://developer.mozilla.org/ko/docs/Web/API/Element/insertAdjacentHTML
var cancelButton = section.queryselector(".btn-cancel");
cancelButton.onclick = function(e){
e.preventDefault();
section.querySelector(".screen").remove();
};
cancelButton을 눌렀을때를 설정해주자.
그런데 위의 코드들을 앞으로도 많이 쓸 것이기 때문에 다른 곳에서도 이용할 수 있는 방법을 알아보자.
먼저,
var html = '<div class="screen"> \
.
.
.
var cancelButton = section.queryselector(".btn-cancel");
cancelButton.onclick = function(e){
e.preventDefault();
section.querySelector(".screen").remove();
};
이 부분을 잘라내 dialog.js를 따로 만들어 옮겨주자.
남은 dom.js에는 아래와 같이 만들어주자.
delButton.onclick = function(e){
e.preventDefault();
var dlg = new Dialog();
if(dlg.confirm("정말 삭제하시겠습니까?") == true)
console.log("삭제되었습니다.");
new는 개체를 넘겨받는게 있다는 것이다. (초기화하라)
호출하는 방법에 따라 this가 달라진다.
이제 dialog.js를 만들어보자.
일반함수가 아닌 객체를 초기화하는 것이라는것을 알려주기 위해 이름 첫글자를 대문자로 쓴다.
function Dialog(){
this.show = function(){
console.log("show");
}
this.confirm = function(){
console.log("confirm);
return false;
}
}
html에서 <script src = "dialog.js"></script>
를 추가해준다.
(단, 사용되는 쪽 위에 배치해 순서에 주의해준다.)
section이 없으므로 section을 #s14를 통해 얻어주는 것도 추가해주자.
function Dialog(){
this.section = document.querySelector("#s14");
this.show = function(){
console.log("show");
}
this.confirm = function(){
var html = '<div class="screen"> \
<div class="dlg"> \
<div class="view"> \
정말 삭제하시겠습니까? \
</div> \
<div class="action-panel"> \
<a href="" class="btn btn-strong">OK</a> \
<a href="" class="btn ml-2">CANCEL</a> \
</div> \
</div> \
</div>';
this.section.insertAdjacentHTML("beforeend", html);
var cancelButton = this.section.queryselector(".btn-cancel");
var section = this.section;
cancelButton.onclick = function(e){
e.preventDefault();
this.section.querySelector(".screen").remove();
};
//위임함수다. dlg를 통해서 호출되는 함수가 아니다. (dlg객체를 넘겨받을 수 없다.)
//여기서 this.section을 하면 this는 window가 된다.
}
}
this는 생략이 불가능하다.
this는 멤버함수(this의 멤버로 대입되는 함수)에서 쓸 수 있다.
그런데 cancelButton은 this의 멤버가 아니다. (저 함수는 지역의 속성에 대입되는 함수다.)
그렇지만 outer 지역변수를 쓸 수는 있다.
대화상자 띄우기 (2) - 1
대화상자에 제목을 추가하고 title이라는 class로 지정하자
var html = '<div class="screen"> \
<div class="dlg"> \
<div class="title"> \
제목 \
</div> \
<div class="view"> \
정말 삭제하시겠습니까? \
</div> \
<div class="action-panel"> \
<a href="" class="btn btn-strong">OK</a> \
<a href="" class="btn ml-2">CANCEL</a> \
</div> \
</div> \
</div>';
css는 적절히 설정해주자.
.
.
.
css 생략
.
.
.
function Dialog(){
this.section = document.querySelector("#s14");
this.show = function(){
console.log("show");
}
this.confirm = function(){
var html = '<div class="screen"> \
<div class="dlg"> \
<div class="title"> \
제목 \
</div> \
<div class="view"> \
정말 삭제하시겠습니까? \
</div> \
<div class="action-panel"> \
<a href="" class="btn btn-strong">OK</a> \
<a href="" class="btn ml-2">CANCEL</a> \
</div> \
</div> \
</div>';
this.section.insertAdjacentHTML("beforeend", html);
var cancelButton = this.section.queryselector(".btn-cancel");
var section = this.section;
cancelButton.onclick = function(e){
e.preventDefault();
this.section.querySelector(".screen").remove();
};
//위임함수다. dlg를 통해서 호출되는 함수가 아니다. (dlg객체를 넘겨받을 수 없다.)
//여기서 this.section을 하면 this는 window가 된다.
return false;
}
}
Function bind() / call() / apply()
const animals = [
{species : 'Lion', name : 'King'},
{species : 'Whale', name : 'Fail'}
];
var print = function(i) {
console.log('#' + i + ' ' + this.speices + ':' + this.name);
};
// 캡슐화 되지 않은 함수에서의 this에 객체를 할당할 수 있을까?
print(0); → #0 undefined:
print(1); → #1 undefined:
print.call(animals[0], 0); → #0 Lion:King
this에 객체를 할당하지 않으면 this는 window가 되므로 undefined가 나온다.
var print = function(i, j, k) {
console.log('#' + i + ' ' + this.speices + ':' + this.name);
};
print.call(animals[0], 0, 1, 1);
print.apply(animals[0], [0, 1, 1]);
하나씩 대입하려면 call, 배열 형태로 대입하려면 apply를 쓰자.
const animals = [
{species : 'Lion', name : 'King'},
{species : 'Whale', name : 'Fail'}
];
var print = function(i) {
console.log('#' + i + ' ' + this.speices + ':' + this.name);
};
var onclick = print;
onclick(1);
// 여기서 this는 window
// #1 undefined:
var onclick = print.bind(animals[1]);
onclick(1);
// 여기서 this는 animals[1]
// #1 Lion:King
bind를 이용해 위임할 객체를 미리 정해 onclick에 대입했다.
대화상자 띄우기 (2) - 2
this.section.insertAdjacentHTML("beforeend", html);
var cancelButton = this.section.queryselector(".btn-cancel");
cancelButton.onclick = function(e){
e.preventDefault();
this.section.querySelector(".screen").remove();
}.bind(this);
return false;
}
}
꼼수를 쓰지 않고 this를 쓰기 위해 함수 뒤에 bind(this)를 붙인다.
Prototype
생성자는 객체를 만들때마다 생성
total도 2개가?
똑같은 기능을 하는 함수가 개별적으로 만들어진다.
한 번만 만들어서 공유시키자.
프로토타입이란 어떤것의 원형이라고 보면 될 듯 하다.
var exam = {
//kor:0,
//eng:10,
여기서 변수를 지정하면 모든 객체에 적용된다.
total: function(){
console.log("total");
}
};
function NeExam(){
this.kor = 0;
this.eng = 0;
this.com = 0;
}
NeExam.prototype = exam;
var ne1 = new NeExam();
var ne2 = new NeExam();
//prototype 객체가 하나만 만들어진다.
ne1.total();
ne2.total();
console.log(NeExam.prototype);
//NeExam 개체로 prototype 개체를 볼 수 있다.
console.log(ne1__proto__);
//ne1 객체로 prototype 개체를 볼 수 있다.
console.log(ne1__proto__.__proto__);
// prototype의 상위인 Object를 볼 수 있다.
console.log(ne1__proto__.__proto__.__proto__);
// null이 나오게 된다.
console.log(Object.hasOwn(exam, "kor"));
console.log(ne1.hasOwnProperty("kor"));
// true가 나온다.
상속과 비슷한 느낌이다.
var exam을 굳이 쓰지 않고 다음과 같이 할 수 있다.
function NeExam(){
this.kor = 0;
this.eng = 0;
this.com = 0;
}
NeExam.prototype = {
total: function(){
console.log("total");
}
};
Array에도 적용이 되는지 확인해보자.
Array.prototype.aaa = function(){
console.log("Hi~");
}
var arr = [];
console.log(arr.aaa());
Array의 프로토타입에 적용을 시켰기 때문에 Hi~가 호출된다.
만약, 일회성으로 객체를 만들고 싶으면 create를 쓰면 된다.
var exam = Object.create(NeExam);
exam.kor = 0;
exam.eng = 0;
exam.math - 0;
exam.total();
대화상자 띄우기 (2) - 3
Dialog의 내용을 prototype으로 만들기 위해 이동시키자.
Dialog.prototype = {
this.show = function(){
console.log("show");
}
this.confirm = function(){
var html = '<div class="screen"> \
<div class="dlg"> \
<div class="title"> \
제목 \
</div> \
<div class="view"> \
정말 삭제하시겠습니까? \
</div> \
<div class="action-panel"> \
<a href="" class="btn btn-strong">OK</a> \
<a href="" class="btn ml-2">CANCEL</a> \
</div> \
</div> \
</div>';
this.section.insertAdjacentHTML("beforeend", html);
var cancelButton = this.section.queryselector(".btn-cancel");
cancelButton.onclick = function(e){
e.preventDefault();
this.section.querySelector(".screen").remove();
}.bind(this);
return false;
}
}
Dialog.prototype = {
this.show = function(){
console.log("show");
}
this.confirm = function(message, title){
var html = '<div class="screen"> \
<div class="dlg"> \
<div class="title"> \
'+title+' \
</div> \
<div class="view"> \
'+message+' \
</div> \
<div class="action-panel"> \
<a href="" class="btn btn-strong">OK</a> \
<a href="" class="btn ml-2">CANCEL</a> \
</div> \
</div> \
</div>';
this.section.insertAdjacentHTML("beforeend", html);
var cancelButton = this.section.queryselector(".btn-cancel");
cancelButton.onclick = function(e){
e.preventDefault();
this.section.querySelector(".screen").remove();
}.bind(this);
return false;
}
}
제목과 내용은 사용할때마다 달라지게 하자.
dom.js
delButton.onclick = function(e){
e.preventDefault();
var dlg = new Dialog();
if(dlg.confirm("정말 삭제하시겠습니까? 정말?", "알림") == true)
console.log("삭제되었습니다.");
message와 title이 제대로 적용된 것을 볼 수 있다.
만든 prototype을 다른곳에서도 이용하려면?
그런데 이렇게 만들어놓은 prototype을 다른 곳에서 적용하려면 몇가지 문제가 있다.
우선 section에 class명을 s14로 정해놓았는데 다른곳에서는 이런 이름을 사용하지 않을수도 있다.
this.section = document.querySelector("#s14");
이것과 더불어 this.section
을 사용한 것들을 전부 삭제하거나 주석처리해주자.
this.section.insertAdjacentHTML("beforeend", html);
↓
document.body.insertAdjacentHTML("beforeend", html);
자리할 위치를 나타내는 코드는 이렇게 바꿔주자.
그런데 this.section을 전부 지울 경우 css가 깨지게 된다.
그래서
#s14 .aaaa
스타일의 이름에서 #s14를 전부 빼주고 새로운 고유한 이름을 만들어주자.
.com-nelec_screen
이러면 모든 문제가 해결된 것일까?
다른사람에게 이런 prototype을 사용하게 하려면 css를 같이 넘겨줘야 하는 번거로움이 있다.
Object
mdn 참조하기
스타일 속성 대입하기
방법 1,2,3은 pseudo class 적용이 어렵다.
var style = document.createElement("style");
style.textContent = `.newlecture_screen{
background-color: #0008;
/* opacity:.6; */
position: fixed;
left: 0;
top:0;
width:100vw;
height: 100vh;
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
}
.
.
.
.btn-strong:hover{
background-color: #669415;
border-color: #67921e;
}`;
//css부분을 추가해준다.
document.head.append(style);
// dom.html의 head 부분에 추가할 수 있도록 하자.
`
이 부호를 처음과 끝에 써주면 줄마다 /
을 쓰지 않아도 내려쓰기가 가능해진다.
delButton.onclick = function(e){
e.preventDefault();
var dlg = new Dialog();
if(dlg.confirm("정말 삭제하시겠습니까? 정말?", "알림"))
console.log("삭제되었습니다.");
이 부분에서 delButton이 눌리면 consolo.log의 내용일 실행되어야 하는데 비동기로 실행되기때문에 버튼을 누르지 않아도 console.log의 내용이 뜰 수 있다. 그래서 dialog.js에서 return true/false 하는 것이 의미가 없다.
var dlg = new Dialog();
dlg.oncancel = function(){
console.log("취소되었습니다.");
};
dlg.onok = function(){
console.log("삭제되었습니다.");
}
dlg.confirm("정말 삭제하시겠습니까? 정말?", "알림")
console.log("삭제되었습니다.");
dialog.js에서 cancel,ok를 초기화하자.
this.oncancel = null;
this.onok = null;
//세팅하지 않았으면 null
cancelButton을 다시 설정해주자.
var cancelButton = this.section.querySelector(".newlecture_btn-cancel");
cancelButton.onclick = function(e){
e.preventDefault();
this.section.remove();
this.oncancel();
//oncancel을 불러오자.
}.bind(this);
Author And Source
이 문제에 관하여([JS] 50. 대화상자 띄우기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@psh94/JS-50저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)