ํค๋ณด๋์์ ์ ๋ ฅ์ ๋ฐ์ง ์๊ณ ์ง์ ํคํจ๋๋ฅผ ํด๋ฆญํ์ฌ ๋น๋ฐ๋ฒํธ๋ฅผ ์ฒดํฌํ๋ ๊ธฐ๋ฅ์ ๋ง๋ค์ด๋ณด์์ต๋๋ค.
์ฐธ๊ณ ๋ก ๋จ์ํ ์น๋จ์์ ์ ํด์ง ๊ฐ์ ์ ๋ ฅ๊ฐ๊ณผ ๋น๊ตํ๋ ๋ก์ง๋ง ์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ OOP๊ธฐ๋ฐ์ผ๋ก ์์ฑํ์์ต๋๋ค.
1. ๋งํฌ์ ์คํ์ผ
<div class="pwWrap">
<div class="pwSection">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
<p class="message"> </p>
</div>
<div class="numberSection">
<button class="number">1</button>
<button class="number">2</button>
<button class="number">3</button>
<button class="number">4</button>
<button class="number">5</button>
<button class="number">6</button>
<button class="number">7</button>
<button class="number">8</button>
<button class="number">9</button>
<button class="number">0</button>
</div>
</div>
1-1. SCSS์ฌ์ฉ์
$errorColor: red;
$confirmColor: green;
.pwWrap {
width: 80%;
max-width: 450px;
background: lightGrey;
margin: 20px auto;
.pwSection {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 150px;
.dot {
display: block;
width: 10px;
height: 10px;
background: darkgrey;
border-radius: 100%;
margin: 0 5px;
&.active {
background: rgba(0,0,0,0.7);
}
}
.message {
position: absolute;
bottom: 5px;
left: 0;
z-index: 1;
min-width: 100%;
text-align: center;
font-size: 14px;
font-weight: bold;
letter-spacing: -0.03em;
opacity: 0;
transition: .2s ease-out;
}
}
.numberSection {
overflow: hidden;
.number {
float: left;
width: 33.33%;
border: 1px solid rgba(0,0,0,0.1);
padding: 12px 0;
cursor: pointer;
background: #F8F2F2;
&:last-child {
margin-left: 33.33%;
}
}
}
&.error {
.message {
opacity: 1;
color: $errorColor;
}
}
&.confirm {
.message {
opacity: 1;
color: $confirmColor;
}
}
}
1-2. CSS ์ฌ์ฉ ์
.pwWrap {
width: 80%;
max-width: 450px;
background: lightGrey;
margin: 20px auto;
}
.pwWrap .pwSection {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 150px;
}
.pwWrap .pwSection .dot {
display: block;
width: 10px;
height: 10px;
background: darkgrey;
border-radius: 100%;
margin: 0 5px;
}
.pwWrap .pwSection .dot.active {
background: rgba(0, 0, 0, 0.7);
}
.pwWrap .pwSection .message {
position: absolute;
bottom: 5px;
left: 0;
z-index: 1;
min-width: 100%;
text-align: center;
font-size: 14px;
font-weight: bold;
letter-spacing: -0.03em;
opacity: 0;
transition: .2s ease-out;
}
.pwWrap .numberSection {
overflow: hidden;
}
.pwWrap .numberSection .number {
float: left;
width: 33.33%;
border: 1px solid rgba(0, 0, 0, 0.1);
padding: 12px 0;
cursor: pointer;
background: #F8F2F2;
}
.pwWrap .numberSection .number:last-child {
margin-left: 33.33%;
}
.pwWrap.error .message {
opacity: 1;
color: red;
}
.pwWrap.confirm .message {
opacity: 1;
color: green;
}
2. ์คํฌ๋ฆฝํธ ์์ฑํ๊ธฐ
์ ๋ ์ด๋ ๊ฒ ๋ง๋ค์ด๋ณด์์ต๋๋ค.
1. ์ซ์ ๋ฒํผ ํด๋ฆญ, ํด๋ฆญ๋ ์ซ์๋ฅผ ๋ฐฐ์ด์ ๋ด๊ธฐ
2. ๋ฒํผ ํด๋ฆญ ํ์ ์ฒดํฌ
3. ๋ฒํผ ํด๋ฆญ ํ์๊ฐ 4์ผ ๋ ๋์ด์จ ๋น๋ฐ๋ฒํธ์ ์ ๋ ฅํ ๊ฐ ๋น๊ต
4. 3๋ฒ ๋น๊ต๊ฐ ํ๋ฆฌ๋ฉด ๋ฆฌ์ ๋ฐ ์๋ฌ ๋ฉ์์ง ์ถ๋ ฅ
5. 3๋ฒ ๋น๊ต๊ฐ ๋ง์ผ๋ฉด ์ฑ๊ณต ๋ฉ์ธ์ง ์ถ๋ ฅ
pwCheck๋ผ๋ ํจ์๋ฅผ ์์ฑํ ๋ค, ๋ด๋ถ์ ํ์ํ ๋ณ์๋ฅผ ์ง์ ํฉ๋๋ค.
ํ์ํ ๊ฐ์ฒด๋ค๋ ๋ถ๋ฌ์ต๋๋ค.
function PwCheck(pw) {
const _this = this;
_this.pwStr = pw.toString(); // ๋ฌธ์, ์ซ์์ด์ ๋ชจ๋ ํ์ฉํ๊ธฐ ์ํด ๋ฌด์กฐ๊ฑด ํ๊ฐ์ง ํ์
์ผ๋ก ๋ง์ถค
_this.password = []; // ์ง์ ๋ ํจ์ค์๋
_this.passwordNumber = []; // ์
๋ ฅํ ํจ์ค์๋
_this.cnt = 0; // ์
๋ ฅํ์ ์ฒดํฌ
_this.compChk = false; // ์
๋ ฅ์๋ฃ ์ฒดํฌ
_this.msg = [
'Wrong Password! Try Again! ๐ฟ',
'Success! ๐'
];
_this.parent = document.querySelector('.pwWrap');
_this.dots = document.querySelectorAll('.dot');
_this.numbers = document.querySelectorAll('.number');
_this.message = document.querySelector('.message');
}
์ฌ๊ธฐ์ this๋ pwCheckํจ์๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ, this๋ฅผ _this์์ ๋ด์๊ธฐ ๋๋ฌธ์,
์์์ ์ ์ธํ ๋ณ์์ ํจ์๋ค์ ์ธ๋ถ์์ ๋ฐ๋ก ์ ๊ทผ์ด ๋์ง ์์ต๋๋ค.
PwCheck์์ ๋๊ฒจ๋ฐ๋ pw๋ฅผ ์ค์ ๋น๋ฐ๋ฒํธ๋ผ๊ณ ๊ฐ์ ํฉ๋๋ค.
pw๋ฅผ ๊ตณ์ด string์ผ๋ก ๋ฐ๋ ์ด์ ๋ ๋์ด์ค๋ pw๊ฐ ์ซ์์ธ ๊ฒฝ์ฐ ๋ฐฐ์ด์ ๋ฃ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ฐ๋์ ๋ฐฐ ์ด๋ ๋ฐฐ์ด๋ก ๋น๊ตํ ํ์๋ ์์ง๋ง ์ ๋ ์ ๋ ฅ๋ฐ์ ๊ฐ์ ํ๋์ฉ ๋ฐฐ์ด์ ๋ด๊ธฐ ๋๋ฌธ์ ๋ฐฐ์ด๋ผ๋ฆฌ ๋น๊ต๋ฅผ ํ๊ณ ์ ํฉ๋๋ค.
๋จผ์ ๋ฐ์ pw๊ฐ์ ๋ฐ์๋ง์ ๋ฐฐ์ดํ ํฉ๋๋ค.
// ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐฐ์ด์ ๋ฃ์
_this.getPw = function(){
for(let i=0; i<_this.pwStr.length; i++) {
_this.password[i] = _this.pwStr[i];
}
}
์ด๋ ๊ฒ ์ ์ธํ ๋ค ์ฆ์ ์คํ์์ผ์ฃผ๊ธฐ ์ํด initํจ์๋ฅผ ํ๋ ๋ ๋ง๋ค ๊ฒ๋๋ค.
init๋ด๋ถ ํจ์๋ค์ ๋ชจ๋ ์ฆ์ ํธ์ถ๋ฉ๋๋ค.
_this.init = function(){
_this.getPw();
}();
๊ทธ๋ฆฌ๊ณ ์ฆ์ ์คํ๋์ด์ผ ํ ํจ์๊ฐ ํ๋ ๋ ์์ต๋๋ค.
๋ฒํผ ํด๋ฆญ ์ด๋ฒคํธ์ ๋๋ค.
{...}
// ์ซ์๋ฒํผ click์ด๋ฒคํธ ์ฐ๋
_this.handleListener = function(){
if(!_this.compChk) {
_this.numbers.forEach(function(number){
number.addEventListener('click', function(){console.log("number")});
})
}
}
_this.init = function(){
_this.handleListener();
_this.getPw();
}();
์ด๋ ๊ฒ ํ๋ฉด ๊ฐ๊ฐ ํด๋ฆญํ ๋ฒํผ์ ์ ๋๋ก ๊ฐ์ง๊ณ ์ต๋๋ค.
์ด๋ ์๋๋ id๋ฅผ ๋๊ฑฐ๋ ๋ฐ๋ก attribute๋ฅผ ๋ฐ๋ก ์ค์ ํ์ฌ value๊ฐ์ ์ง์ ํ์ง๋ง, ์ ๋ ๊ทธ๋ฅ textContent๋ก ๊ฐ์ ธ์์ต๋๋ค.
handleNumber๋ผ๋ ํจ์๋ฅผ ๋ฐ๋ก ๋๊ณ ์ฌ๊ธฐ์ ํด๋ฆญํ ์ซ์๋ฅผ ๋๊ธธ ๊ฒ๋๋ค.
ํด๋ฆญํ ๋๋ง๋ค passwordNumber ๋ฐฐ์ด์ ํ๋์ฉ ๋ฃ์ด์ฃผ๊ณ ์นด์ดํธ๋ฅผ ์ฆ๊ฐ์์ผ์ค๋๋ค.
๋ง์ฝ ์นด์ดํธ๊ฐ 4๊ฐ ๋๋ค๋ฉด, handleResultํจ์๋ก ๋๊ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ UI๋ฅผ ๋ด๋นํ๋ handleDotActive๋ผ๋ ํจ์๋ฅผ ๋๊ณ ์ ๋ ฅํ ์ซ์๋ ๋๊ทธ๋ผ๋ฏธ ์์ ๋ฐ๊ฟ์ค๋๋ค.
// ์ซ์ํค๋ฅผ ๋๋ ์๋ ์ด๋ฒคํธ
_this.handleNumber = function(number){
_this.passwordNumber[_this.cnt] = number.textContent;
_this.handleDotActive(true);
_this.cnt++; // _this.passwordNumber[_this.cnt] ๋ฃ์ด์ค ํ์ ์ฆ๊ฐ์์ผ์ฃผ์ธ์!
if(_this.cnt === 4) {
_this.handleResult();
}
}
// dot ํ์ฑํ
_this.handleDotActive = function(type){
if(type) {
_this.dots.forEach(function(dot, i){
if(i === _this.cnt) dot.classList.add('active');
})
} else {
_this.dots.forEach(function(dot){
dot.classList.remove('active');
})
}
}
// ๊ฒฐ๊ณผ์ฒ๋ฆฌ
_this.handleResult = function(){
// ๊ฒฐ๊ณผ์ฒ๋ฆฌํ๋ ๊ตฌ๊ฐ!
}
handleDotActive์์ type์ ๋ฐ๋ ์ด์ ๋ ๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ์ ๊ฒฝ์ฐ ๋ฆฌ์ ์ ์ฒ๋ฆฌํ๋ ๋ถ๋ถ์ ๊ฐ์ด ์ฌ์ฉํ๊ธฐ ์ํด์์ ๋๋ค. ์ด์ handleResult๊น์ง ๋ง๋ฌด๋ฆฌํด๋ด ์๋ค.
์ ๋ ๋น๊ต๋ง ํ๋ ํจ์๋ฅผ ๋ฐ๋ก ๋์ด boolean๊ฐ์ ๋ฆฌํดํ๋๋ก ํ์์ต๋๋ค.
// ๋น๋ฐ๋ฒํธ ๋น๊ต
_this.handleCheckPw = function(){
let compare = JSON.stringify(_this.password) === JSON.stringify(_this.passwordNumber);
return compare;
}
// ๊ฒฐ๊ณผ์ฒ๋ฆฌ
_this.handleResult = function(){
if(_this.handleCheckPw()) {
// ๋น๋ฐ๋ฒํธ ๋ง์ผ๋ฉด
_this.parent.classList.add('confirm');
_this.message.textContent = _this.msg[1];
_this.compChk = true;
} else {
// ๋น๋ฐ๋ฒํธ ํ๋ฆฌ๋ฉด
_this.parent.classList.add('error');
_this.message.textContent = _this.msg[0];
// ์
๋ ฅ์ํ ์ด๊ธฐํ
_this.passwordNumber = [];
_this.cnt = 0;
setTimeout(function(){
_this.parent.classList.remove('error');
_this.handleDotActive(); // ๋๊ทธ๋ผ๋ฏธ UI ์ด๊ธฐํ
}, 800);
}
}
JSON.stringify๋ก ์ ์ฒด ๋ฌธ์๋ฅผ ๋น๊ตํด์ผ ์์๊น์ง ํต์งธ๋ก ๋น๊ต๊ฐ ๋ฉ๋๋ค.
( for๋ฌธ์ผ๋ก๋ ๋น๊ตํ ์ ์์ง๋ง ์ด๊ฒ ํจ์ฌ ๊ฐ๋จํ๊ณ ํธํด์! )
๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ์ ๋ setTimeout์ ํตํด ์๋ฌ ๋ฌธ๊ตฌ๋ฅผ ์ ์ ๋ณด์ฌ์ค ๋ค ๋ค์ ์ ๋ ฅํ ์ ์๋๋ก ์ํ ์ด๊ธฐํ๋ฅผ ์์ผ์ค๋๋ค.
์ด๋ ๊ฒ ํ๋ฉด ์์ฑ์ธ ๊ฒ ๊ฐ์ง๋ง! ๐ค
์๋ฌ ๋ฌธ๊ตฌ๊ฐ ๋ ์๋ ๋์ ๋ค๋ฅธ ํค๋ฅผ ๋๋ฌ๋ฒ๋ฆฐ๋ค๋ฉด, ๊ทธ ๋๋ฆฐ ๊ฐ์ด ์์ฌ ๋ฒ๋ฆฌ๊ฒ ๋ผ์!
๊ทธ๋์ ์๋ฌ ๋ฌธ๊ตฌ๊ฐ ๋ ์๋ ๋์์๋ ํค ์ ๋ ฅ์ ํด๋ ๋์์ด ๋์ง ์๋๋ก ๋ง์์ผ ํฉ๋๋ค.
๊ทธ๋์ _this.comp๋ผ๋ ๋ณ์๋ฅผ ์ ์ํด ๋์์ต๋๋ค.
{...}
// ์ซ์๋ฒํผ click์ด๋ฒคํธ ์ฐ๋
_this.handleListener = function(){
if(!_this.compChk) { // ์ถ๊ฐ!
_this.numbers.forEach(function(number){
{...}
})
}
}
// ์ซ์ํค๋ฅผ ๋๋ ์๋ ์ด๋ฒคํธ
_this.handleNumber = function(number){
if(!_this.compChk) { // ์ถ๊ฐ
_this.passwordNumber[_this.cnt] = number.textContent;
{...}
}
}
// ๊ฒฐ๊ณผ์ฒ๋ฆฌ
_this.handleResult = function(){
if(_this.handleCheckPw()) {
{...}
_this.compChk = true;
} else {
{...}
// ์ผ์์ ์ธ ํด๋ฆญ ๋ฐฉ์ง
_this.compChk = true;
setTimeout(function(){
_this.compChk = false; // ๋ค์ false๋ก ๋ฐ๊ฟ์ค์ผ ํด๋ฆญ์ด๋ฒคํธ๊ฐ ์๋๋๊ฒ ์ง์?
{...}
}, 800);
}
}
{...}
์ด๋ ๊ฒ ํ๋ฉด ๋น๋ก์ ๋๋ฌ์ต๋๋ค!
ํจ์๋ฅผ ํธ์ถํ๊ธฐ ์ํด ์๋ก์ด ๋ณ์์ ํ ๋นํ๊ณ ๋น๋ฐ๋ฒํธ๋ฅผ ๋๊ฒจ์ค๋๋ค.
let pwCheck = new PwCheck(1234);
ํ๋ฌ์ค๋ก ์ฌ์ฌํด์(?) ํค ์ ๋ ฅ๊ฐ๋ ๋ฐ์๋ณด์์ต๋๋ค.
์ฌ์ค ํค๋ณด๋ ์ ๋ ฅ์ผ๋ก ํ ๊ฑฐ๋ผ๋ฉด ๊ตณ์ด ํคํจ๋๊ฐ ํ์ ์๋๋ฐ, ๊ทธ๋ฅ ์ด์ ์์ด ๋ง๋ค์ด ๋ณด์์ต๋๋ค. ๐คฃ
๊ธฐ๋ณธ ๋ก์ง์ ๋ชจ๋ ๊ฐ๊ณ ๋ฒํผ ํด๋ฆญ์ ํค๋ณด๋ ํด๋ฆญ์ผ๋ก ๋ฐ๊ฟ์ฃผ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
๋ํ ํค ์ ๋ ฅ์ ํ์ํ๊ธฐ ์ํด ํคํจ๋ UI๋ ์ถ๊ฐํด์ค๋๋ค.
handleListenerํจ์๋ฅผ ์์ ํ๊ณ , handleButtonActive๋ฅผ ๋ง๋ค์ด ํค๋ณด๋ ํด๋ฆญ ์ ํคํจ๋๊ฐ ํ์ฑํ๋๋๋ก ํด๋ณด๊ฒ ์ต๋๋ค.
// ํค๋ณด๋ click์ด๋ฒคํธ ์ฐ๋ (๋ณ๊ฒฝ)
_this.handleListener = function(){
window.addEventListener('keydown', function(e){
_this.handleButtonActive(e.key);
_this.handleNumber(e.key);
})
}
// ๋ฒํผํ์ฑํ (์ถ๊ฐ)
_this.handleButtonActive = function(key){
_this.numbers.forEach(function(number){
if(number.textContent === key) number.style.background = "lightblue";
setTimeout(function(){ number.style.background = "#F8F2F2" }, 140);
})
}
๊ทธ๋ฆฌ๊ณ handleListener์์ e.key๋ฅผ ๋๊ฒผ๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด์ handleNumber์์๋ number.textContent๋ก ๊ฐ์ ๊ฐ์ ธ์์ง๋ง, ์ฌ๊ธฐ์๋ ๊ทธ๋ฅ number๋ก ์์ ํด ์ค์ผ ํฉ๋๋ค.
// ์ซ์ํค๋ฅผ ๋๋ ์๋ ์ด๋ฒคํธ
_this.handleNumber = function(number){
if(!_this.compChk) { // 999
// _this.passwordNumber[_this.cnt] = number.textContent;
_this.passwordNumber[_this.cnt] = number; // <- ์ด๋ ๊ฒ ์์
{...}
}
}
๊ทธ๋ผ ์๋ฃ๋์์ต๋๋ค.
'๊ฐ๋ฐ ๐พ > Playground' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
ํ๋์ฉ ๋ํ๋๋ ํต ๋ฉ๋ด ๋ง๋ค๊ธฐ (SCSS & CSS) (0) | 2021.07.12 |
---|---|
javascript ์คํฌ๋กค ์ํ๋ฐ ๋ง๋ค๊ธฐ (window / div) (2) | 2021.07.01 |
[html, css, javascript] ์ฌ์ฌํด์ ๋ง๋ค์ด๋ณธ ๋ฉ์ธ ํ๋ฉด ํจ๊ณผ (0) | 2021.02.06 |