Skip to content

Instantly share code, notes, and snippets.

@sokcuri
Created July 12, 2017 12:03
Show Gist options
  • Save sokcuri/7e8e224647478d78b0076f027b6a6f3f to your computer and use it in GitHub Desktop.
Save sokcuri/7e8e224647478d78b0076f027b6a6f3f to your computer and use it in GitHub Desktop.
// HTML과 CSS를 수정하지 않고 기능추가.
// * 코드를 더 개선해 볼 것 *
// √ 1. Switch, if 등 조건에 해당하는 것을 최대한 줄일 것
// √ 2. event delegation을 잘 써서 for문으로 돌렸던 addEventListener를 삭제
// √ 3. AJAX 재요청 없게끔 만들기
// DOMContentLoaded가 호출되면 하는 일
// 1) 이벤트를 등록한다
// - 'nav' 태그에 'click' 이벤트를 등록한다
// 2) 첫번째 탭의 내용을 서버에서 불러온다
// 3) CSS를 삽입한다
// pointer-events: none; 을 넣은 이유는 클릭했을 때 tab 하위의 element가 클릭되는걸 막기 위함
document.addEventListener('DOMContentLoaded', function () {
registerEvents();
loadContents();
insertCSS('.tab * { pointer-events: none; }');
});
// CSS를 인라인으로 삽입해주는 함수
function insertCSS(css) {
if (!checkParam(arguments, 1))
return false;
var styleElem = document.createElement('style');
styleElem.type = 'text/css';
(styleElem.styleSheet) ?
styleElem.styleSheet.cssText = css :
styleElem.appendChild(document.createTextNode(css));
document.getElementsByTagName('head')[0].appendChild(styleElem);
}
function registerEvents() {
setHandlerTab();
}
function loadContents() {
let el = document.querySelectorAll('nav > *')[0];
setContent(el, el.id);
}
function setHandlerTab() {
const nav = getNav();
nav.addEventListener('click', tabClickDelegate);
}
function tabClickDelegate(evt) {
// evt.target이 nav면 클릭한게 아니라 드래그한 경우
if (evt.target == this) return;
// 클릭한 탭에 색이 들어가고 탭에 해당하는 섹션이 보이도록 조정
let tabElement = evt.target;
let sectionElement = document.querySelector(`#my_${evt.target.id}`);
visibleTab(tabElement);
visibleSection(sectionElement);
// 탭에 컨텐츠를 채워넣는다
setContent(tabElement);
}
function visibleTab(el) {
return visibleControl(el, 'selectedTab');
}
function visibleSection(el) {
return visibleControl(el, 'eleDisplayShow');
}
function visibleControl(el, name) {
if (!checkParam(arguments, 2))
return false;
el.parentNode.getElementsByClassName(name)[0].classList.remove(name);
el.classList.add(name);
}
// nav 태그 element를 가져온다
function getNav() {
return document.querySelector('nav');
}
// nav element 안의 tab 이름을 가진 div들을 가져온다
function getNavTabs() {
return Array.from(document.querySelectorAll('nav > div.tab'));
}
function getJsonURL(number = 1) {
return `http://jsonplaceholder.typicode.com/posts/${number}`;
}
function getTabNumber(tabElement) {
const navTabs = getNavTabs();
for (let i = 0; i < navTabs.length; i++) {
if (navTabs[i] == tabElement)
return i + 1;
}
}
// 탭을 클릭했을 때 이 함수가 호출됨.
// 서버에서 한번도 가져온 적이 없을 때 JSON을 가져오기
function setContent(el) {
let id = el.id;
let number = getTabNumber(el);
if (!el.classList.contains('receivedData')) {
console.log(`[get] number: ${number}, id: ${id}`);
el.classList.add('receivedData');
// () => 화살표 함수를 쓰면 this를 못가져온다
reqContents(getJsonURL(number), function() {
return updateSection(`#my_${id}`, JSON.parse(this.responseText));
});
}
}
// 컨텐츠를 요청. XHR
function reqContents(url, callback) {
if (!checkParam(arguments, 2))
return false;
let oReq = new XMLHttpRequest();
oReq.addEventListener('load', callback);
oReq.open('GET', url);
oReq.send();
}
// 섹션을 업데이트
function updateSection(el_id, obj) {
if (!checkParam(arguments, 2))
return false;
let template = "<ul > <li > <div class='myName' ><%=title%></div> <div class='myDesc' ><%=body%></div> </li> </ul>";
let result = _.template(template)({title: obj.title, body: obj.body});
document.querySelector(el_id).innerHTML = result;
}
// 파라메터가 유효한지 확인한다
function checkParam(func_arg, len) {
let numbers = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'];
if (func_arg.length < len) {
console.error(`${func_arg.callee.name} must requires ${numbers[len]} parameter${(len > 1) ? 's.' : '.'}`);
return false;
}
return true;
}
header,nav,section,div,footer,ul,dd {margin:0;padding:0;}
li{list-style: none;}
dt {
font-weight: bold;
font-size: 1.2em;
margin-bottom: 5px;
}
dl {
float: left;
width : 75%;
}
dd {
font-size: 0.9em;
}
.mainHeader{
height:200px;
text-align: center;
padding-top: 20px;
line-height: 1.4em
}
.userId {
font-size: 1.2em;
font-weight: bold;
}
.userMessage, .userSNSInfo {
font-size: 0.8em;
color : gray;
}
.userSNSInfo {
overflow: auto;
width: 255px;
margin: 0px auto;
}
.userSNSInfo > li {
float: left;
margin-right: 5px;
width : 80px;
}
.userSNSInfo span.count {
color : #1FB820;
}
.mainView > nav {
height:40px;
margin-top: 10px;
overflow: auto;
border-bottom: 1px solid rgb(228, 228, 228);
border-top: 1px solid rgb(228, 228, 228);
}
.tab {
border-right: 1px solid rgb(228, 228, 228);
float:left;
height:100%;
line-height: 40px;
text-align: center;
width:24.5%;
cursor: pointer;
}
.tab:last-child {
border-right: 0px;
}
.mainView > section {
display:none;
padding:8%;
line-height: 1.5em;
}
.mainView > section.eleDisplayShow {
display:block;
padding:8%;
line-height: 1.5em;
}
.myName {
font-size: 1.2em;
font-weight: bold;
}
.myDesc {
font-size: 0.8em;
}
.eleDisplayShow li {
margin-bottom: 8%;
}
.selectedTab {
background-color: #DF9274;
color: #fff;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>tabUI</title>
<link rel="stylesheet" href="tabUI.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src=./script.js></script>
</head>
<body>
<div id="wrapper">
<div class="mainView" >
<header class="mainHeader" ><img src="https://avatars1.githubusercontent.com/u/1456761?v=3&s=140" width="80" >
<div class="userId" ><span > </span><span >nigayo</span><span > </span>
</div>
<div class="userMessage" ><span > </span><span >안녕하세요 nigayo입니다.</span><span > </span>
</div>
<ul class="userSNSInfo" >
<li ><span >review : </span><span class="count" >10</span><span > | </span>
</li>
<li ><span >follower : </span><span class="count" ><span >12</span><span > </span></span><span > | </span>
</li>
<li ><span >following : </span><span class="count" ><span >30</span><span > </span></span><span > </span>
</li>
</ul>
</header>
<nav >
<div class="tab selectedTab" id="position" ><span > </span><span >aboutMe</span><span > </span>
</div>
<div class="tab" id="friend" ><span > </span><span >friend</span><span > </span>
</div>
<div class="tab" id="theme" ><span > </span><span >lorem</span><span > </span>
</div>
<div class="tab" id="news" ><span > </span><span >repository</span><span > </span>
</div>
</nav>
<section id="my_position" class="eleDisplayShow" >
<ul >
<li >
<div class="myName" >blah blah !</div>
<div class="myDesc" >Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eaque recusandae hic obcaecati maxime officiis commodi! Cumque maiores maxime quam quidem deleniti, aspernatur iste, minima sit laboriosam laudantium saepe dignissimos provident.</div>
</li>
</ul>
</section>
<section id="my_friend"> </section>
<section id="my_theme" > </section>
<section id="my_news"> </section>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment