필수구현
입력폼 구현
입력에는 제목과 내용을 입력할 수 있다. 둘중 하나라도 값이 없는경우 사용자에게 알려줘야 한다. alert 또는 입력창 하단에 문구 노출 방식 첫 페이지가 렌더링 되었을때 제목에 포커스가 맞춰져야 한다. 제출은 키보드의 Enter 를 누르거나 입력 버튼을 누르면 제출이 되어야 한다. 제출 후에는 입력값들이 초기화 되어야 한다. 제출 후 할일 목록에 티켓이 생성되고 티켓에는 제목, 내용, 제출 시간이 표시되어야 한다.
ItemAdd.js : 내용 추가기능
method 전달 확인
// src/app.js
// state , method 관리
import Component from './core/Component.js' ;
import ItemList from './components/ItemList.js' ;
import ItemAdd from './components/ItemAdd.js' ;
export default class App extends Component {
// 초기 state
setup () {
this . state = {
items : [
{
seq : 1 ,
title : '선배!!' ,
contents : '마라탕 사주세요' ,
date : '2024.08.17. 02:43' ,
},
{
seq : 2 ,
title : '그럼 혹시..' ,
contents : '탕후루도 같이?' ,
date : '2024.08.17. 02:45' ,
},
],
};
}
// 자식 컴포넌트가 위치할 dom 요소
template () {
return `
<div data-component="itemAdd"> </div>
<div data-component="itemList"> </div>
` ;
}
// mounted에서 자식 컴포넌트를 마운트
mounted () {
const { addItem } = this ;
const $itemList = this . $target . querySelector ( '[data-component="itemList"]' );
const $itemAdd = this . $target . querySelector ( '[data-component="itemAdd"]' );
// new 컴포넌트명('DOM'위치 , 전달할 props)
new ItemList ( $itemList , {
items : this . state . items ,
});
new ItemAdd ( $itemAdd , {
items : this . state . items ,
addItem : addItem ,
addItemthis : addItem . bind ( this ),
});
}
// 함수 정의
addItem (NewContent ) {
console . log ( 'addItem:' , this );
}
}
// src/components/ItemAdd.js
// 입력UI 와 입력기능
import Component from '../core/Component.js' ;
export default class ItemAdd extends Component {
template () {
this . props . addItem ();
this . props . addItemthis ();
}
setEvent () {}
}
입력받은 내용으로 state 를 수정하는 함수 addItem 을 App.js 에서 생성하고 자식 컴포넌트인 ItemAdd 에 props 로 전달한다.
bind(this) 를 사용하는 이유는 this 메서드가 확실하게 App.js 를 가리키기 위해서 사용하며,
bind(this) 를 사용하지 않는다면 호출 되는 상황에 따라서 다른 환경을 가리키게 된다.
ItemAdd.js 기능 구현
메소드가 자식 컴포넌트에 전달되는것을 확인했으니.. 실제 기능을 구현해보자.
// src/components/ItemAdd.js
// 입력UI 와 입력기능
import Component from '../core/Component.js' ;
export default class ItemAdd extends Component {
template () {
return `
<input class='title' name='title' placeholder="제목" />
<input class='contents' name='content' placeholder="내용" />
<button class='addBtn' type='button'>제출</button>
` ;
}
setEvent () {
const { addItem } = this . props ;
this . addEvent ( 'click' , '.addBtn' , () => {
console . log ( 'addBtn_click' );
let title = document . querySelector ( '.title' ). value ;
let contents = document . querySelector ( '.contents' ). value ;
console . log ( title , contents );
addItem ({ title : title , contents : contents });
});
}
}
'addBtn' 클릭시 각 input 에 접근하여 value 를 가져와서 App.js 에서 가져온 addItem 에게 입력받은 값을 인수로 넘겨준다.
그러면 App.js 의 addItem에 정의된 setState 기능으로 state 를 설정하게 되고
addItem ( NewContent ) {
const items = [ ... this . state . items ];
const seq = Math . max ( 0 , ... items . map ( v => v . seq )) + 1 ;
const { title , contents , date } = NewContent ;
this . setState ({
items : [ ... items , { seq , title , contents , date }],
});
}
core의 Component.js 에서 state 변경시 추가 하고 render 를 진행하게 된다.
setState ( newState ) {
// 상태 업데이트
this . state = { ... this . state , ... newState };
this . render ();
}
해당 내용이 ItemList 에서 보여지게 된다.
currentTime()
시간을 알려줄 함수를 App.js 에서 생성
Date 객체를 이용해서 원하는 format 으로 날짜를 표시 가능
currentTime () {
const now = new Date ();
// 사용자 정의 형식 (예: YYYY-MM-DD HH:MM:SS)
const year = now . getFullYear ();
const month = String ( now . getMonth () + 1 ). padStart ( 2 , '0' ); // 월은 0부터 시작하므로 +1
const day = String ( now . getDate ()). padStart ( 2 , '0' );
const hours = String ( now . getHours ()). padStart ( 2 , '0' );
const minutes = String ( now . getMinutes ()). padStart ( 2 , '0' );
const seconds = String ( now . getSeconds ()). padStart ( 2 , '0' );
const formattedDate = ` ${ year } . ${ month } . ${ day } ${ hours } : ${ minutes } ` ;
return formattedDate ;
}
해당 함수를 ItemAdd 에게 props 로 전달하며,
ItemAdd 에서 날짜를 추가하여 addItem 함수에게 전달
new ItemAdd ( $itemAdd , {
items : this . state . items ,
addItem : addItem . bind ( this ),
currentTime : currentTime . bind ( this ),
});
setEvent () {
const { addItem , currentTime } = this . props ;
this . addEvent ( 'click' , '.addBtn' , () => {
let title = document . querySelector ( '.title' ). value ;
let contents = document . querySelector ( '.contents' ). value ;
let date = currentTime ();
addItem ({ title : title , contents : contents , date : date });
});
}
필수구현
입력폼 구현
입력에는 제목과 내용을 입력할 수 있다. 둘중 하나라도 값이 없는경우 사용자에게 알려줘야 한다. -> alert 또는 입력창 하단에 문구 노출 방식 첫 페이지가 렌더링 되었을때 제목에 포커스가 맞춰져야 한다. 제출은 키보드의 Enter 를 누르거나 입력 버튼을 누르면 제출이 되어야 한다. 제출 후에는 입력값들이 초기화 되어야 한다. -> 일단은 비워지긴 하는데제출 후 할일 목록에 티켓이 생성되고 티켓에는 제목, 내용, 제출 시간이 표시되어야 한다.
'제출은 키보드의 Enter 를 누르거나'
-> keyup 이나 keydown 활용
this . addEvent ( 'keyup' , '.title, .contents' , e => {
if ( e . key === 'Enter' ) {
let title = document . querySelector ( '.title' ). value ;
let contents = document . querySelector ( '.contents' ). value ;
let date = currentTime ();
addItem ({ title : title , contents : contents , date : date });
}
});
첫 페이지가 렌더링 되었을때 제목에 포커스가 맞춰져야 한다.
-> focus 함수 생성
-> 처음 렌더링시 포커스
-> addItem 이후 제목에 포커스
// focus 하기
inputFocus ( focusSelector ) {
let newFocus = document . querySelector ( focusSelector );
newFocus . focus ();
}
둘중 하나라도 값이 없는경우 사용자에게 알려줘야 한다.
-> alert 또는 입력창 하단에 문구 노출 방식
-> 값이 없는 경우 div 에 관련 문구가 나오도록 함
기타.
input 의 autocomplete="off" : 자동완성 끄기
전체 코드
// src/app.js
// state , method 관리
import Component from './core/Component.js' ;
import ItemList from './components/ItemList.js' ;
import ItemAdd from './components/ItemAdd.js' ;
export default class App extends Component {
// 초기 state
setup () {
this . state = {
items : [
{
seq : 1 ,
title : '선배!!' ,
contents : '마라탕 사주세요' ,
date : '2024.08.17. 02:43' ,
},
{
seq : 2 ,
title : '그럼 혹시..' ,
contents : '탕후루도 같이?' ,
date : '2024.08.17. 02:45' ,
},
],
};
}
// 자식 컴포넌트가 위치할 dom 요소
template () {
return `
<div data-component="itemAdd"> </div>
<div data-component="itemList"> </div>
` ;
}
// mounted에서 자식 컴포넌트를 마운트
mounted () {
const { addItem , currentTime , inputFocus } = this ;
const $itemList = this . $target . querySelector ( '[data-component="itemList"]' );
const $itemAdd = this . $target . querySelector ( '[data-component="itemAdd"]' );
// new 컴포넌트명('DOM'위치 , 전달할 props)
new ItemList ( $itemList , {
items : this . state . items ,
});
new ItemAdd ( $itemAdd , {
items : this . state . items ,
addItem : addItem . bind ( this ),
currentTime : currentTime . bind ( this ),
inputFocus : inputFocus . bind ( this ),
});
}
// 함수 정의
// 추가하기
addItem ( NewContent ) {
const items = [ ... this . state . items ];
const seq = Math . max ( 0 , ... items . map ( v => v . seq )) + 1 ;
const { title , contents , date } = NewContent ;
this . setState ({
items : [ ... items , { seq , title , contents , date }],
});
}
// focus 하기
inputFocus ( focusSelector ) {
let newFocus = document . querySelector ( focusSelector );
newFocus . focus ();
}
currentTime () {
const now = new Date ();
// 사용자 정의 형식 (예: YYYY-MM-DD HH:MM:SS)
const year = now . getFullYear ();
const month = String ( now . getMonth () + 1 ). padStart ( 2 , '0' ); // 월은 0부터 시작하므로 +1
const day = String ( now . getDate ()). padStart ( 2 , '0' );
const hours = String ( now . getHours ()). padStart ( 2 , '0' );
const minutes = String ( now . getMinutes ()). padStart ( 2 , '0' );
const seconds = String ( now . getSeconds ()). padStart ( 2 , '0' );
const formattedDate = ` ${ year } . ${ month } . ${ day } ${ hours } : ${ minutes } ` ;
return formattedDate ;
}
}
// src/components/ItemAdd.js
// 입력UI 와 입력기능
import Component from '../core/Component.js' ;
export default class ItemAdd extends Component {
template () {
return `
<input class='title' name='title' placeholder="제목" autocomplete="off" />
<input class='contents' name='content' placeholder="내용" autocomplete="off" />
<button class='addBtn' type='button'>제출</button>
<div class='error'></div>
` ;
}
setEvent () {
const { addItem , currentTime , inputFocus } = this . props ;
let inputCheck = () => {
let title = document . querySelector ( '.title' ). value ;
let contents = document . querySelector ( '.contents' ). value ;
let error = document . querySelector ( '.error' );
let date = currentTime ();
if ( title == '' || contents == '' ) {
// error 처리
error . innerHTML = '입력 값을 확인해 주세요' ;
} else {
// state 추가
addItem ({ title : title , contents : contents , date : date });
// 추가 후 focus
inputFocus ( '.title' );
}
};
// 초기 focus
inputFocus ( '.title' );
// 클릭 이벤트
this . addEvent ( 'click' , '.addBtn' , () => {
inputCheck ();
});
// enter키 이벤트
this . addEvent ( 'keyup' , '.title, .contents' , e => {
if ( e . key === 'Enter' ) {
inputCheck ();
}
});
}
}
예시) 제목이나 내용이 비어있을 경우