파일명 : boardwrite.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시판글쓰기</title>
<style>
.container {
width : 600px;
margin : 0px auto;
border : 3px solid #cccccc;
padding : 15px; //패딩 값도 마진과 마찬가지로 4방향설정. 한 값만 주면 4방향 모두 그 값이 되는것.
// 높이를 계속 안준 이유? 안줘야지 내용이 자연스럽게 콘테이너 안에 들어감. 높이를 줬는데 내용이 많을 경우 컨테이너 밖으로 삐져나온다.
//처음에는 테두리 값을 주고 하는게 어느정도 간격이 되는지 눈에 보여서 알기 쉽다. 최종적으로는 안보이게 해야 깔끔!
}
.grid {
display : grid;
grid-template-columns: 100px auto;
/* grid-template-rows: 100px; 높이설정 */
//한 값 주고 오토를 주면 컨테이너에서 주어진 값을 뺀 나머지 값을 알아서 가져간다.
}
.item {
border : 0px solid #25a61b ;
margin : 5px;
} //item간에 간격을 주고 싶어서 마진을 사용.
.item:nth-child(1) { //특정 그리드 내의 설정만 바꾸는것 nth-child 잊지마!
justify-self: center; /* start end center */
}//가로배열 조절
.item:nth-child(3) {
align-self: center; /* start end center */
}//세로배열 조절
</style>
</head>
<body>
<div class="container">
<h3>글쓰기</h3>
<div class="grid">
<div class="item">
<label>제목</label> //그냥 제목이라고 해도 되지만 label로 묶는 이유? 찾기 쉬움, 스타일 설정 등 변화를 줘야 할때도 편리.
</div>
<div class="item">
<input type="text" id="title" placeholder="제목입력" autofocus />
//여기에 id를 지정한것은 보여지는데에는 아무 영향 없으나 이후에 상수로 지정하여 정보를 읽고, 변화를 줄때에 편하게 하기 위해서.
</div>
<div class="item">
<label>내용</label>
</div>
<div class="item">
<textarea rows="6" id="content" cols="22" style="resize: none;" placeholder="내용입력"></textarea> //축약 될꺼 처럼 생긴 태그지만 안됨.
//입력창이 마우스로 마음대로 크기 조절되는게 보기 싫다. resize 못하게해.
</div>
<div class="item">
<label>작성자</label>
</div>
<div class="item">
<input type="text" id="writer" placeholder="작성자입력" />
</div>
<div class="item">
</div>//버튼을 오른쪽 그리드에 놓고 싶어서 빈 아이템을 생성한것.
<div class="item">
<div style="margin:30px">
<button onclick="func()">글쓰기</button>//버튼을 클릭할때 함수가 동작하도록 만듬.
<button>목록으로</button>
</div>
</div>
</div>
</div>
//프론트는 보이는 화면을 만드는것과 REST풀(?)로 구성된다. html과 css는 화면 구성을 보기 좋게 하는 역할. 입력된 데이터들을 백엔드로 전송->백엔드에서 데이타 베이스로 전송->성공or실패 반환값이 백엔드로 돌아옴->백엔드에서 프론트엔드로 전송하는 역할은 js가 담당한다.
//이때 뭔가 오류가 생겨서 알림창이 뜬다면 이 알림창은 크롬과 같은 웹 브라우저가 띄우는 것이다. 해석한 주체가 크롬이니까! 서버는 그저 데이터를 던지는것 뿐. 그래서 크롬에서는 오류가 생겨도 파이어폭스에서는 잘되고... 그런 경우도 있음. 해석의 주체가 다르므로.
//그래서 오류를 확인하고 싶으면 데이터에서 확인하는것이 아님. 웹 브라우저에서 확인해야함. 웹 브라우저 창에서 f12를 눌러서 콘솔로 확인하면 오류난 내용을 알수있다. 아주중요!!
//자바 스크립트는 헤드 앞부분에 넣는경우, 뒷부분에 넣는 경우가 있으나 주로 뒤에 넣음.
//왜냐하면 크롬과 같은 웹 브라우저들은 첫번째 라인 부터 순서대로 읽어서 그림을 그리는데 동작이 되기 전에 화면부터 나오는것이 중요. 화면이 나오기 전에 동작부터 되게 하려고 세팅하면 느리다. 그래서 뒷부분에 스크립트를 입력.
<script>
// 바로 실행됨. 즉 준비물
const ti = document.getElementById('title'); /* 제목 */
//const는 상수. 상수말고 변수도 있으나 일단은 구분하지말고... 뒤에서 자세히 배울 예정.
//임의로 지정한 문자(여기서는 ti)에 = 이후의 내용을 담아서 그걸 상수로 만든다고 생각. ti는 document..이후의 내용을 담고 있는 상수인것.
//왜 담아야 하는가? 입력된 정보를 담아놔야지 백엔드로 전송할수 있으니까!
//그래서 사용자가 입력한 값을 어떻게 담을지가 굉장히 중요하다.
//get..은 이름에서도 짐작할수 있듯이 id값을 찾아서 ti에 넣어주는 역할.
//위에서 id로 title을 지정했으므로 겟바이id를 쓴것. class로 지정했다면 겟바이class를 써야한다.
console.log(ti);
//콘솔 로그는 잘 담아졌는지 확인하기 위한것. 콘솔창에서 오류가 떴는지 확인할수있다. 개발자를 위한것이므로 배포시에는 주석처리 하고 날려버려.
const co = document.getElementById('content');
console.log(co);
const wr = document.getElementById('writer');
console.log(wr);
//스크립트부터 위의 값들은 함수가 실행되는데 필요하긴 하지만 전부 함수에 걸려 있을 필요는 없다. 함수에 걸어 놓으면 함수 작동 속도가 느려짐. 수업 전에 준비물 미리 안꺼내 놓으면 수업 시작하고 나서 부랴부랴 준비물 꺼낸다고 정신 없는거랑 마찬가지.
// 함수를 만듬, 즉시 실행되지 않음, 호출이 되어야 실행됨.
function func() {
//즉시 실행되면 안될때 함수를 만든다. 글쓰기 버튼을 눌를때만 데이터를 전송해야함. 사용자의 타이밍에 맞춰서 기다려야해.
//func()가 함수의 명칭. 괄호도 빼먹지 마라.
//함수가 실행되도록 하는 타이밍은 글쓰기 버튼이 눌려 졌을때이므로 위에서 글쓰기 버튼에 onclick을 걸어준것.
if(ti.value === ''){
alert('제목을 입력하세요.'); /* 알림표시함 */
ti.focus();
return false; /* 벡엔드 전송하지 않음 */
}
if(co.value === ''){
alert('내용을 입력하세요.');
co.focus();
return false;
}
if(wr.value === ''){
alert('작성자를 입력하세요.');
wr.focus();
return false;
}
//글쓰기 누르면 입력된 값이 있는지 확인해야한다. 내용이 없으면 백엔드에 넘겨줄 필요가 없으니까.
//ti, co, wr의 값이 비어있는지('') 확인하고 만약 그렇다면 알림을 띄우고 바로 해당하는 창에 커서가 찍히도록 한다.
//return false는 백엔드로 값을 보내지 말라는 뜻. 이 문장을 넣지 않을경우 오류가 떴음에도 다음 if문이 읽어져서(?) 알림창이 연달아 뜬다.
// 여기가 벡엔드로 전송할 타이밍!!!
// 다 입력했기 때문에
alert('벡엔드 전송');
}
</script> //script 축약형 안됨.
</body>
</html>
파일명 : board.html
<!DOCTYPE html>
<html lang="ko"> //기본값은 en이라 크롬에서 열면 번역해줄까? 하는 알림이 자동으로 뜸.
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시판 목록</title>
<style>
.container {
width : 600px;
margin : 0px auto;
border : 3px solid #cccccc;
padding : 15px;
}
table {
width : 100%;
}
/* 태그명 그대로, "." 클래스로, "#"아이디 */
</style>
</head>
<body>
<div class="container">
<h3>게시판목록</h3>
<hr />
<table border="1">
//목록에는 table을 많이 쓴다.
<thead>
<tr>// table row. 테이블에서 하나의 행을 정의. th나 td를 가짐.
<th>번호</th> // table head. 표의 제목
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>날짜</th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<td>1</td> // table data. 셀을 만드는 역할.
<td>aaa</td>
<td>bbb</td>
<td>1</td>
<td>2022-12-12</td>
</tr>
<tr>
<td>2</td>
<td>aaa</td>
<td>bbb</td>
<td>1</td>
<td>2022-12-12</td>
</tr>
<tr>
<td>3</td>
<td>aaa</td>
<td>bbb</td>
<td>1</td>
<td>2022-12-12</td>
</tr>
</tbody>
</table>
</div>
//위의 테이블은 하나하나의 값을 직접 정해준것. 그렇다면 데이터에서 받은 정보는 어떻게 표기하나? 내가 정할수 없잖아? js를 쓰는것.
<script>
/* 벡엔드로 전달, 받기는 모두 script만 가능 */
const a = '124'; /* 변수 문자를 보관 */
//작은 따옴표가 있으면 문자로 취급한다.
console.log(a); //문자 124가 출력
/* 변수 객체를 보관 */
const obj = {
no : 4,
title : 'aaa',
writer : 'bbb',
hit : 5,
regdate : '2022-12-12'
};
//당장 백엔드에서 데이터를 받아오는건 아직 안배웠기 때문에 받아왔다 치고.. 이런식으로 받아온다는걸 풀어서 쓴것.
//5개의 항목을 각기 따로따로 const를 걸면 비효율적. 5개가 정확히 와야하는데 하나라도 안오면 중간에 손실남. 데이터는 다 오던가 다 안오던가 두가지 경우만 존재해야한다. 그래서 obj로 묶어서 객체를 보관하는것! 압축한다 생각.
//객체는 { key : value, ..} 꼴
console.log(obj); /* 객체 전체 출력 */
console.log(obj.title); /* 객체 내부의 제목만 출력함 */
console.log(obj['title']); /* 위와 동일 방식 */
//압축한걸 풀어서 나온 값을 읽는것.
// 태그 중에서 아이디가 tbody인것 찾기
const tb = document.getElementById('tbody');
// 왜 찾나? tbody 하위에 값을 추가 하고 싶으니까. 추가 하고 싶은 값의 부모를 찾아야 한다. 그래서 위에서 tbody에 id를 부여해둠.
// 찾은 태그에 html 태그를 추가하기 ( += )
tb.innerHTML +=
`<tr>` +
`<td>${obj.no}</td>` +
`<td>${obj.title}</td>`+
`<td>${obj.writer}</td>`+
`<td>${obj.hit}</td>`+
`<td>${obj.regdate}</td>`+
'</tr>';
//추가하는 값은 고정된게 아님. 이때는 '작은 따옴표가 아니라 `백틱을 사용한다.
//객체의 값 불러 오는 꼴!!!! 꼭 기억하자 중요해!!!!
//이런 식으로 데이터를 백엔드로 부터 받아서 적절한 방식으로 꺼내서 태그를 이용해 화면에 배치하는게 프론트엔드의 전체 골격이다.
</script>
</body>
</html>
파일명 : iteminsert.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>물품등록</title>
<style>
.container {
width : 600px;
margin : 0px auto;
border : 3px solid #cccccc;
padding : 15px;
}
.lbl {
display : inline-block;
width : 100px;
}
</style>
</head>
<body>
<div class="container">
<h3>물품등록</h3>
<hr />
<div>
<label class="lbl">물품명</label>
<input type="text" class="input" placeholder="물품명" />
</div>
// 변수 or 상수 선언을 위해서 id만 써야 하는 것은 아니다.
//id는 고유해야하지만 class는 그렇지 않다. 그래서 style에서 class를 사용한것. 여러군데에서 쓰니까!
//여기에서도 물품명, 가격, 수량에 각각 id를 부여해도 되지만 편의성을 위해 class로 여러개의 값을 배열하려고 함.
<div>
<label class="lbl">가격</label>
<input type="text" class="input" placeholder="가격" />
</div>
<div>
<label class="lbl">수량</label>
<input type="text" class="input" placeholder="수량" />
</div>
<div>
<label class="lbl">이미지</label>
<img src="imgs/noimage.jpg" id="img" style="height:100px" />
//이미지를 사용하기 위해서는 resource로 미리 저장(?)을 해두어야 한다.
//html은 이미지 있는 곳을 연결해서 표시하는 역할을 하는것.
<input type="file" onchange="handleImage(this)" />
//이미지 파일이 변화되었을때 알고 싶다! onchange 사용.
//그러나 이미지 파일의 변화에만 촛점을 맞추면 이게 첨부가 안되있다가 된건지 됐다가 안된 상태로 바뀐건지 알수가 없음. 변화가 있었다는거만 알 수 있을뿐.
//그래서 이미지를 첨부하면 첨부한 파일이 뜨면 좋겠다. 그러기 위해선 나자신에 대한 정보를 넘겨야 한다. this 사용.
//this를 사용하므로써 어떤 메커니즘이 발생하는지를 모르겠어서 어렵게 느껴짐. 좀더 공부할것.
</div>
<div>
<label class="lbl"></label>
<button onclick="handleInsert()">등록</button>
//이건 등록 버튼 눌렀을때 함수가 실행되야하니까 onclick 사용.
</div>
</div>
<script>
/* 페이지 로딩시 바로 실행되는 부분 */
const c = [ 21, 26, 43, 54 ]; // 이렇게 복수형으로 되는걸 배열이라고 한다. 하나씩 const로 지정하면 낭비. []로 묶음.
console.log(c[2]); //0번부터 시작하기 때문에 43이 출력됨.
/* 배열 */
// const ip = [ <input>, <input>, <input> ]
const ip = document.getElementsByClassName('input');
//input을 class로 지정했기 때문에 클래스 네임을 찾아라!
//자세히 보면 엘리먼트가 복수임. id랑은 다르게 여러개를 가져오는거니까.
const img = document.getElementById('img');
//id는 한개라서 엘리먼트가 단수다.
//const e.files = {0: File, length: 1}
//const e.files = {length: 0}
/* 이미지가 변경될 때 실행되는 부분 */
function handleImage( e ) {
console.log( e.files );
console.log( e.files.length ); //e.files['length']
//오늘 수업의 고비... e는 임의로 정한 문자.
//files의 정체는 아직 알수없음.. 좀더 뒤에 설명해주신다고함.
//this를 입력하므로써 파일이 첨부 됐는지 아닌지의 여부를 e에 객체화함..?
//이게 명시 되어 있지 않지만 콘솔로 띄우면 보인다. 이미지 파일이 첨부되면 {0: File, length: 1}로 뜸. 즉 보이진 않지만 받아진 데이터가 있다는것!
//첨부 되지 않으면 {length: 0}으로 뜸
//아까 객체 표기법이 기억나는가? const obj ={ name : '가나다', age : 13 }
//바로 와닿지 않아서 어려워 보이지만 결국 이것처럼 객체화된 정보를 불러온것.
//이때 obj.name을 하면 '가나다'가 출력될것이고 obj.age를 하면 13이 출력됨.
//이것처럼 파일이 첨부된 상태이면 e.files[0]을 하면 File이 출력되고 e.files.length를 하면 1이 출력됨.
//파일이 첨부되지 않았으면 0에 해당하는 값은 없고 e.files.length를 하면 0이 출력되는것.
// 첨부한 상태
if(e.files.length > 0){
console.log(e.files[0]); //e.files.0 숫자라서 안됨.
img.src = URL.createObjectURL(e.files[0]);
}
// 첨부 취소한 상태
else {
img.src = 'imgs/noimage.jpg';
}
//첨부한 상태와 첨부 되지 않은 상태는 length로 구분하면 되겠군!
//첨부된 이미지를 띄우는 법은 아직 안배웠으나..대충 말하신건 파일정보가 넘어와서 크롬에서 가상의 url을 만들었고 그 정보를 src로 넣은것.
//첨부 취소됐을때 이미지는 리소스에 넣어두고 쓰는것. 기본 이미지라 생각.
};
/* 등록 버튼을 클릭했을 때 실행되는 부분 */
function handleInsert() {
if(ip[0].value === ''){
alert('물품명 입력하세요.');
ip[0].focus();
return false;
}
if(ip[1].value === ''){
alert('가격을 입력하세요.');
ip[1].focus();
return false;
}
if(ip[2].value === ''){
alert('수량을 입력하세요.');
ip[2].focus();
return false;
}
//class로 배열했으므로 0, 1, 2로 구분해서 읽어냄.
//함수들끼리의 위치는 상관없다. 어차피 이벤트가 발생할때만 동작하므로.
};
</script>
</body>
</html>
-- 라이브러리 활용
파일명 : boardwrite.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시판글쓰기</title>
<link href="css/quill.snow.css" rel="stylesheet" /> //quill editor에서 다운 받은것.
<link href="css/board.css" rel="stylesheet" /> //원래 헤드에 스타일로 만들어 썼던걸 css로 옮김.
</head>
<body>
<div class="container">
<h3>글쓰기</h3>
<div class="grid">
<div class="item">
<label>제목</label>
</div>
<div class="item">
<input type="text" id="title" placeholder="제목입력" autofocus />
</div>
<div class="item">
<label>내용</label>
</div>
<div class="item">
<div id="editor" style="height: 400px;"></div>
//다운받은 css, js를 이용해서 원하는 부분을 바꾸고 싶으면 div태그를 사용해야한다.
</div>
<div class="item">
<label>작성자</label>
</div>
<div class="item">
<input type="text" id="writer" placeholder="작성자입력" />
</div>
<div class="item">
</div>
<div class="item">
<div style="margin:30px">
<button onclick="func()">글쓰기</button>
<a href="/board.html">
<button>목록으로</button>
</a>
</div>
</div>
</div>
</div>
<script src="js/board.js" type="text/javascript"></script> //js도 css처럼 따로 빼서 리소스로 사용.
<script src="js/quill.min.js" type="text/javascript"></script>
//똑같은 이름의 min없는 버전은 수정이 용이하나 느리고 min 버전은 공백을 없앤거라 수정은 불가능(알아보기 힘들어서)하지만 빠르게 동작한다.
<script>
var quill = new Quill('#editor', {
theme: 'snow'
});
//이렇게 하니 진짜 글쓰는 창 모양이 됨... 결국 손으로 짜는건 엉성할 수 밖에 없으니 잘만들어 진걸 가져와서 쓰는것.
//quill editor 다운로드 누르면 링크에//cdn....복사해서 주소창에 쳐서 이동한->크롬에서 점점점 눌러서 도구 더보기->페이지를 다른이름으로 저장.->홈페이지에서 퀵스타트를 참조하면 어디에 뭘 입력해야 하는지 알려줌. 여기 마지막에 따로 은 script처럼...
//최종적으로 자바 스크립트 때문에 바뀌는것. 없으면 빈 div다. 써줘야 위에 있는 div가 원하는 형태로 바뀜.
</script>
</body>
</html>
files는ㄴ 속성들의 값. 정보를 보관하고 있는것. 실제 보관된느건 e안에 files에 보관되는것. 정해진것