[Front-end๐Ÿฆ] #31 DOM Event (target, ์œ„์ž„ +), TDD

๋˜์ƒยท2021๋…„ 12์›” 10์ผ
0

front-end

๋ชฉ๋ก ๋ณด๊ธฐ
45/58
post-thumbnail

1. DOM

1. createElement

<input type="text">
<div id="parentElement">
  <p id="childElement">ใ…ใ„ดใ…‡ใ„น</p>
</div>
<script>
    var input = document.querySelector("input");
    var span = document.createElement("span");
    // input์œผ๋กœ ์ฃผ๋ฉด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ž…๋ ฅ ๋ฐ›์•„์˜ด.
    input.addEventListener('input, () => {
        span.textContent = input.value;
    });
    var sibling = document.getElementById("childElement");
    var parentDiv = document.getElementById("parentElement");
    parentDiv.insertBefore(span, sibling);
</script>
  • outerHTML :
  • innerHTML : ์š”์†Œ์— ํฌํ•จ๋œ HTML ๋งˆํฌ์—… -> XSS ๊ณต๊ฒฉ ๊ฐ€๋Šฅ. ๊ทธ๋ž˜์„œ Node.textContent ๊ฐ™์€ ๊ฑธ๋กœ ์ž…๋ ฅ๊ฐ’ ์ฒ˜๋ฆฌ ํ•„์š”.
  • innerText : ์š”์†Œ + ์ž์†์˜ ๋ Œ๋”๋ง๋œ ํ…์ŠคํŠธ ์ฝ˜ํ…์ธ  (์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์š”์†Œ๋งŒ ์ฒ˜๋ฆฌ.) CSS ๋ Œ๋”๋ง ๋จ. ๊ณต๋ฐฑ ์ธ์‹X
  • textContent : ๋…ธ๋“œ์˜ ํ…์ŠคํŠธ ์ฝ˜ํ…์ธ . ๊ณต๋ฐฑ ๋ฌธ์ž ์ธ์‹. tag ๋นผ๊ณ  text ๋‹ค ๋“ค์–ด๊ฐ. ํ…์ŠคํŠธ๋งŒ ์ฒ˜๋ฆฌํ•  ๋•Œ๋Š” ์ด๊ฑธ๋กœ ํ•˜๋Š” ๊ฒƒ์ด ์„ฑ๋Šฅ์ƒ ์œ ๋ฆฌํ•˜๋‹ค.

2. insertAdjacentHTML

<strong class="sayHi">
    ๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค.
</strong>
<script>
    const sayHi = document.querySelector('.sayHi');
// ์›๋ž˜ ์š”์†Œ์˜ ์ž์‹ ์•ž๋’ค๋กœ ์š”์†Œ๋ฅผ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.
    sayHi.insertAdjacentHTML('beforebegin', '<span>1</span>');
    sayHi.insertAdjacentHTML('afterbegin', '<span>2</span>');
    sayHi.insertAdjacentHTML('beforeend', '<span>3</span>');
    sayHi.insertAdjacentHTML('afterend', '<span>4</span>');
</script>

3. ๋…ธ๋“œ ํƒ์ƒ‰

๋…ธ๋“œ : ๊ฐ ์š”์†Œ, ์†์„ฑ, ์ฝ˜ํ…์ธ ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋‹จ์œ„๋ฅผ ๋ชจ๋‘ ๋…ธ๋“œ๋ผ๊ณ  ํ•œ๋‹ค. ์ฃผ์„, Text๊ฐ’, ์ค„๋ฐ”๊ฟˆ ...

const cont = document.querySelector(".cont");
console.log(cont.firstElementChild);  // ์ฒซ๋ฒˆ์งธ ์ž์‹
console.log(cont.lastElementChild);   // ๋งˆ์ง€๋ง‰ ์ž์‹
console.log(cont.nextElementSibling); // ๋‹ค์Œ ํ˜•์ œ์š”์†Œ
console.log(cont.previousSibling);    // ์ด์ „ ํ˜•์ œ๋…ธ๋“œ - Element๊ฐ€ ์—†์œผ๋ฉด.
console.log(cont.children);           // ๋ชจ๋“  ์ง๊ณ„์ž์‹
console.log(cont.parentElement);      // ๋ถ€๋ชจ ์š”์†Œ

4. ์ด๋ฒคํŠธ ๊ฐ์ฒด, ํ๋ฆ„

  • ์ด๋ฒคํŠธ ๊ฐ์ฒด : ์ด๋ฒคํŠธ์—์„œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜์—๋Š” ์ด๋ฒคํŠธ์™€ ๊ด€๋ จ๋œ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ธ์ž๊ฐ€ ์ „์†ก๋œ๋‹ค. ์žก์•„์„œ ์“ธ ์ˆ˜ ์žˆ๋‹ค.
  • ์ด๋ฒคํŠธ ํ๋ฆ„ : ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” DOM tree๋ฅผ ํƒ€๊ณ  ์ด๋ฒคํŠธ ๋Œ€์ƒ์„ ์ฐพ์•„๊ฐ. (์บก์ฒ˜๋ง ๋‹จ๊ณ„) ๋Œ€์ƒ์„ ์ฐพ๊ณ  ์บก์ฒ˜๋ง์ด ๋๋‚˜๋ฉด DOM tree๋ฅผ ํƒ€๊ณ  ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ๋ชจ๋“  ๋ฒ„๋ธ”๋ง ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์‹คํ–‰ (์ด๋ฒคํŠธ๋ฒ„๋ธ”๋ง ๋‹จ๊ณ„) ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ฐจ๋ก€๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ์ด๋ฒคํŠธ ์ „ํŒŒ(event propagation)๋ผ๊ณ  ํ•œ๋‹ค.
window.addEventListener('click', () => {
    console.log("window capture!");
}, true); // true : ์บก์ฒ˜๋ง ๋‹จ๊ณ„์˜ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก. ์•ˆ์“ฐ๋ฉด ๋ฒ„๋ธ”๋ง ์ด๋ฒคํŠธ default

5. event target, current target, ์ด๋ฒคํŠธ ์œ„์ž„

<article class="parent">
    <ol>
        <li><button class="btn-first" type="button">๋ฒ„ํŠผ1</button></li>
        <li><button type="button">๋ฒ„ํŠผ2</button></li>
        <li><button type="button">๋ฒ„ํŠผ3</button></li>
    </ol>
</article>

<script>
    const parent = document.querySelector('.parent');
    parent.addEventListener('click', function (event) {
        console.log(event.target); // ์ด๋ฒคํŠธ๋ฅผ ์ผ์œผํ‚จ ๋…€์„. ๋ถ€๋ชจ์— ์ด๋ฒคํŠธ๊ฐ€ ๋ถ™์–ด์žˆ์œผ๋ฉด ์ž์‹์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ์ผ์–ด๋‚˜๋„ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์—!
        console.log(event.currentTarget); // ์›๋ž˜ ์ด๋ฒคํŠธ๊ฐ€ ๋ถ™์–ด์žˆ๋Š” ๋…€์„.
      //
      // ์ด๋ฒคํŠธ ์œ„์ž„ : target์œผ๋กœ ์ด๋ฒคํŠธ๋ฅผ ์ผ์œผํ‚จ ๋…€์„์„ ์žก๊ณ  ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋„ ๊ฐ€๋Šฅ!
      if (event.target.classList.contains("btn")) {
        event.target.innerText = "๋ฒ„ํŠผ~~";
    })
</script>
  • ์ด๋ฒคํŠธ ์œ„์ž„ : ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์—†์–ด๋„ ๋งˆ์น˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์‚ฌ์šฉ.

5. ์ด๋ฒคํŠธ์—์„œ this

const parent = document.querySelector('.parent');
parent.addEventListener('click', function (event) {
  //currentTarget === this
  console.log(this);
})
parent.addEventListener('click', (evt) => {
  // ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์•ˆ์˜ this๋Š” ์ƒ์œ„ ์Šค์ฝ”ํ”„์˜ this๋ฅผ ์ฐธ์กฐ. -> ํ—ท๊ฐˆ๋ฆฌ๋‹ˆ๊นŒ ์›ฌ๋งŒํ•˜๋ฉด this ๋Œ€์‹  evt.target ์ด๋ ‡๊ฒŒ ์จ์ฃผ์ž.
  console.log(this);
})

6. select box ์‹ค์Šต

#20 ์—์„œ js ์ฝ”๋“œ๋Š” ์„ ์ƒ๋‹˜์ด ์ฃผ์‹œ๊ณ  CSS๋Š” ์ง์ ‘ ์ž‘์„ฑํ–ˆ์—ˆ๋˜, ์…€๋ ‰ํŠธ ๋ฐ•์Šค๋ฅผ ์ด๋ฒˆ์—๋Š” js ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.

// 1. ul์— li ๋™์  ์ถ”๊ฐ€
const memberList = document.body.querySelector(".list-member");
const contents = ["Python", "Java", "JavaScript", "C#", "C/C++"];

for (x of contents) {
    const li = document.createElement('li');
    const button = document.createElement('button');
    button.type = "button";
    button.innerText = x;
    li.appendChild(button);
    memberList.appendChild(li);
  // list.appendChild(li).appendChild(btn); //chaining ๊ฐ€๋Šฅ!!
}
// 2. addEventListener ๋ถ™์ด๊ธฐ.
const selectButton = document.querySelector('.btn-select');
const memberButtons = document.querySelectorAll('.list-member li button');
// ๋ฐ•์Šค ๋ˆ„๋ฅด๋ฉด option ๋‚˜์˜ค๊ฒŒ
selectButton.addEventListener('click', (event) => {
    selectButton.classList.toggle('on');
});
// option ์„ ํƒํ•˜๋ฉด ๋ˆŒ๋ฆฌ๋ฉด์„œ option list ๋‹ซํžˆ๊ฒŒ.
// forEach ๋Š” ๋ฐฐ์—ด์„ ์ˆœํ™˜ํ•˜๋Š” ๊ฒƒ์ธ๋ฐ.. 
// querySelectorAll ๋กœ ๋ฝ‘์•„์˜จ๊ฑด nodeList(์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด)
// Array.prototype.forEach, NodeList.prototype.forEach() ๊ฐ€ ๋‘˜ ๋‹ค ์žˆ์–ด์„œ ์ž‘๋™์ด ๋˜๋Š” ๊ฒƒ.
// ๊ทผ๋ฐ NodeList forEach๋Š” IE ์ง€์›์ด ์•ˆ๋จ..............
memberButtons.forEach(x => x.addEventListener('click', (event) => {
    selectButton.textContent = event.target.innerText;
    selectButton.classList.remove('on');
}));
// keyboard ์ ‘๊ทผ์„ฑ์„ ๊ณ ๋ คํ•œ ์ฝ”๋“œ.
const listAll = ul.querySelectorAll('button'); // option list
const firstOption = ul.querySelector('button'); //option first button
const lastOption = listAll[listAll.length - 1]; //option last button
//focus ์ด๋™
const handleTabFoucus = function (e) {
    if (!e.shiftKey && e.keyCode === 9) {
        e.preventDefault();
        window.setTimeout(function () {
            firstOption.focus();
        }, 100);
    }
};
//shift+tab
const handlShiftTabFoucus = function (e) {
    if (e.shiftKey && e.keyCode === 9) {
        e.preventDefault();
        window.setTimeout(function () {
            lastOption.focus();
        }, 100);
    }
};
//ESCํ‚ค 
const hadleEsc = function (e) {
    if (e.keyCode === 27) {
        btn.classList.remove('on');
        ul.classList.remove('on');
        window.setTimeout(function () {
            btn.focus();
        }, 100);
    }
}
selectButton.addEventListener('keydown', hadleEsc);
memberList.addEventListener('keydown', hadleEsc);
lastOption.addEventListener('keydown', handleTabFoucus);
firstOption.addEventListener('keydown', handlShiftTabFoucus);
// jQuery ์ฒ˜๋Ÿผ ์“ฐ๋Š” ํ…Œํฌ๋‹‰ -> ์“ฐ์ง€ ๋ง์ž.
const $ = (selector => document.querySelector(selector);
$('.list-member')




2. TDD

Test Driven Development - ์šฐ๋ฆฌ๋Š” jasmin์„ ์ด์šฉํ•œ๋‹ค.

  • test ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์ ๊ณ , ๊ทธ ํ›„์— ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœ.
  • 3๊ฐ€์ง€ ๋‹จ๊ณ„๋ฅผ ํ†ตํ•ด ์ง„ํ–‰๋จ.
  1. RED : ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํŒจํ•˜๋Š” ๋‹จ๊ณ„
  2. GREEN : ํ…Œ์ŠคํŠธ์— ์„ฑ๊ณตํ•œ ๋‹จ๊ณ„
  3. REFACTOR : ํ…Œ์ŠคํŠธ์— ์„ฑ๊ณตํ•œ ์ฝ”๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฝ”๋“œ์˜ ํ’ˆ์งˆ์„ ๋†’์ด๋Š” ๋‹จ๊ณ„

์‹ค์Šต

  1. jasmine ํŒŒ์ผ์„ ๋‹ค์šด๋ฐ›์•„์„œ ํ”„๋กœ์ ํŠธ์— ๋„ฃ๊ณ ,
  2. html ์— ๋งํฌ๋ฅผ ๊ฑด๋‹ค. jasmine link
  3. spec ํด๋”์— ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ
  4. src ์— ์ง„์งœ js ์ฝ”๋“œ๋ฅผ ๋„ฃ๊ณ 
  5. SpecRunner.html ์— ์—ฐ๊ฒฐ ํ›„ ์‹คํ–‰์‹œ์ผœ์„œ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๊ฐ€ ์ž˜ ๋‚˜์˜ค๋Š”์ง€ ํ™•์ธํ•ด๋ณธ๋‹ค.
// ์›๋ž˜ ์ฝ”๋“œ
function plusOne(num) {
    return num + 1;
}
// test code
// ํ…Œ์ŠคํŠธ ์œ ๋‹›๋“ค์˜ ๋ชจ์Œ
describe('์Ÿˆ์Šค๋ฏผ ํ…Œ์ŠคํŠธ ์ž…๋‹ˆ๋‹ค.', () => {
    // it : ํ…Œ์ŠคํŠธ ์œ ๋‹› 1 (๋ง์…ˆ ํ•จ์ˆ˜)
    it('๋ง์…ˆ์„ ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.', () => {
        let num = 10;
        // expect : ์‹คํ–‰ํ•  ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•œ๋‹ค.
        // toBe : ๋‚ด๊ฐ€ ๊ธฐ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋„ฃ์œผ๋ฉด ์ผ์น˜ํ•˜๋Š”์ง€ ํŒ๋‹จํ•ด์คŒ.
        expect(plusOne(num)).toBe(num+1); 
    });
});

๊ทผ๋ฐ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋ผ์„œ ์ด๋ ‡๊ฒŒ ๋ฐ”๋กœ ์ง ๊ฑฐ์ง€.. ๋งŒ์•ฝ ๋” ๋ณต์žกํ•˜๋‹ค๋ฉด...? ์ •๋ง ํž˜๋“ค ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ž˜์„œ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์งœ๋ ค๋ฉด

  • ์ฝ”๋“œ๋ฅผ UI ์—์„œ ์™„์ „ํžˆ ๋ถ„๋ฆฌ
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ JS ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ
  • ๋ชจ๋“  ๊ธฐ๋Šฅ์€ ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„
    ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.
    + ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋„ ๊ฒฐ๊ตญ ์‚ฌ๋žŒ์ด ์งœ๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์–ธ์ œ๋“ ์ง€ ์˜ˆ์™ธ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.




์ž‘์€ ํšŒ๊ณ 

  • Xcode ์—์„œ ํ”„๋กœ์ ํŠธ ๋งŒ๋“ค๋•Œ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ญ”๋ฐ.. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ๋ญ”๋ฐ.. ๋‚ด๊ฐ€ ์ง  ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธ ํ•ด์ฃผ๋Š” ๊ฑฐ๊ฒ ์ง€ ๊ทผ๋ฐ ๊ทธ๋ž˜์„œ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”๋ฐ... ๊ธฐ์—… ๊ณต๊ณ ์—์„œ๋Š” ์งœ๋ณธ ์‚ฌ๋žŒ ์šฐ๋Œ€์ธ๋ฐ... ๋ผ๋Š” ์ƒ๊ฐ์„ ํ–ˆ๋Š”๋ฐ ์ด์ œ์•ผ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ญ”์ง€ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • ๋‚˜์ค‘์„ ๋Œ€๋น„ํ•ด์„œ ์ด๋ฒคํŠธ ์บก์ณ๋ง, ๋ฒ„๋ธ”๋ง, target, this ๋ฅผ ์ž˜ ์•Œ์•„๋‘๋Š” ๊ฒƒ์ด ์ข‹์„๋“ฏ!!!!




profile
0๋…„์ฐจ iOS ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€