오늘 완성한 웹앱의 1) GAS 창, 2)웹앱 을 새 창으로 켜 놓고 시작합니다~
1. html 파일의 구조
내용 보기
html 파일은 아래와 같이 구성됩니다.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
</body>
</html>- <html>,</html> : html문서의 시작과 끝
- <head>,</head> : html 문서에 대한 정보 정의하는 영역(언어, 제목, 뷰포트 등)
- <body>,</body>: 클라이언트에게 보여지는 모든 것이 담기는 영역
지금은 웹앱의 특성상 <style>태그와 <script>태그가 추가되어 있는 구조입니다.
<!DOCTYPE html>
<html>
<head>
<style>
</style>
<script>
</script>
</head>
<body>
</body>
</html>- <style>: CSS코드가 들어가는 부분. 사실상 디자인 영역
- <script>: 자바스크립트 코드가 들어가는 영역
우리가 만든 코드 안에서도 html 기본 구조를 확인해 봅시다.
html코드 보기
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
body { font-family: "맑은 고딕", sans-serif; margin: 20px; }
h2, h3 { text-align: center; margin-bottom: 20px; }
.greeting-box { border: 1px solid #ccc; border-radius: 8px; padding: 15px; background-color: #f9f9f9; margin-bottom: 20px; line-height: 1.6; }
table { border-collapse: collapse; width: 100%; max-width: 800px; margin: 0 auto 30px auto; text-align: center; }
table, th, td { border: 1px solid #999; }
th, td { padding: 10px; }
th { background-color: #f0f0f0; }
.form-section { max-width: 600px; margin: 0 auto; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input[type="text"], select, textarea { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-family: inherit; }
textarea { height: 80px; resize: vertical; }
.radio-group { display: flex; gap: 20px; }
.submit-btn { display: inline-block; background-color: #4CAF50; color: white; padding: 10px 20px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; transition: background-color 0.3s ease; }
.submit-btn:hover { background-color: #45a049; }
</style>
<script>
function submitForm() {
const name = document.getElementById("studentName").value.trim();
const date = document.getElementById("dateSelect").value;
const time = document.querySelector("input[name='time']:checked")?.value || "";
const note = document.getElementById("note").value.trim();
if (!name || !date || !time) {
alert("학생 이름, 날짜, 시간을 모두 입력해주세요.");
return;
}
google.script.run
.withSuccessHandler(function(response) {
const btn = document.getElementById("submitBtn");
if (response === "success") {
btn.innerText = "전송 완료";
btn.disabled = true;
btn.style.backgroundColor = "#999";
alert("상담 예약이 완료되었습니다.");
loadReservationData(); // 저장 후 표 갱신
} else if (response === "duplicate") {
alert("이미 예약이 존재합니다. 다른 날짜 또는 시간을 택해주세요.");
} else {
alert("예약 중 오류가 발생했습니다. 다시 시도해주세요.");
}
})
.saveReservation(name, date, time, note);
}
// 서버에서 시트 데이터 읽어와 표에 표시
function loadReservationData() {
google.script.run.withSuccessHandler(function(data) {
const times = ["19:00-20:00","20:00-21:00"];
const dates = ["9.15.(월)","9.16.(화)","9.17.(수)","9.18.(목)","9.19.(금)"];
times.forEach((time, rowIdx) => {
dates.forEach((date, colIdx) => {
const cell = document.querySelectorAll("table tr")[rowIdx + 2].cells[colIdx + 1];
cell.textContent = data[time][date] || "";
});
});
}).getReservationData();
}
window.onload = function() {
loadReservationData(); // 페이지 로드 시 예약 현황 표시
};
</script>
</head>
<body>
<h2>아이좋아고등학교 3학년 1반 학부모 상담 예약</h2>
<div class="greeting-box">
안녕하십니까. 3학년 1반 학부모님. 학기초 상담주간을 맞이하여 학부모 상담을 실시하고자 합니다.
바쁘시겠지만 시간을 내시어, 자녀의 학교 생활 및 교우 관계, 진로진학과 관련하여 알찬 시간이 될 수 있도록 많은 참석 부탁드립니다.
원하는 날짜와 시간을 선택하셔서 상담 예약을 부탁드립니다.
</div>
<table>
<tr>
<td></td>
<td>월</td>
<td>화</td>
<td>수</td>
<td>목</td>
<td>금</td>
</tr>
<tr>
<td></td>
<td>9.15.</td>
<td>9.16.</td>
<td>9.17.</td>
<td>9.18.</td>
<td>9.19.</td>
</tr>
<tr>
<td>19:00-20:00</td>
<td></td><td></td><td></td><td></td><td></td>
</tr>
<tr>
<td>20:00-21:00</td>
<td></td><td></td><td></td><td></td><td></td>
</tr>
</table>
<h3>상담 신청</h3>
<div class="form-section">
<div class="form-group">
<label>1. 학생의 이름을 적어주세요</label>
<input type="text" id="studentName" placeholder="예: 홍길동">
</div>
<div class="form-group">
<label>2. 원하시는 날짜를 택해주세요</label>
<select id="dateSelect">
<option value="">-- 선택하세요 --</option>
<option value="9.15.(월)">9.15.(월)</option>
<option value="9.16.(화)">9.16.(화)</option>
<option value="9.17.(수)">9.17.(수)</option>
<option value="9.18.(목)">9.18.(목)</option>
<option value="9.19.(금)">9.19.(금)</option>
</select>
</div>
<div class="form-group">
<label>3. 원하시는 시간을 택해주세요</label>
<div class="radio-group">
<label><input type="radio" name="time" value="19:00-20:00"> 19:00-20:00</label>
<label><input type="radio" name="time" value="20:00-21:00"> 20:00-21:00</label>
</div>
</div>
<div class="form-group">
<label>4. 참고사항이 있다면 적어주세요.</label>
<textarea id="note" placeholder="예: 아이의 성향, 특별히 상담하고 싶은 내용 등"></textarea>
</div>
<button id="submitBtn" class="submit-btn" onclick="submitForm()">전송</button>
</div>
</body>
</html>
.
2.body태그
내용 보기
클라이언트 눈에 보이는 모든 것은 <body>태그 안에 있다.
1)제목

<body>
<h2>아이좋아고등학교 3학년 1반 학부모 상담 예약</h2>- <h2></h2> : 글자 크기를 2단계로 하라.

.
2) 학생 이름 입력란

<div class="form-group">
<label>1. 학생의 이름을 적어주세요</label>
<input type="text" id="studentName" placeholder="예: 홍길동">
</div>- <div></div> : 영역으로 묶는 코드
- class = “form-group” : 이 구역(div)의 class선택자를 form-group으로 하라.
- <input> : 사용자로부터 입력받는 요소를 생성하는 태그(이름, 전화번호, 주소, 의견,..)
| type=”text” : 텍스트 타입을 입력받을것
| id = “studentName” : 이 입력폼의 id선택자를 studentName으로 하라.
| placeholder : 입력값에 대한 힌트
3) 전송 버튼

<button id="submitBtn" class="submit-btn" onclick="submitForm()">전송</button> - <button>,</button> : 버튼 생성 태그
- 이 버튼의 고유한 이름 역할을 하는 선택자는? submitBtn
- 버튼의 또 다른 선택자는? submit-btn
- onclick=”submitForm()” : 버튼이 클릭되면 submitForm()이라는 함수를 실행시켜라. (<<API)
.
3.다양한 html 폼 요소
내용 보기
1)텍스트입력필드

<input type="text" id="studentName" placeholder="예: 홍길동">- <input type=”text”> : 텍스트 입력필드
2) 콤보박스(드롭다운)

<select id="dateSelect">
<option value="">-- 선택하세요 --</option>
<option value="9.15.(월)">9.15.(월)</option>
<option value="9.16.(화)">9.16.(화)</option>
<option value="9.17.(수)">9.17.(수)</option>
<option value="9.18.(목)">9.18.(목)</option>
<option value="9.19.(금)">9.19.(금)</option>
</select>- <select></select> : 콤보박스(드롭다운)의 시작과 끝
- <option value=”9.15.(월)”> 9.15.(월)을 선택하세요 </option>
: “9.15.(월)을 선택하세요” 옵션을 택하면 드롭다운의 값이 “9.15.(월)”이 되도록 하여라.
Q. 해당셀렉트에 9.20.(토) 항목을 추가해보세요
3)라디오버튼

<label><input type="radio" name="time" value="19:00-20:00"> 19:00-20:00</label>
- <input type=”radio”> : 라디오버튼 형식의 입력폼
.
4.style태그
내용 보기
style 태그는 무엇을(선택자) 어떻게(속성) 꾸밀지 정해주는 부분이다. CSS언어로 작성.
body { font-family: "맑은 고딕"; }- 의미 : body태그 즉 페이지 전체의 글꼴은 맑은 고딕으로 해주세요
- 선택자(무엇을) : body
- 속성(어떻게) : font-family:”맑은 고딕”
태그 선택자 스타일 지정
아래와 같이 <h2>태그로 작성된 태그의 스타일은 어떻게 지정할까?
<h2>아이좋아고등학교 3학년 1반 학부모 상담 예약</h2>다음과 같이 h2태그 전체에 대해 글꼴 등의 스타일을 지정할 수 있다.
h2, h3 { text-align: center; margin-bottom: 20px; }- h2, h3 { } : h2, h3 태그 전체에 대해 {} 속의 내용대로 스타일 지정
- text-align: center : 가운데정렬
- margin-bottom : 20px : 아래쪽 여백 폭을 20px로 지정
class선택자 활용 스타일 지정
하지만 모든 태그에 대해 일일이 스타일을 지정하는 것은 비효율적이다. 예컨대 아래 상담섹션 구역에서 1,2,3,4번 항목의 글자체, 글씨 색 등은 통일되어야 하므로 스타일을 한꺼번에 지정하는 것이 효율적이다. 이 때 필요한 것이 class 선택자다.
.form-group { margin-bottom: 15px; }- .form-group { } : class선택자가 form-group인 모든 요소의 스타일은 {}안의 내용으로 통일
Q. 오늘 완성한 코드에서 상담신청 섹션의 1,2,3,4번 항목의 글자 색을 모두 회색으로 바꿔 보세요. (속성명: color)
.
5.script태그
내용 보기
여기서부터 살~짝 어려워진다. script 태그 안에는 클라이언트와 서버 간의 상호작용에 관한 함수가 들어 있다. 자바스크립트 언어를 쓴다.
1)script태그 구조
<script>
//1.전송버튼 눌렀을 때의 기능 함수
function submitForm() {
}
//2. 서버의 데이터를 가져와 프론트엔드의 표 채우는 기능 함수
function loadReservationData(){
}
//3. 웹페이지가 처음 열렸을 때의 기능 함수
window.onload = function() {
}
</script>.
2) function submitForm() {}
const name = document.getElementById("studentName").value.trim();
const date = document.getElementById("dateSelect").value;
const time = document.querySelector("input[name='time']:checked")?.value || "";
const note = document.getElementById("note").value.trim();- const name = document.getElementById(“studentName”).value.trim();
: id선택자가 studentName인 녀석의 값을 가져와 name이라는 변수에 담아라
Q. 학생 이름이 “홍길동”이었으면 name의 값은?
A. 답 보기 : “홍길동”
아래 내용은 조금 많이 어려우므로 마음을 내려놓고 들어주세요. ^^
google.script.run
.withSuccessHandler(function(response) {
const btn = document.getElementById("submitBtn");
if (response === "success") {
btn.innerText = "전송 완료";
btn.disabled = true;
btn.style.backgroundColor = "#999";
alert("상담 예약이 완료되었습니다.");
loadReservationData(); // 저장 후 표 갱신
} else if (response === "duplicate") {
alert("이미 예약이 존재합니다. 다른 날짜 또는 시간을 택해주세요.");
} else {
alert("예약 중 오류가 발생했습니다. 다시 시도해주세요.");
}
})
.saveReservation(name, date, time, note);
}
- google.script.run : code.gs에 든 함수 즉 서버함수를 실행시켜라.
- .saveReservation(name, date, time, note) : name, date, time, note를 갖고 saveReservation 함수를 실행(호출)하라.
- withSuccessHandler (function (response) {..}) : 일이 성공적으로 끝나면 그 결과를 response라는 이름으로 돌려줘. 그럼 내가 {} 속의 일을 할게.
| 이 내용이 어려운 이유는 여기에 콜백함수라는 개념이 쓰였기 때문입니다. 코딩 중급자는 이해할 수 있습니다. 아래에 콜백함수에 대해 소개한 글이 있으니 시간되실 때 읽어보셔도 좋습니다. (클릭) 콜백함수 강의 보러 가기 (중급자 이상) |
3)window.onload
이 함수는 서버에서 클라이언트로의 통신 함수이다. 웹앱에 접속하면 서버에 있는 예약 현황이 웹앱의 표에 뜨게 하자.
window.onload = function() {
loadReservationData(); // 페이지 로드 시 예약 현황 표시
}- window.onload : 웹앱의 모든 요소(이미지, 글자 등)가 완전히 로딩되었을 때
- loadReservation() : loadReservation()함수를 실행(호출)하라. (예약현황 보여주는 함수)
.
>> code.gs 코드 톺아보기 바로가기
댓글 남기기