728x90
반응형
1. 컴포넌트 생성 및 클래스 작성
- 컴포넌트 : 재사용 가능한 각각의 독립된 기능의 모듈(화면에 보여지는 각각의 UI 단위)
EX) HEADER, 제목, 설명 부분, INPUT 요소+검색 버튼, 영화 정보 카드 부분(사진, 연도 포함)
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="module" defer src="./src/main.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
MAIN.JS
import App from './App.js'
const root = document.querySelector('#root')
root.append(new App().el)
APP.JS
// export default class App {
// constructor() {
// this.el = document.createElement('div')
// this.el.textContent = 'Hello, world!'
// }
// }
import { Component } from "./core/core.js";
export default class App extends Component {
// constructor() {
// // component 앱에서 상속하는 클래스의 constructor 실행
// // constructor(), super() 모두 지우면 기본값으로 실행됨
// super()
// }
render() {
this.el.textContent = 'Hello, world!'
}
}
CORE.JS - 해당 기능에서 CORE 역할
// 컴포넌트, 라우터, 스토어(컴포넌트와 컴포넌트의 데이터 통신 기능) 기능 포함
/* =========== Component ============ */
// tagName을 받거나, el 속성에 요소를 메모리 상에만 하나 추가하고,
// 사용되는 부분에서 정의되는 render 함수 부분을 실행
export class Component {
// payload : App.js에서 요소 생성에서 필요한 태그 인수
constructor(payload = {}) {
// 객체 구조 분해 할당
// payload 객체 데이터의 tagName 속성에서 데이터를 꺼냄
const {tagName = 'div'} = payload
this.el = document.createElement(tagName)
this.render() // 최초 1번만 호출
}
// 컴포넌트 클래스를 App.js, 다른 js 파일에서 확장해서 사용할 때만 동작
render() {
}
}
2. 선언적 렌더링 및 이벤트 핸들링
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="module" defer src="./src/main.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
MAIN.JS
// main.js
import App from './App.js'
const root = document.querySelector('#root')
root.append(new App().el)
APP.JS
// app.js
// export default class App {
// constructor() {
// this.el = document.createElement('div')
// this.el.textContent = 'Hello, world!'
// }
// }
import { Component } from "./core/core.js";
export default class App extends Component {
constructor() {
// component 앱에서 상속하는 클래스의 constructor 실행
// constructor(), super() 모두 지우면 기본값으로 실행됨
super({
state: { // 선언적 렌더링 : App 클래스 내부에서 사용할 하나의 데이터를 state 속성에 지정하고,
//render 함수에서 사용할 수 있도록 구현
// -> 선언해서 렌더링할 수 있도록 사용하는 것
inputText: ''
}
})
}
render() {
this.el.classList.add('search')
this.el.innerHTML = /* html */ `
<input />
<button>click!</button>
`
const inputEl = this.el.querySelector('input')
inputEl.addEventListener('input', ()=>{
this.state.inputText = inputEl.value
})
const buttonEl = this.el.querySelector('button')
buttonEl.addEventListener('click', () => {
console.log(this.state.inputText)
})
}
}
CORE.JS
// core.js
// 컴포넌트, 라우터, 스토어(컴포넌트와 컴포넌트의 데이터 통신 기능) 기능 포함
/* =========== Component ============ */
// tagName을 받거나, el 속성에 요소를 메모리 상에만 하나 추가하고,
// 사용되는 부분에서 정의되는 render 함수 부분을 실행
export class Component {
// payload : App.js에서 요소 생성에서 필요한 태그 인수
constructor(payload = {}) {
// 객체 구조 분해 할당
// payload 객체 데이터의 tagName 속성에서 데이터를 꺼냄
const {tagName = 'div',
state = {}} = payload
this.el = document.createElement(tagName)
this.state = state
this.render() // 최초 1번만 호출
}
// 컴포넌트 클래스를 App.js, 다른 js 파일에서 확장해서 사용할 때만 동작
render() {
}
}
3. 조건과 반복
- HTML, MAIN.JS, CORE.JS는 이전과 동일
APP.JS
// app.js
import { Component } from "./core/core.js";
export default class App extends Component {
constructor() {
super({
state: {
fruits : [
{name: 'Apple', price: 1000},
{name: 'Banana', price: 2000},
{name: 'Cherry', price: 3000},
]
}
})
}
render() {
console.log(this.state.fruits)
this.el.innerHTML = /*html*/ `
<h1>Fruits</h1>
<ul>
<!-- filter 메소드로 조건에 맞는 경우만 배열로 반환 -->
${this.state.fruits
.filter(fruit => {
return fruit.price < 3000
}).map(fruit => {
return `<li>${fruit.name}</li>`
}).join('')}
</ul>
`
}
}
4. 자식 컴포넌트에게 데이터 전달
- HTML, MAIN.JS 이전과 동일
APP.JS
import { Component } from "./core/core.js";
import FruitItem from "./components/FruitItem.js";
export default class App extends Component {
constructor() {
super({
state: {
fruits : [
{name: 'Apple', price: 1000},
{name: 'Banana', price: 2000},
{name: 'Cherry', price: 3000}
]
}
})
}
render() {
console.log(this.state.fruits)
this.el.innerHTML = /*html*/ `
<h1>Fruits</h1>
<ul></ul>
`
const ulEl = this.el.querySelector('ul')
ulEl.append(...this.state.fruits
// app.js 컴포넌트에서 사용하는 fruititem 컴포넌트는 자식 컴포넌트
.map(fruit => new FruitItem({
// 부모 컴포넌트가 자식 컴포넌트에게 내려주는 데이터가 들어있는 속성
// 부모한테 데이터를 받아야 자식 fruititem.js 컴포넌트에서 사용 가능
props: {
name: fruit.name,
price: fruit.price
}
}).el))
}
}
FruitItem.JS
import { Component } from "../core/core.js";
export default class FruitItem extends Component {
constructor(payload) {
super({
tagName : 'li',
props: payload.props
})
}
render() {
this.el.innerHTML = /*html*/ `
<span>${this.props.name}</span>
<span>${this.props.price}</span>
`
this.el.addEventListener('click', ()=>{
console.log(this.props.name, this.props.price)
})
}
}
CORE.JS
// 컴포넌트, 라우터, 스토어(컴포넌트와 컴포넌트의 데이터 통신 기능) 기능 포함
/* =========== Component ============ */
// tagName을 받거나, el 속성에 요소를 메모리 상에만 하나 추가하고,
// 사용되는 부분에서 정의되는 render 함수 부분을 실행
export class Component {
// payload : App.js에서 요소 생성에서 필요한 태그 인수인데, 객체 데이터를 payload에 저장
constructor(payload = {}) {
// 객체 구조 분해 할당
// payload 객체 데이터의 tagName 속성에서 데이터를 꺼냄
const {
tagName = 'div',
state = {},
props = {}
} = payload
// this가 붙어있는 경우, 클래스 내부에서 만들어지는 모든 메소드 안에서
// this 키워드로 참조해서 사용 가능
this.el = document.createElement(tagName)
this.state = state
this.props = props
this.render() // 최초 1번만 호출
}
// 컴포넌트 클래스를 App.js, 다른 js 파일에서 확장해서 사용할 때만 동작
render() {
}
}
728x90
반응형
'JS, TS' 카테고리의 다른 글
[JS] 컴포넌트 - 상태관리(스토어) (0) | 2024.01.17 |
---|---|
[JS] 컴포넌트 - 해시 라우터 관리 (0) | 2024.01.16 |
[JS] 정규표현식 (0) | 2024.01.16 |
[JS] 심화 학습 (0) | 2024.01.15 |
[JS] 기타 Web APIs (1) | 2024.01.15 |