이번 주에는 아주 기주본적인 HTML 과 CSS 문법에 대해 배우고, Twittler 목업 페이지를 구현하였습니다. HTML과 CSS만으로는 어떠한 동적 기능도 들어있지 않은 속이 빈 껍데기같은 상태였지만, 자바스크립트 DOM 기본지식을 습득하고 나서는 마법같은 일들을 해낼 수 있었어요 ㅎㅎ
첫 껍데기를 만들어보면서 느꼈습니다. html, css를 다루는데는 코딩 경험의 양이 절대적으로 중요하다는 걸요. 쉽사리 손이 떨어지지 않았고 정말 여러번의 삽질을 반복하였습니다. 오히려 알고리즘 문제를 푸는 것이 더 쉬웠던 것 같습니다ㅠ
Box-Model에 대해서는 어느정도 빠르게 이해할 수 있었지만, 제일 이해하는데 애먹었던 건 css position의 개념이었습니다. relative와 absolute에 대해 코드스테이츠가 제공해준 컨텐츠만으로 이해가 어려워 국내 해외 유튜브 컨텐츠를 보면서 기본 개념을 잡았습니다.
CSS Box Model ::
Padding과 Margin 값을 조절하면서 컨텐츠가 점유하고 있는 공간과, 다른 컨텐츠와의 상대적인 간격을 변화시킬 수 있습니다
relative 상태에서는 원래 있어야 할 위치를 기준으로 움직이며, absolute 상태에서는 부모 컨텐츠의 위치를 기준으로 움직입니다. relative와 absolute를 적절히 섞어 사용함으로써 div 안에 있는 다른 div를 원하는 위치에 포지셔닝 할 수 있습니다.
몇시간의 씨름 끝에 예쁘진 않지만 저만의 사랑스러운 껍데기를 완성할 수 있었습니다.
열심히 만들었지만 껍데기는 껍데기일 뿐입니다. 저 상태로는 Tweet버튼을 누르거나, check new tweet 버튼을 아무리 눌러도 웹페이지에 변화가 생기지 않습니다. html, css만을 이용한 페이지 구현이 끝나기 무섭게, 코드스테이츠는 이를 해결하기 위한 다른 키워드를 알려줍니다. 바로 DOM입니다.
DOM은 Document Object Model의 약자로, HTML(Document)에 접근하여 Object(JavaScript Object)처럼 HTML을 조작(Manipulation)할 수 있는 Model이라는 의미를 가지고 있습니다. 즉, 자바스크립트를 사용하는 방법을 알고 있으면 DOM을 활용하여 HTML을 조작할 수 있다는 의미입니다.
DOM을 이용해 저 껍데기에 생명력을 넣어주기 위해 자바스크립트 Document 객체에 접근하여, HTML 태그를 Create, Read, Update, Delete 하는 법을 배웠습니다. 네, 바로 그 말로만 듣던 CRUD를 여기서 만나게 됐네요 😆
//CRUD의 초간단 예시입니다
//Create : div태그 만들기
const tweetDiv = document.createElement('div');
//Read : class가 tweet인 html요소에 접근하기
const oneTweet = document.querySelector('.tweet');
//Update : 접근한 요소의 class 추가하기
oneTweet.classList.add('tweet');
//Delete : 접근한 요소 제거하기
tweetDiv.remove();
기본적인 DOM 활용법과 이벤트 객체에 대해서 배우고, HTML내에 자바스크립트 파일을 불러오는 시점에 따른 작동의 차이를 배웠습니다. 이제 이전에 만들었던 껍데기 상태에서 해결해야 할 과제는 총 4가지 였습니다
// 주어진 데이터
var DATA = [
{ user: 'ingikim', message: 'Welcome to Code States #codestates', created_at: '2019-01-03 12:30:20' },
{ user: 'satya', message: 'this is test message #pair #programming', created_at: '2019-01-04 18:30:20' },
{ user: 'sundar', message: 'code now! #work #hard', created_at: '2019-01-05 07:30:20' },
{ user: 'steve', message: 'Stay hungry, and stay foolish', created_at: '2015-01-03 12:30:20' },
{ user: 'tim', message: 'education for real world', created_at: '2019-01-04 18:30:20' }
];
function renderDATA() {
//생성된 li를 집어넣을 div 태그에 접근한다
let comments = document.querySelector('#low');
for (i = 0; i < DATA.length; i++) {
//li.comments 만들기
let createLi = document.createElement('li');
createLi.classList.add('comments');
//span.name -> 이름을 li의 자식태그로 넣는다
let createName = document.createElement('span');
createName.textContent = DATA[i].user
createName.classList.add('name')
createLi.appendChild(createName);
//span.dateTime -> 날짜를 li의 자식태그로 넣는다
let createdAt = document.createElement('span');
createdAt.textContent = DATA[i].created_at;
createdAt.classList.add('dateTime');
createLi.appendChild(createdAt);
//p.comment -> 코멘트를 li의 자식태그로 넣는다
let createMsg = document.createElement('p');
createMsg.textContent = DATA[i].message;
createMsg.classList.add('comment');
createLi.appendChild(createMsg);
//li 출력하기
comments.appendChild(createLi);
}
}
//
renderDATA();
아까와 동일한 페이지이지만, 하드코딩의 결과가 아닌 자바스크립트 함수 실행을 통한 구현이라는 점에서 아주 큰 차이가 생겼습니다. 이제, 데이터베이스에 100개의 코멘트가 있다면, 100개의 코멘트가 반복문을 돌면서 자동으로 생성됩니다.
// 랜덤한 유저와 코멘트 데이터들을 가져오는 함수는 generateNewTweet
// 이라는 이름으로 사전에 구현되어 있었습니다.
checkBtn.onclick = function () { // Check new Tweet 버튼을 누르면
removeTweet(); //1. 먼저 모든 트윗을 지우웁니다
DATA.unshift(generateNewTweet()); //2. 데이터 객체에 랜덤으로 생성된 데이터를 추가시키고,
renderDATA(); //3. 다시 renderDATA 함수 실행을 통해 데이터들을 출력합니다.
}
이제 check new tweet 버튼을 2번 누르면, 상단에 2개의 랜덤 코멘트가 생성됩니다.
2번과 마찬가지로 먼저 모든 트윗을 지운 뒤, obj라는 객체를 생성하여 새 데이터를 만들고 기존 DATA 객체에 추가한 뒤 renderDATA함수를 실행하여 출력하는 로직으로 구성되어 있습니다. 이름과 코멘트를 적지 않으면 alert을 띄우는 간단한 기능도 추가했습니다.
// tweet! 버튼을 누르면 입력한 대로 새로운 트윗을 생성합니다
tweetBtn.onclick = function () {
let username = document.querySelector('#nameInput');
let comment = document.querySelector('#commentInput');
if (username.value === '') {
alert('이름을 입력하세요');
} else if (comment.value === '') {
alert('코멘트를 적어주세요');
} else {
removeTweet();
let obj = {};
obj.user = username.value;
obj.message = comment.value;
obj.created_at = Date.prototype.format();
DATA.unshift(obj);
renderDATA();
}
}
가장 구현하는데 애를 먹었던 기능입니다. 모든 span.name 요소를 클릭할 때 함수를 실행시키기 위해서 for 문을 써야했고, onclick 이벤트 발생 시 해당 이벤트 객체에 접근하여 span.name의 text를 가져오는 법을 배워야 했습니다.
//먼저 filtering이라는 이름으로, 데이터베이스에서 클릭 한 요소와 username이
//일치하는 데이터들을 출력하는 기능을 만들었습니다.
function filtering() {
for (i=0; i<DATA.length; i++) {
if (DATA[i].user === event.target.textContent) {
//li.comments 만들기
let createLi = document.createElement('li');
createLi.classList.add('comments');
//span.name 만들기
let createName = document.createElement('span');
createName.textContent = DATA[i].user
createName.classList.add('name')
createLi.appendChild(createName);
//span.dateTime 만들기
let createdAt = document.createElement('span');
createdAt.textContent = DATA[i].created_at;
createdAt.classList.add('dateTime');
createLi.appendChild(createdAt);
//p.comment 만들기
let createMsg = document.createElement('p');
createMsg.textContent = DATA[i].message;
createMsg.classList.add('comment');
createLi.appendChild(createMsg);
//li 출력하기
comments.appendChild(createLi);
}
}
// 그 다음, id가 name인 모든 태그를 array로 가져와 targetName이라는 변수에
// 저장하고, 반복문으로 onclick 이벤트를 만들었습니다.
// 처음엔 Global Scope에서 코드 작성 후 실행하였으나 작동이 되지 않아서
// renderDATA 함수 내에 삽입하였더니 원활하게 작동하는 것을 확인하였습니다.
let targetName = document.querySelectorAll('.name');
for (i=0; i<targetName.length; i++) {
targetName[i].onclick = function() {
removeTweet();
filtering();
makeBackBtn();
checkBtn.remove();
}
//추가적으로 작성자 이름 클릭 시 check new tweet 버튼을 back 버튼으로
//바꿔줘서, 원래 상태로 돌아갈 수 있도록 하는 기능도 만들었습니다.
function makeBackBtn() {
let div = document.querySelector('#checkBtnDiv')
let backBtn = document.createElement('button');
backBtn.textContent = 'Back';
backBtn.classList.add('lowBtn');
backBtn.id = 'backBtn'
div.appendChild(backBtn)
backBtn.onclick = function(){
removeTweet();
renderDATA();
backBtn.remove();
div.append(checkBtn)
}
}
이제 작성자 이름을 클릭하면, 같은 작성자의 모든 코멘트들을 타임라인으로 보여주는 기능이 완성되었습니다. 작성자이름 Steve를 클릭하면 Steve가 작성한 코멘트만 필터링하여 보여줍니다.
back 버튼을 누르면, 다시 원래 상태로 돌아옵니다
여태까지 배운 지식들을 총동원해서, 처음으로 하나의 웹페이지를 구현해 보았습니다. 만들고보니 왠지 윈도우 98을 사용하던 초등학교 시절이 생각나는 디자인이네요😢 html과 css를 너무 짧게 배우고 바로 만들기 시작해서.. 뭐랄까 현대적인 디자인으로 만들지 못했던 점이 아쉽습니다.
아쉬운 건 아쉽지만, 한편으로는 굉장히 뿌듯합니다. 이 조그만 페이지를 만들기 위해 거의 하루를 갈아넣었고, 여기엔 꽤나 많은 기능들이 들어가 있습니다. 중간중간 막히는 부분이 한두개가 아니었지만, 그때그때 구글링과 헬프데스크에 올라온 질문들을 통해 해결해 나갔고 어쨌든 저의 손으로 마무리 지었습니다.
이 조그만 페이지 하나 만들고 혼자 좋아하는건 좀 부끄러운 일이지만, 솔직히 애정이 갑니다 ㅋㅋㅋ
곧 다가올 추석 연휴동안에는 css의 grid, flex 기능을 학습해볼 생각입니다. 코드스테이츠 과정에는 없지만 현재로써 css를 이용해 보기좋은 레이아웃을 만들기가 많이 버겁다고 느껴져서, 나중을 위해서는 css의 다양한 기능들을 조금더 배워두는게 좋을 것 같다고 생각했습니다.
다음주도 항상 긍정적인 생각하면서 화이팅 해보겠습니다
빠샤🔥