재사용 가능한 의미 있는 기능을 가진 UI 모음
여러 군데에서 동일하게 쓰이는 UI들을 묶어서 하나의 컴포넌트로 분리하면 코드의 중복도 줄이고 재사용성을 높여 전체 서비스의 일관성을 부여할 수 있다.
export default class Component {
events = [];
constructor(){
}
template(){
return '';
}
render(){
this.setEvents();
}
addEvent(){
this.events.push({ listenerName, callback });
}
}
export class Component {
children = {
//name: {
// object: new Object(),
// parentSelector: ""
//} 와 같은 방식으로 정보를 가지고 있다.
};
events = [];
constructor() {
super();
}
template() {
return `
<div id = "header"> </div>
<div id = "column"> </div>
`;
}
render(parent) {
this.parent = parent;
parent.innerHTML += this.template();
for (const key in this.children) {
const childParent = root.querySelector(this.children[key].parentSelector) || root;
this.children[key].object.render(childParent);
}
}
addEvent(listenerName, callback) {
this.events.push({ listenerName, callback });
}
}
→ 해결방안
export class Component {
children = {
//name: {
// object: new Object(),
// parentSelector: ""
//} 와 같은 방식으로 정보를 가지고 있다.
};
events = [];
rootId;
rootClass = [];
rootSelectorClassName = "";
constructor() {
super();
}
template() {
return `
<div id = "header"> </div>
<div id = "column"> </div>
`;
}
render(parent) {
this.parent = parent;
this.createDOM();
parent.appendChild(this.current);
this.setEvents(this.current);
}
createDOM() {
const wrapper = document.createElement("div");
if (this.rootId) {
wrapper.id = this.rootId;
}
this.rootClass.forEach((className) => {
wrapper.classList.add(className);
});
wrapper.innerHTML = this.template();
this.renderTree(wrapper);
this.current = wrapper;
return wrapper;
}
renderTree(root) {
for (const key in this.children) {
const childParent = root.querySelector(this.children[key].parentSelector) || root;
this.children[key].object.render(childParent);
}
}
setEvents(root) {
if (root) {
this.events.forEach(({ listenerName, callback }) => {
root.addEventListener(listenerName, (event) => callback(event));
});
}
}
addEvent(listenerName, callback) {
this.events.push({ listenerName, callback });
}
}
export default class Component {
//...
rerender() {
this.clear();
this.renderTree(this.current);
this.setEvents(this.current);
}
clear() {
this.current.innerHTML = this.template();
}
//...
}
export default class Component {
children = {};
events = [];
rootId;
rootClass = [];
rootSelectorClassName = "";
constructor() {
this.rootSelectorClassName = this.generateRandomString(16);
this.rootClass.push(this.rootSelectorClassName);
this.children = {};
this.events = [];
}
generateRandomString(length) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
let result = '';
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
addRootclass(className) {
this.rootClass.push(className);
}
template() {
return '';
}
render(parent) {
this.parent = parent;
this.current = this.createDOM();
this.parent.appendChild(this.current);
this.setEvents(this.current);
}
createDOM() {
const wrapper = document.createElement("div");
if (this.rootId) {
wrapper.id = this.rootId;
}
this.rootClass.forEach((className) => {
wrapper.classList.add(className);
});
wrapper.innerHTML = this.template();
this.renderTree(wrapper);
this.current = wrapper;
return wrapper;
}
renderTree(root) {
for (const key in this.children) {
const childParent = root.querySelector(this.children[key].parentSelector) || root;
this.children[key].object.render(childParent);
}
}
setEvents(root) {
if (root) {
this.events.forEach(({ listenerName, callback }) => {
root.addEventListener(listenerName, (event) => callback(event));
});
}
}
rerender() {
this.clear();
this.renderTree(this.current);
this.setEvents(this.current);
}
clear() {
this.current.innerHTML = this.template();
}
addEvent(listenerName, callback) {
this.events.push({ listenerName, callback });
}
}
사용 예시
import { Button } from "./Button/button.js";
import Component from "./component.js";
export class AlertDialog extends Component {
rootId = "alertDialog"
children = {
dismiss: {
object: new Button("취소", null, "dismiss-button"),
parentSelector: "#alertButtons"
},
confirm: {
object: new Button("삭제", null, "alert-button"),
parentSelector: "#alertButtons"
},
};
constructor(text, onConfirmClck = () => { }, onDismissClick = () => { }) {
super();
this.text = text;
this.children.confirm.object.addEvent("click", onConfirmClck);
this.children.dismiss.object.addEvent("click", onDismissClick);
}
template() {
return `
<div id="alertText" class = "display-medium16">
${this.text}
</div>
<div id = "alertButtons">
</div>
`;
}
}
template() {
return `
<div id = "header"> ${this.children.header.object.template()}</div>
<div class = "div"> ${this.children.column.object.template()}</div>
`;
}