힘들었던 carousel
구현을 끝내고 나서,
뭔가 점차 고민을 하다 보니, 좀 더 구현에 있어 자신감이 생긴 듯합니다. 👏
지금 다룰 채용 리스트 컴포넌트 역시, 집중 빡!하고 끝내서 기분이 좋네요. 😘
그렇게 어려운 건 없었지만 이 프로그래머스 페이지 자체가 breakpoint
가 4개인지라... 시간은 좀 걸리지만, 그래도 좋은 경험을 하는 거서 같아 기분이 좋습니다.
그럼 시작합니다!!
제가 클론할 job
은 말이죠, 다음과 같이 구성되어 있어요.
데스크탑에서는(992px~) 다음과 같이 렌더링되는데요,
991px 부터는 이제 한 줄당 하나씩 나오게 됩니다.
그리고 575~766px
에서는 그냥 글자만 작아지는데요,
모바일(574px
)에서는 로고가 보이지 않게 됩니다.
저는 다음과 같이 구성했습니다!
먼저 이 역시 독립적으로 구성될 수 있는 콘텐츠라 생각해서 article
로 시멘틱하게 해줬어요.
또한 이 콘텐츠가 어떤 페이지인지 알려주는 헤더는 header
로 마크업 했습니다.
이후 skill들과 카드들은 ul
태그로 썼고, 나머지 상세 하위 요소들은 li
태그로 감싸주었어요.
<article class="job">
<header class="job__header">
<h2 class="job__title">채용 중인 포지션</h2>
<button class="job__more-btn">포지션 더보기</button>
</header>
<!--
<ul class="job__skills">
<li class="job__skill">Java</li>
<li class="job__skill">Spring</li>
<li class="job__skill">Node.js</li>
<li class="job__skill">Django</li>
<li class="job__skill">ReactJS</li>
<li class="job__skill">Vue.js</li>
<li class="job__skill">JavaScript</li>
<li class="job__skill">Python</li>
<li class="job__skill">Kotlin</li>
<li class="job__skill">C++</li>
<li class="job__skill">Android</li>
<li class="job__skill">IOS</li>
<li class="job__skill">서버/백엔드</li>
<li class="job__skill">프론트엔드</li>
<li class="job__skill">웹 풀스택</li>
<li class="job__skill">안드로이드 앱</li>
<li class="job__skill">아이폰 앱</li>
</ul>
<ul class="job__cards">
<li class="job__card">
<div class="job__logo-box">
<img src="https://grepp-programmers.s3.amazonaws.com/production/company/logo/1718/20160804_%EB%A1%9C%EA%B3%A0%EC%84%B8%EB%A1%9C%ED%98%95.png" alt="채용회사 로고 이미지" class="job__card-logo">
</div>
<section class="job__card-info">
<h4 class="job__card-title">웹 서비스 개발자</h4>
<h4 class="job__card-brand">오니온파이브</h4>
<ul class="job__requirements">
<li class="job__requirement">웹 풀스택</li>
<li class="job__requirement">Django Channels</li>
<li class="job__requirement">Celery</li>
<li class="job__requirement">Django</li>
<li class="job__requirement">Redis</li>
<li class="job__requirement">MariaDB</li>
</ul>
</section>
</li>
<li class="job__card">
<div class="job__logo-box">
<img src="https://grepp-programmers.s3.amazonaws.com/production/company/logo/1718/20160804_%EB%A1%9C%EA%B3%A0%EC%84%B8%EB%A1%9C%ED%98%95.png" alt="채용회사 로고 이미지" class="job__card-logo">
</div>
<section class="job__card-info">
<h4 class="job__card-title">웹 서비스 개발자</h4>
<h4 class="job__card-brand">오니온파이브</h4>
<ul class="job__requirements">
<li class="job__requirement">웹 풀스택</li>
<li class="job__requirement">Django Channels</li>
<li class="job__requirement">Celery</li>
<li class="job__requirement">Django</li>
<li class="job__requirement">Redis</li>
<li class="job__requirement">MariaDB</li>
</ul>
</section>
</li>
</ul> -->
</article>
이번에는 뭔가 IIFE
를 써보고 싶었어요!
써본 결과, 뭔가 개인적으로는 좀 더 이게 편하고, 직관적이라는 생각이 들었습니다.
바로 실행한다는 의미가 있어서일까요? 여기서 쓰면 바로 돌아가겠다는 느낌이 들어서, 위치를 고민할 필요가 없어서 좋았습니다.
(실제로는 정반대일 수도 있고, 이렇게 쓰이지는 않을 수 있겠지만요.)
또, 커스텀을 해봤는데요, 여러 개를 계속 똑같이 createElement
와 appendChild
하기 귀찮아서 rest
연산자 등등을 활용하면서 구현해봤어요!
기존 함수들과 헷갈리지 않게 custom
을 변수명 맨 앞에 붙여줬습니다.
interface jobDataFormat {
name: string;
url: string;
image: string;
jobName: string;
requirements: Array<string>;
}
interface Names {
[name: string]: string;
}
interface SkillDatasFormat {
0: {
skills: Array<string>;
};
};
export default class Job {
private readonly names: Names;
constructor(private readonly jobDatas: Array<jobDataFormat>, private readonly SkillDatas: SkillDatasFormat) {
this.names = {
jobHeader: 'job__header',
jobTitle: 'job__title',
jobMoreBtn: 'job__more-btn',
jobSkills: 'job__skills',
jobSkill: 'job__skill',
jobCards: 'job__cards',
jobCard: 'job__card',
jobLogoBox: 'job__logo-box',
jobCardLogo: 'job__card-logo',
jobCardInfo: 'job__card-info',
jobCardTitle: 'job__card-title',
jobCardBrand: 'job__card-brand',
jobRequirements: 'job__requirements',
jobRequirement: 'job__requirement'
}
this.render();
}
customCreateElement(tag: string, name: string): HTMLElement {
const elem = document.createElement(tag);
elem.className = name;
return elem;
};
customAppendChild(parent: HTMLElement, ...elems: Array<HTMLElement>) {
[...elems].map(elem => parent.appendChild(elem));
};
render() {
const renderSkillsComponent = (() => {
const $jobSkills = this.customCreateElement('ul', this.names.jobSkills);
const datas = this.SkillDatas[0].skills;
datas.map(data => {
const $jobSkill = this.customCreateElement('li', this.names.jobSkill);
$jobSkill.textContent = data;
$jobSkills.appendChild($jobSkill)
});
document.querySelector('.job').appendChild($jobSkills);
})();
const renderCardsComponent = (() => {
const $jobCards = this.customCreateElement('ul',this.names.jobCards);
this.jobDatas.map((jobData: jobDataFormat) => {
const $jobCard = this.customCreateElement('li',this.names.jobCard);
const $jobLogoBox = this.customCreateElement('div',this.names.jobLogoBox);
const $jobCardLogo = this.customCreateElement('img', this.names.jobCardLogo);
$jobCardLogo.setAttribute('src', jobData.image);
$jobCardLogo.setAttribute('alt', "채용회사 로고 이미지");
// job__logo-box 생성
$jobLogoBox.appendChild($jobCardLogo);
const $jobCardInfo = this.customCreateElement('section', this.names.jobCardInfo);
const $jobCardTitle = this.customCreateElement('h4', this.names.jobCardTitle);
$jobCardTitle.textContent = jobData.jobName;
const $jobCardBrand = this.customCreateElement('h4', this.names.jobCardBrand);
$jobCardBrand.textContent = jobData.name;
const $jobRequirements = this.customCreateElement('ul', this.names.jobRequirements);
jobData.requirements.map((requirement: string) => {
const $jobRequirement = this.customCreateElement('li', this.names.jobRequirement);
$jobRequirement.textContent = requirement;
$jobRequirements.appendChild($jobRequirement);
})
// job__card-info 생성
this.customAppendChild($jobCardInfo, $jobCardTitle, $jobCardBrand, $jobRequirements);
// 결과적으로 job__card 생성
this.customAppendChild($jobCard, $jobLogoBox, $jobCardInfo)
// job__card를 job__cards 안에 넣음
$jobCards.appendChild($jobCard);
})
document.querySelector('.job').appendChild($jobCards)
})();
}
}
아주 어썸하게 잘 나왔네요! 🌈🎉
원래는 리액트로 하다가, 자바스크립트로 하니 뭔가 좀 생산성에 있어 불편한 점은 있지만,
아, 원래 이렇게 자바스크립트로 작업했었구나. 그래서 리액트, 뷰같은 라이브러리 및 프레임워크가 생산성 측면에서 이점이 있구나를 느낍니다.
클론 프로젝트 정말 매력 있는 것 같아요. 앞으로도 자주 해야겠습니다!!
💬
아직 많이 부족하기 때문에 잘못된 생각이 많을 수 있습니다. 틀린 부분이 있다면 날카로운 비판 매우 환영합니다!! 읽어주셔서 감사합니다 🎉