実施条件
[JavaScript][L4] コンテンツ(div>ul>li)の生成機能を共通化(コンポーネント化)するを理解していること
環境
MacBook Pro (2.3 GHz 8コアIntel Core i9)
macOS 14.0(23A344)
Homebrew 4.3.8
gh 2.52.0
ソースコード外観
HTML
index.html
<!DOCTYPE html>
<html>
<head>
<title>TODO(JS)</title>
<meta charset="UTF-8" />
</head>
<body>
<div class="input-area">
<input id="add-text" placeholder="TODOを入力" />
<button id="add-button">追加</button>
</div>
<div class="incomplete-area">
<p class="title">未完了のTODO</p>
<ul id="incomplete-list">
<!-- // 完成系の例としてliタグ以下を作成している
<li>
<div class="list-row">
<p class="todo-item">TODOです</p>
<button>完了</button>
<button>削除</button>
</div>
</li> -->
</ul>
</div>
<div class="complete-area">
<p class="title">完了したTODO</p>
<ul id="complete-list">
<!-- // 完成系の例としてliタグ以下を作成している
<li>
<div class="list-row">
<p class="todo-item">TODOでした</p>
<button>戻す</button>
</div>
</li> -->
</ul>
</div>
<script src="src/index.js"></script>
</body>
</html>
JavaScript
index.js
import "./styles.css";
const onClickAdd = () => {
// テキストボックスの値を取得し、初期化する
const inputText = document.getElementById("add-text").value;
document.getElementById("add-text").value = "";
// 未完了リストに追加
createIncompleteTodo(inputText);
};
// 渡された引数を基に未完了のTODOを作成する関数
const createIncompleteTodo = (todo) => {
// li生成
const li = document.createElement("li");
// div生成
const div = document.createElement("div");
div.className = "list-row";
// p生成
const p = document.createElement("p");
p.className = "todo-item";
p.innerText = todo;
// button(完了)タグ生成
const completeButton = document.createElement("button");
completeButton.innerText = "完了";
completeButton.addEventListener("click", () => {
// 押された完了ボタンの親にあるliタグ配下の完了ボタンと削除ボタンを削除
const moveTarget = completeButton.closest("li");
completeButton.nextElementSibling.remove();
completeButton.remove();
// 戻すボタンを生成してdivタグ配下に設定
const backButton = document.createElement("button");
backButton.innerText = "戻す";
backButton.addEventListener("click", () => {
// TODOの内容を取得し、未完了リストに追加
const todoText = backButton.previousElementSibling.innerText;
createIncompleteTodo(todoText);
// 押された戻すボタンの親にあるliタグを削除
backButton.closest("li").remove();
});
moveTarget.firstElementChild.appendChild(backButton);
// 完了リストに移動
document.getElementById("complete-list").appendChild(moveTarget);
});
// button(削除)タグ生成
const deleteButton = document.createElement("button");
deleteButton.innerText = "削除";
deleteButton.addEventListener("click", () => {
// 押された削除ボタンの親にあるliタグを未完了リストから削除
const deleteTarget = deleteButton.closest("li");
document.getElementById("incomplete-list").removeChild(deleteTarget);
});
// liタグの子要素に各要素を設定
div.appendChild(p);
div.appendChild(completeButton);
div.appendChild(deleteButton);
li.appendChild(div);
// id="incomplete-list"の`ul`タグに子要素を設定した`li`タグを追加
document.getElementById("incomplete-list").appendChild(li);
};
document.getElementById("add-button").addEventListener("click", onClickAdd);
手順
-
戻す
ボタン(backButton
)が押された際に呼び出す関数を用意するindex.js// button(完了)タグ生成 const completeButton = document.createElement("button"); completeButton.innerText = "完了"; completeButton.addEventListener("click", () => { // 押された完了ボタンの親にあるliタグ配下の完了ボタンと削除ボタンを削除 const moveTarget = completeButton.closest("li"); completeButton.nextElementSibling.remove(); completeButton.remove(); // 戻すボタンを生成してdivタグ配下に設定 const backButton = document.createElement("button"); backButton.innerText = "戻す"; + backButton.addEventListener("click", () => { + }); moveTarget.firstElementChild.appendChild(backButton); // 完了リストに移動 document.getElementById("complete-list").appendChild(moveTarget); });
- TODOの内容を取得し、未完了リストに追加する
previousElementSibling
はnextElementSibling
の逆で、HTMLの前(コードで上では上部)の要素を指すindex.js// button(完了)タグ生成 const completeButton = document.createElement("button"); completeButton.innerText = "完了"; completeButton.addEventListener("click", () => { // 押された完了ボタンの親にあるliタグ配下の完了ボタンと削除ボタンを削除 const moveTarget = completeButton.closest("li"); completeButton.nextElementSibling.remove(); completeButton.remove(); // 戻すボタンを生成してdivタグ配下に設定 const backButton = document.createElement("button"); backButton.innerText = "戻す"; backButton.addEventListener("click", () => { + // TODOの内容を取得し、未完了リストに追加 + const todoText = backButton.previousElementSibling.innerText; + createIncompleteTodo(todoText); }); moveTarget.firstElementChild.appendChild(backButton); // 完了リストに移動 document.getElementById("complete-list").appendChild(moveTarget); });
- 押された戻すボタンの親にある
li
タグを削除index.js// button(完了)タグ生成 const completeButton = document.createElement("button"); completeButton.innerText = "完了"; completeButton.addEventListener("click", () => { // 押された完了ボタンの親にあるliタグ配下の完了ボタンと削除ボタンを削除 const moveTarget = completeButton.closest("li"); completeButton.nextElementSibling.remove(); completeButton.remove(); // 戻すボタンを生成してdivタグ配下に設定 const backButton = document.createElement("button"); backButton.innerText = "戻す"; backButton.addEventListener("click", () => { // TODOの内容を取得し、未完了リストに追加 const todoText = backButton.previousElementSibling.innerText; createIncompleteTodo(todoText); + // 押された戻すボタンの親にあるliタグを削除 + backButton.closest("li").remove(); }); moveTarget.firstElementChild.appendChild(backButton); // 完了リストに移動 document.getElementById("complete-list").appendChild(moveTarget); });
Tips
戻す
button
タグから見ると、p
タグがpreviousElementSibling
index.html
<li>
<div class="list-row">
<p class="todo-item">TODOでした</p>
<button>戻す</button>
</div>
</li>
完了
button
タグから見ると、削除
button
タグがnextElementSibling
index.html
<li>
<div class="list-row">
<p class="todo-item">TODOです</p>
<button>完了</button>
<button>削除</button>
</div>
</li>