☑️ Bom
Browser Object Model (브라우저 객체 모델)
✅ 브라우저의 구성요소를 객체로 처리할 수 있는 기능
=> 브라우저의 구성요소가 이미 객체로 생성되어 있음 (내장객체)
✅ BOM 객체
1) window : 브라우저 창을 의미. 최상위 객체
2) screen : 화면을 의미. 화면의 너비/높이 등 처리
3) history : 방문 경로를 저장. 뒤/앞 이동 가능
4) location : 현재 브라우저의 경로 처리
5) document : 현재 브라우저의 문서를 의미
DOM : 문서상의 모든 요소들
document
- html
- meta
- title
- body
- div
- ul
- li ...
...
노드(Node) : Html의 요소
- 요소노드(Element Node) : 태그, 요소, 객체
- 텍스트노드(Text Node) : 태그 내의 내용
<div>텍스트</div> => 텍스트 노드 존재
<input type="..."> => 텍스트 노드 존재하지 않음(Empty Tag 빈태그)
✅ screen 객체
console.log("화면너비:", screen.width);
console.log("화면높이:", screen.height);
console.log("실제너비:", screen.availWidth);
console.log("실제높이:", screen.availHeight);
--
화면너비: 1920
화면높이: 1080
실제너비: 1920
실제높이: 1032
✅ history 객체
버튼클릭시 이전 페이지, 앞전 페이지로 이동가능
<input type="button" onclick="history.back()" value="뒤로">
<input type="button" onclick="history.forward()" value="앞으로">
<input type="button" onclick="history.go(-1)" value="뒤로1번">
<input type="button" onclick="history.go(-2)" value="뒤로2번">
✅ location 객체
버튼클릭시 url 경로로 이동
<input type="button" onclick="location.href='https://www.naver.com'" value="네이버">
<input type="button" onclick="location.href='https://www.google.com'" value="구글">
✅ window 객체
feature : `width=${width}, height=${height}, left=${left}, top=${top}` : 오픈되는 위치 지정
버튼클릭시 window.open("오픈할 파일명", '', feature) 창 오픈
<input type="button" id="btn_open" value="창열기">
<input type="button" id="btn_close" value="창닫기">
<script>
let nwin; // 전역변수
document.getElementById("btn_open").addEventListener("click",() => {
let width = 480;
let height = 360;
// window.innerWidth, window.innerHeight: 현재 브라우저 창의 너비와 높이를 가져옴
// window.screenX, window.screenY: 현재 브라우저 창의 좌측 상단 기준 위치를 보정
let left = (window.innerWidth - width) / 2 + window.screenX;
let top = (window.innerHeight - height) / 2 + window.screenY;
let feature = `width=${width}, height=${height}, left=${left}, top=${top}`;
// open(화면에 출력할 페이지의 url 정보, 화면의이름, 옵션) : 새로운 창을 띄우기
// nwin : 팝업 페이지의 window 객체임
nwin = window.open("ex21_popup.html",'',feature);
// let를 붙이지 않으면 함수 내부에서도 전역변수 가능
})
</script>
✅ window.close() : 클릭이벤트를 사용하여 팝업 닫기 가능
// 팝업닫기
document.getElementById("btn_close").addEventListener("click", () => {
nwin.window.close(); // ex21_popup.html 브라우저 닫기.
window.alert("새창 닫기");
})
<!-- 팝업페이지.js -->
// window.close() : 현재 창을 닫기
document.getElementById("btn_close").addEventListener("click",() => {window.close();});
☑️ 이미지 이동
drop(event) : 드래그 대상이 영역에 drop 된 경우
dragover(event) : 드래그 대상이 내 영역위에 존재
dragstart : drag 시작.
dragend : drag 종료.
event : DragEvent (내장 이벤트)
draggable="true" : 드래그 가능
<div class="droptarget" ondrop="drop(event)" ondragover="allowDrop(event)">
<img src="images_01/apple.gif" ondragstart="dragStart(event)" ondragend="dragEnd(event)"
draggable="false" id="dragtarget1" width="100"> <!-- false 시 드래그 안됨 -->
<img src="images_01/apple.gif" ondragstart="dragStart(event)" ondragend="dragEnd(event)"
draggable="true" id="dragtarget2" width="100">
<p ondragstart="dragStart(event)" ondragend="dragEnd(event)"
draggable="true" id="dragtarget3">이동해주세요</p>
<h1 ondragstart="dragStart(event)" ondragend="dragEnd(event)"
draggable="true" id="dragtarget4">이동해주세요</h1>
</div>
<div class="droptarget" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<p id="demo1"></p>
<p id="demo2"></p>
event.dataTransfer : drag and drop 기능 구현시 드래그 중인 데이터에 접근할 수 있다.
event.target : 이벤트 발생 객체 : img,p,h1 태그
setData("형식", event.target.id) : 이동중인 태그의 id 속성값
let demo1 = document.querySelector("#demo1");
let demo2 = document.querySelector("#demo2");
function dragStart(event){
event.dataTransfer.setData("text", event.target.id);
demo1.innerHTML = "이동 시작합니다.";
}
function dragEnd(event){
demo1.innerHTML = "이동 완료되었습니다.";
}
function allowDrop(event){
event.preventDefault(); // 기본 이벤트 막기
demo2.innerHTML = "drag over 시작입니다.";
}
function drop(event){
event.preventDefault(); // 기본 이벤트 막기
let data = event.dataTransfer.getData("text"); // 이동중인 태그의 id 값 조회
// event.target : div 태그
// appendChild : 하위 객체로 추가
event.target.appendChild(document.getElementById(data));
demo2.innerHTML = "drag drop 이벤트가 발생했습니다.";
☑️ 글자 잡기 게임
기본설정 : 글자 스피드, 움직일수 있는 캠퍼스 범위, 글자수
function nextRandomInteger(limit){
return Math.round(Math.random() * limit); // 0 ~ limit 까지의 임의의 수 리턴
}
function randomSpeed(maxSpeed){ // -2 ~ 2 정도 사이의 임의의 수
return Math.random() * maxSpeed - Math.random() * maxSpeed;
}
let canvasWith = 700; // A 글자의 이동 가로 크기
let canvasHight = 500; // A 글자의 이동 세로 크기
let total = 10; // 글자의 수
h1(움직일 글자) 객체 생성 : css추가, clickEvent 추가(클릭시 텍스트 변경), 전체 카운트 감소
// 객체. 클래스. new MovingText() 객체화
function MovingText(){ // 생성자 => 멤버변수: x,y,vX,vy,body
this.x = nextRandomInteger(canvasWith); // 0 ~ 700사이의 임의의 정수 저장
this.y = nextRandomInteger(canvasHight); // 0 ~ 500사이의 임의의 정수 저장
this.vX = randomSpeed(2); // -2 ~ 2사이의 임의의 값
this.vY = randomSpeed(2); // -2 ~ 2사이의 임의의 값
// h1태그.
this.body = document.createElement("h1"); // <h1></h1>
this.body.innerHTML = "넥슨게임즈 떡상 가즈아!"; // <h1>A</h1>
this.body.setAttribute("style","background-color:white"); // <h1 style= "background-color:white;">A</h1>
this.body.style.position = "absolute"; // <h1 style= "background-color:white; position:absolute;">A</h1>
let text = this.body; // h1 태그
this.body.onclick = function(){ // 클릭 이벤트 등록.
--total;
alert("떡상까지 남은 주:" + total);
text.innerHTML = "30%로 상방 VI발동!!"; // 글자 변경
}
// document.body : <body><h1></h1></body
// appendChild : 하위태그 추가
document.body.appendChild(this.body);
}
글자 객체 움직임 설정 : 클릭한 글자(움직이지 않음), 캔버스 한계 도달시 역움직임(-1)
// prototype : 객체 외부에 멤버함수 추가하기
// MovingText.move() 추가
MovingText.prototype.move = function(){
if(this.body.innerHTML == '30%로 상방 VI발동!!') return; // 이미 잡힌 글자. 움직이지 않음
if(this.x < 0 || this.x > canvasWith){ // 가로 범위 이탈된 경우 이동 방향 반대로 설정
this.vX *= -1;
}
if(this.y < 0 || this.y > canvasHight){ // 세로 범위 이탈된 경우 이동 방향 반대로 설정
this.vY *= -1;
}
this.x += this.vX; // 가로 위치의 값을 변경
this.y += this.vY; // 세로 위치의 값을 변경
this.body.style.left = this.x + "px";
this.body.style.top = this.y + "px";
// <h1 style= "background-color:white; position:absolute; left:123px; top:30px;">A</h1>
// h1태그의 위치 설정
}
화면 시작시 이벤트 표출 : 배열으로 저장하여 3개 남을시 alert(), Interval 이벤트 취소, 종료
// 화면 시작된 경우, 화면이 실행될 준비가 완료경우 발생되는 이벤트
window.onload = function(){
let movingTexts = []; // 배열 객체 생성
for(let i = 0; i < 10; i++){
movingTexts.push(new MovingText()); //H1 태그 10개를 배열에 저장
}
let game = setInterval(function(){
for(let i in movingTexts){
// i : 인덱스값.
if(total < 4){ // total == 3, 7개의 글자를 잡으면 게임종료
alert("수익률 58000% 달성!!");
clearInterval(game); // setInterval 취소
return; // function 종료
}
// movingTexts[i] : MoveText 객체
movingTexts[i].move();
}
},1000/60); // 1초의 60번마다 function 실행
}
☑️ 숫자 야구게임
<div id="wrap">
<!-- img 태그 -->
<div id="card"></div>
<div id="left">
<!-- 숫자를 입력 영역 -->
<input type="text" id="userNum">
<!-- 입력된 값의 결과 처리 함수 호출 -->
<input type="button" id="inbtn" value="입력">
</div>
<!-- 결과 출력 부분 -->
<div id="result"></div>
</div>
✅ 정답 생성
ran 값(0~9사이의 임의의 정수)을 예를 들어 3 이라고 할때,
1. nums[0] 값(0)을 tmp에 저장 nums : 0 1 2 3 4 5...
2. nums[0] ← nums[3]값(3)를 저장 nums : 3 1 2 3 4 5...
3. nums[3] ← tmp값(0)를 저장 nums : 3 1 2 0 4 5...
answer[i] = nums[i] : 정답은 뒤섞인 nums[] 배열의 0~3 인덱스 번호까지의 값 : 3120(정답)
for(let i=0; i<nums.length;i++){
nums[i] = i; // 0 ~ 9까지의 값을 배열에 저장(중복방지)
}
// nums : 3 1 2 0 4 5 6 7 8 9
// nums 배열의 값을 shuffle.
for(let a=0; a<10; a++){
// ran = 3
let ran = Math.floor(Math.random() * nums.length); // 0~9사이의 임의의 정수. nums 배열의 인덱스
let tmp = nums[0]; // 0
nums[0] = nums[ran];
nums[ran] = tmp;
}
for(let i=0;i<answer.length;i++){
answer[i] = nums[i]; // 3 1 2 0
}
console.log("answer=" + answer); // 시스템이 저장한 정답 콘솔에 출력
✅ 화면이 실행할 준비 완료 시점에 발생되는 이벤트 window.onload = function(){
✅ 이미지 태그 동적 생성
createElement("img") : 동적요소 생성 후 setAttribut를 사용하여 css 스타일 추가
appendChild : 부모요소 안에 생성한 img 태그 추가
for(let i=0; i<4; i++){
// createElement(태그명) : <img/>
// img : img 태그 저장
let img = document.createElement("img");
// setAttribute(속성명, 속성값) : 속성등록
// 속성값 getAttribute(속성명) : 속성조회
// removeAttribute(속성명) : 속성제거
img.setAttribute("width",100);
img.setAttribute("height",100);
img.setAttribute("border",1);
// <img width="100",height="100" border="1" />
// #card 안에 img 요소추가
document.querySelector("#card").append(img);
}
✅ 입력버튼 이벤트 등록
입력된 값과, 정답을 비교하여 결과를 #result 영역에 추가
document.querySelector("#inbtn").onclick = function(){
// v_userNum : 사용자가 입력한 숫자 값값
let v_userNum = document.querySelector("#userNum").value;
// 입력값 검증
if(v_userNum == ""){
alert("숫자를 입력해주세요");
document.querySelector("#userNum").focus();
return; // 함수 종료 이벤트 핸들러 종료
}
// isNaN(문자열) : 숫자가 아닙니까?
if(isNaN(v_userNum)){ // true : 숫자아님, false : 숫자
alert("숫자 타입으로 입력해주세요");
document.querySelector("#userNum").focus();
return;
}
// 입력한 숫자의 갯수가 4개가 아닌경우
if(v_userNum.length != 4){
alert("4자리 숫자로 입력해주세요");
document.querySelector("#userNum").focus;
return;
}
// 4자리 숫자 입력한 경우
// inputarr : 4개의 숫자요소를 갖는 배열 값
inputarr = v_userNum.split("");
// 중복 검증
for(let v1 in inputarr){ // 1231
let cc = 0;
for(let v2 in inputarr){ // 1231
if(inputarr[v1] == inputarr[v2]) cc++;
}
if(cc > 1){
alert("중복된 숫자를 입력할 수 없습니다.");
document.querySelector("#userNum").focus();
return;
}
}
// 중복되지 않은 숫자 4개를 입력한 경우
matchingNum(v_userNum); // 정상적인 숫자가 입력된 경우
document.querySelector("#userNum").value = ""; // 입력란을 초기화
}
✅ keyEvent
keydown : 키가 내려갈때
keypress : 키가 누르고 있는 경우. deprecated 됨
keyup : 키가 올라올때
document.querySelector("#userNum").onkeyup = function(e){
if(e.keyCode == 13){ //Enter 키
// 입력버튼 클릭함. 강제로 입력버튼의 클릭이벤트 발생
document.querySelector("#inbtn").onclick();
}
}
✅ 정답값 과 입력값 매칭 함수
정답배열과 입력값 배열을 for문으로 돌려 각각의 숫자(값, 인덱스) 일치시 strike++, 포함시 ball++
function matchingNum(usernum){
// usernum : 중복되지 않게 입력된 4자리 숫자
let strike = 0;
let ball = 0;
let inputarr = usernum.split("");
// inputarr : [1,2,3,4]
// answer : [5,2,3,6]
for(let i=0;i<4;i++){
for(let j=0;j<4;j++){
if(answer[j] == inputarr[i]){ // 5 2
if(i == j) strike++;
else ball++;
}
}
}
console.log("strike=" + strike, "ball=" + ball);
✅ 정답/오답 시 화면출력 함수
location : 현재 브라우저의 URL 정보, reload() : 새로고침하기
location.reload(); //초기화면으로 변경. 새로운 정답을 저장
if(strike == 4){ // 정답
let wrap = document.getElementById("wrap");
let h1_1 =
document.querySelector("#result").innerHTML += ("<h1>축하합니다. 정답입니다.</h1>");
document.querySelector("#wrap").innerHTML += ("<button>다시시작</button>");
// 다시시작 버튼의 이벤트 등록
document.querySelector("button").onclick = function(){
// location : 현재 브라우저의 URL 정보
// reload() : 새로고침하기
location.reload(); //초기화면으로 변경. 새로운 정답을 저장
}
// 이미지 요소들을 조회
// cimgs 배열객체 : 4개의 img 태그저장
cimgs = document.getElementsByTagName("img");
for(let i in cimgs){
cimgs[i].src = "../javascript/images/num" + answer[i] + ".jpg"; // 정답에 맞는 이미지가 화면 출력
}
}else{ // 정답이 아님
strike += "S "; //1S (문자열 값으로 변경. 자료형 변경)
ball += "B"; // 1B
let result_div = document.querySelector("#result");
result_div.innerHTML += ++trycount + "번째 도전 : " + strike + ball + ", 유저입력값 : " + usernum + "<br/>";
}
Test
☑️ 주석으로 처리된 결과가 나오도록 Person 객체 생성하기
김삿갓 | kimsg.tistory.com | 이몽룡 | leemy.tistory.com
내부지정방식(맴버변수)
this.getName = function() {
return this.name;
}
외부지정방식
Person.prototype.getBlog = function(){
return this.blog;
}
function Person(name, blog){
this.name = name;
this.blog = blog;
this.getName = function() {
return this.name;
}
}
Person.prototype.getBlog = function(){
return this.blog;
}
let kim = new Person("김삿갓","kimsg.tistory.com");
let lee = new Person("이몽룡","leemy.tistory.com");
document.write(kim.getName(),"<br>") //김삿갓
document.write(kim.getBlog(),"<br>") //kimsg.tistory.com
document.write(lee.getName(),"<br>") //이몽룡
document.write(lee.getBlog(),"<br>") //leemy.tistory.com
☑️ Array 객체에 contain 메서드 추가하기
const a = [273,32,103,57,52]
Array.prototype.contain = function(e) {
for(let i=0; i<a.length; i++){
if(e == a[i]){
return true;
break;
}else{
return false;
}
}
}
document.write("273 in [273,32,103,57,52] : "+a.contain(273) + "<br>") //true
document.write("0 in [273,32,103,57,52] : "+a.contain(0) + "<br>") //false
Array.prototype (배열)
배열 자바스크립트에서 가장 중요한 3가지를 꼽으라 하면 객체, 함수, 그리고 배열일 것이다. 가장 큰 이유 중에 하나는 JSON이 배열과 객체의 조합으로 이루어져 있다는 것. 하지만 자바스크립트
velog.io
☑️ 이미지 잡기 게임
랜덤 수 범위, 이미지 속도 범위, 캔버스 크기, 최대 이미지 갯수 설정
function nextRandomInteger(limit){
return Math.round(Math.random() * limit); // 0 ~ limit 까지의 임의의 수 리턴
}
function randomSpeed(maxSpeed){ // -2 ~ 2 정도 사이의 임의의 수
return Math.random() * maxSpeed - Math.random() * maxSpeed;
}
let canvasWith = 700; // 캔버스 가로 크기
let canvasHight = 500; // 캔버스 세로로 크기
let total = 5; // 이미지의 총 갯갯수
✅new MovingImg() 객체화 : 생성자 => 멤버변수: x,y,vX,vy,body
function MovingImg(){ // 생성자 => 멤버변수: x,y,vX,vy,body
this.x = nextRandomInteger(canvasWith); // 0 ~ 700사이의 임의의 정수 저장
this.y = nextRandomInteger(canvasHight); // 0 ~ 500사이의 임의의 정수 저장
this.vX = randomSpeed(2); // -2 ~ 2사이의 임의의 값
this.vY = randomSpeed(2); // -2 ~ 2사이의 임의의 값
// h1태그.
this.body = document.createElement("img");
this.body.setAttribute("width", 35);
this.body.setAttribute("height", 35);
// 초기 이미지(바나나 세팅)
this.body.setAttribute("src", "banana.jpg");
this.body.style.position = "absolute";
let text = this.body; // img 태그
this.body.onclick = function(){ // 클릭 이벤트 등록.
--total;
alert("남은 바나나 갯수:" + total);
text.src = "apple.gif"; // 이미지 변경경
}
document.body.appendChild(this.body);
}
✅ MovingImg.move() 멤버 함수 추가
MovingImg.prototype.move = function(){
let pos = this.body.src.indexOf("apple.gif");
if(pos > 0) return; // 이미 잡힌 글자. 움직이지 않음
if(this.x < 0 || this.x > canvasWith){ // 가로 범위 이탈된 경우 이동 방향 반대로 설정
this.vX *= -1;
}
if(this.y < 0 || this.y > canvasHight){ // 세로 범위 이탈된 경우 이동 방향 반대로 설정
this.vY *= -1;
}
this.x += this.vX; // 가로 위치의 값을 변경
this.y += this.vY; // 세로 위치의 값을 변경
this.body.style.left = this.x + "px";
this.body.style.top = this.y + "px";
// <h1 style= "background-color:white; position:absolute; left:123px; top:30px;">A</h1>
// h1태그의 위치 설정
}
✅ 화면 시작된 경우, 화면이 실행될 준비가 완료경우 발생되는 이벤트
window.onload = function(){
let movingImgs = []; // 배열 객체 생성
for(let i = 0; i < 5; i++){
movingImgs.push(new MovingImg()); //H1 태그 10개를 배열에 저장
}
let game = setInterval(function(){
for(let i in movingImgs){
// i : 인덱스값.
if(total == 0){
alert("게임종료");
clearInterval(game); // setInterval 취소
return; // function 종료
}
// movingImgs[i] : MoveText 객체
movingImgs[i].move();
}
},1000/60); // 1초의 60번마다 function 실행
}
☑️ 자바스크립트 실습문제
1. 실행 버튼 클릭시 사용자에게 알람창(prompt)으로 "메세지를 입력하세요"문구를 출력
단, 사용자에게 입력받은 값이 없을 경우 "메세지가 입력되지 않았습니다." 출력
function test1(){
let result = prompt("메세지를 입력하세요");
// 값 : 빈값이 아닌경우
if(result !== ""){
document.getElementById("test1").innerHTML = result;
}else{
alert("메세지가 입력되지 않습니다.");
return;
}
}
2. 실행 버튼 클릭시 사용자에게 알람창(confirm)으로 "개인정보활용에 동의하시겠습니까?"를 출력
확인을 누르면 "당신의 개인정보가 유출되었습니다", 취소를 누르면 "당신의 개인정보 유출을 막았습니다" 메세지 출력
function test2(){
let result = confirm("개인정보활용에 동의하시겠습니까?");
if(result){
document.getElementById("test2").innerHTML = "당신의 개인정보가 유출되었습니다.";
}else{
document.getElementById("test2").innerHTML = "당신의 개인정보 유출을 막았습니다.";
}
}
3. 실행 버튼 클릭시 10개의 랜덤(1~100)값을 발생시켜 해당 랜덤값을 담은 배열을 만들고
해당 배열을 내림차순 정렬 한 후 해당 숫자들이 div#test3>ul 안에 총 10개의 li 요소로 출력
let arr = [];
document.querySelector("div#test3>ul").innerHTML = ""; //초기화
// 10개의 랜덤 정수 반환
for(let i=0; i<=9; i++){
let num = Math.round(Math.random() * 100 + 1);
arr.push(num);
}
// 내림차순
arr.sort(function(left,right){return right - left});
// li요소로 저장
arr.forEach(function(item){ // 매개변수를 써두면 매번 각인덱스에 담겨있는 value값이 순차적으로 전달되어 대입됨!
document.querySelector("div#test3>ul").innerHTML += "<li>" + item + "</li>";
})
4. input[type=text name=img]인 요소에 화면에 출력하고자 하는 이미지의 경로를 입력받은 후에
출력 버튼 클릭하면 div.img-container 요소 내에 사용자가 입력한 주소의 img가 200X200크기로 출력
function test4(){
let reult = document.getElementsByName("img")[0].value;
// 동적요소를 dom요소 객체로 만들기
let img = document.createElement("img");
img.setAttribute("width",200);
img.setAttribute("height",200);
img.setAttribute("src", reult);
// 부모요소.appendChild(자식태그요소)
document.querySelector(".img-container").appendChild(img);
}
5. 아래 태그의 데이터를 확인하기 버튼을 클릭하면 모두 가져와 3글자 이상인 데이터만 div#checkStr에 출력
function test5() {
// .data-container 내부의 모든 요소 선택하여 배열로 저장
let elements = document.querySelectorAll(".data-container *");
let result = [];
// 각 요소의 텍스트를 검사하여 3글자 이상인 것만 필터링
elements.forEach(el => {
let text = el.textContent.trim();
if (text.length >= 3) {
result.push(text);
}
});
// 결과를 #checkStr 내부에 출력
document.getElementById("checkStr").innerHTML = result.join("<br>");
}
PS. 게임개발자가 존경스러워진다.
'JavaScript' 카테고리의 다른 글
| [BCGD] 비전공자 백엔드 개발 도전기 (주말과제) (0) | 2025.03.31 |
|---|---|
| [BCGD] 비전공자 백엔드 개발 도전기 (37) (1) | 2025.03.29 |
| [BCGD] 비전공자 백엔드 개발 도전기 (35) (2) | 2025.03.25 |
| [JavaScript] forEach/each/append/appendChild 총 정리 (0) | 2025.03.23 |
| [BCGD] 비전공자 백엔드 개발 도전기 (34) (0) | 2025.03.22 |
