完成品
コード全文
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script>
const state = {
todoList: [],
formText: '',
};
const render = () => {
document.getElementById('main').innerHTML = `
<div>
<div>
<input
type="text"
onchange="handleEvents({type: 'INPUT_TEXT', event})"
value="${state.formText}"
/>
<input type="submit" onclick="handleEvents({type: 'SUBMIT'})"/>️
</div>
<hr/>
<table id="table">
${state.todoList.length > 0 ? `
<thead>
<tr>
<th/>
<th>memo</th>
<th>deadline</th>
<th/>
<th/>
</tr>
</thead>
` : ``}
<tbody>
${state.todoList.map((todo, key) => (`
<tr>
<td>
<button onclick="handleEvents({key: ${key}, type: 'CHECK'})">
check
</button>
<span>${todo.isChecked ? '✅' : ''}</span>
</td>
<td><span>${todo.text}</span></td>
<td>
<input
type="date"
onblur="handleEvents({key: ${key}, type: 'CHANGE_DATE', event})"
value="${todo.deadlineDate}"
/>
</td>
<td>
<input
type="time"
onchange="handleEvents({key: ${key}, type: 'CHANGE_TIME', event})"
value="${todo.deadlineTime}"
/>
</td>
<td>
<button onclick="handleEvents({key: ${key}, type: 'DELETE'})">
delete
</button>
</td>
</tr>
`)).join('')}
</tbody>
</table>
<hr/>
<div>
<button onclick="handleEvents({type: 'SORT'})">sort by deadline</button>
</div>
</div>
`;
};
const handleEvents = (action) => {
switch (action.type) {
case 'INPUT_TEXT':
state.formText = action.event.target.value;
break;
case 'SUBMIT':
document.activeElement.blur();
if (state.formText === '') {
break;
};
const date = new Date();
state.todoList.push({
text: state.formText,
isChecked: false,
createdAt: date.getTime(),
deadlineDate: '',
deadlineTime: '',
});
state.formText = '';
break;
case 'CHECK':
state.todoList[action.key] = {
...state.todoList[action.key],
isChecked: state.todoList[action.key].isChecked ? false : true,
};
break;
case 'DELETE':
state.todoList.splice(action.key, 1);
break;
case 'CHANGE_DATE':
state.todoList[action.key].deadlineDate = action.event.target.value;
break;
case 'CHANGE_TIME':
state.todoList[action.key].deadlineTime = action.event.target.value;
break;
case 'SORT':
const parseDateTime = (todo) => (
todo.deadlineDate ?
new Date(`${todo.deadlineDate} ${todo.deadlineTime}`) :
new Date(todo.createdAt)
);
state.todoList.sort((before, after) => parseDateTime(before) - parseDateTime(after));
default:
break;
}
render();
};
window.onload = render;
</script>
</head>
<body>
<div id='main'></div>
</body>
</html>
説明
表題の通りCDNやフレームワーク等は使っていない。
最近はhtmlを書くだけでブラウザが勝手にカレンダーとか時計とかを表示してくれるので素晴らしい。
表題に「Reactのrenderっぽい動き」と書いたが、要点は三つで
- state: Todoリストなどの状態を保持しておく
- render: stateを画面に反映させる
- handleEvents: ユーザーの操作を受け取ってstateを更新し、再度renderする
ということ。
Reactのrenderはもちろんもっと複雑にできているが、状態管理の設計の練習くらいにはなっただろうと思う。