You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ja/3-terrarium/3-intro-to-DOM-and-closures/README.md

16 KiB

テラリウムプロジェクト パート3: DOM操作とクロージャ

DOMとクロージャ

スケッチノート: Tomomi Imura

講義前クイズ

講義前クイズ

はじめに

DOMDocument Object Modelの操作は、ウェブ開発の重要な側面です。MDNによると、「Document Object Model (DOM) は、ウェブ上のドキュメントの構造と内容を構成するオブジェクトのデータ表現です。」DOM操作の課題は、しばしばJavaScriptフレームワークを使用してDOMを管理する動機となりますが、ここではバニラJavaScriptを使って自力で管理します

さらに、このレッスンではJavaScriptのクロージャの概念を紹介します。クロージャとは、ある関数の中に別の関数が閉じ込められており、内側の関数が外側の関数のスコープにアクセスできる仕組みのことです。

JavaScriptのクロージャは広範で複雑なトピックです。このレッスンでは、基本的なアイデアに触れるだけです。このテラリウムのコード内で、クロージャ内側の関数と外側の関数が構築され、内側の関数が外側のスコープにアクセスできる仕組みを見つけることができます。詳細については、豊富なドキュメントをご覧ください。

このレッスンでは、クロージャを使ってDOMを操作します。

DOMを木構造として考えてみてください。これは、ウェブページのドキュメントを操作するためのすべての方法を表しています。さまざまなAPIアプリケーションプログラムインターフェースが作成されており、プログラマーは選んだプログラミング言語を使ってDOMにアクセスし、編集、変更、再配置、その他の管理を行うことができます。

DOMツリーの表現

DOMとそれを参照するHTMLマークアップの表現。Olfa Nasraouiより

このレッスンでは、JavaScriptを作成して、ユーザーがページ上の植物を操作できるようにすることで、インタラクティブなテラリウムプロジェクトを完成させます。

前提条件

テラリウムのHTMLとCSSを作成済みである必要があります。このレッスンの終わりまでに、植物をドラッグしてテラリウムに出し入れできるようになります。

タスク

テラリウムフォルダ内に、新しいファイルscript.jsを作成します。そのファイルを<head>セクションにインポートします:

	<script src="./script.js" defer></script>

注: 外部JavaScriptファイルをHTMLファイルにインポートする際には、deferを使用して、HTMLファイルが完全に読み込まれた後にJavaScriptが実行されるようにします。また、async属性を使用して、HTMLファイルの解析中にスクリプトを実行することもできますが、今回の場合、ドラッグスクリプトを実行する前にHTML要素が完全に利用可能である必要があります。


DOM要素

最初に行うべきことは、DOM内で操作したい要素への参照を作成することです。今回の場合、サイドバーにある14個の植物が対象です。

タスク

dragElement(document.getElementById('plant1'));
dragElement(document.getElementById('plant2'));
dragElement(document.getElementById('plant3'));
dragElement(document.getElementById('plant4'));
dragElement(document.getElementById('plant5'));
dragElement(document.getElementById('plant6'));
dragElement(document.getElementById('plant7'));
dragElement(document.getElementById('plant8'));
dragElement(document.getElementById('plant9'));
dragElement(document.getElementById('plant10'));
dragElement(document.getElementById('plant11'));
dragElement(document.getElementById('plant12'));
dragElement(document.getElementById('plant13'));
dragElement(document.getElementById('plant14'));

ここで何が起こっているのでしょうかドキュメントを参照し、そのDOMを調べて特定のIdを持つ要素を見つけています。HTMLの最初のレッスンで、各植物画像に個別のIdid="plant1")を付けたことを思い出してください。その作業がここで役立ちます。各要素を特定した後、それをdragElementという関数に渡します。この関数は後で作成します。これにより、HTML内の要素がドラッグ可能になります。

なぜ要素をIdで参照するのでしょうかCSSクラスで参照するのではなくCSSに関する前回のレッスンを振り返ってみてください。


クロージャ

次に、dragElementクロージャを作成します。これは、内側の関数を囲む外側の関数です今回の場合、内側の関数は3つあります

クロージャは、1つ以上の関数が外側の関数のスコープにアクセスする必要がある場合に便利です。以下はその例です

function displayCandy(){
	let candy = ['jellybeans'];
	function addCandy(candyType) {
		candy.push(candyType)
	}
	addCandy('gumdrops');
}
displayCandy();
console.log(candy)

この例では、displayCandy関数が、既存の配列に新しいキャンディタイプを追加する関数を囲んでいます。このコードを実行すると、candy配列は未定義になります。これは、candyがローカル変数(クロージャ内のローカル)であるためです。

candy配列をアクセス可能にするにはどうすればよいでしょうか?配列をクロージャの外側に移動してみてください。これにより、配列はグローバルになり、クロージャのローカルスコープに限定されなくなります。

タスク

script.js内の要素宣言の下に、次の関数を作成します:

function dragElement(terrariumElement) {
	//set 4 positions for positioning on the screen
	let pos1 = 0,
		pos2 = 0,
		pos3 = 0,
		pos4 = 0;
	terrariumElement.onpointerdown = pointerDrag;
}

dragElementは、スクリプトの冒頭で宣言されたterrariumElementオブジェクトを取得します。そして、関数に渡されたオブジェクトのローカル位置を0に設定します。これらは、ドラッグ&ドロップ機能を各要素に追加する際に操作されるローカル変数です。テラリウムはこれらのドラッグされた要素によって埋められるため、配置場所を追跡する必要があります。

さらに、この関数に渡されたterrariumElementは、pointerdownイベントを割り当てられます。これは、ウェブAPIの一部であり、DOM管理を支援するために設計されています。onpointerdownは、ボタンが押されたとき、または今回の場合はドラッグ可能な要素がタッチされたときに発火します。このイベントハンドラは、いくつかの例外を除いて、ウェブおよびモバイルブラウザの両方で動作します。

イベントハンドラonclickは、クロスブラウザでのサポートがはるかに多いですが、ここではなぜ使用しないのでしょうか?作成しようとしている画面操作の正確なタイプについて考えてみてください。


Pointerdrag関数

terrariumElementはドラッグ可能な状態になりました。onpointerdownイベントが発火すると、pointerDrag関数が呼び出されます。この関数を次の行の下に追加します:terrariumElement.onpointerdown = pointerDrag;

タスク

function pointerDrag(e) {
	e.preventDefault();
	console.log(e);
	pos3 = e.clientX;
	pos4 = e.clientY;
}

いくつかのことが起こります。まず、e.preventDefault();を使用して、通常pointerdownで発生するデフォルトイベントが発生しないようにします。これにより、インターフェースの動作をより細かく制御できます。

スクリプトファイルを完全に構築した後、この行を削除して試してみてください。何が起こるでしょうか?

次に、ブラウザウィンドウでindex.htmlを開き、インターフェースを検査します。植物をクリックすると、eイベントがどのようにキャプチャされるかを見ることができます。このイベントを掘り下げて、1回のpointerdownイベントでどれだけの情報が収集されるかを確認してください。

次に、ローカル変数pos3pos4e.clientXに設定される方法に注目してください。これらの値は、クリックまたはタッチした瞬間の植物のx座標とy座標をキャプチャします。植物をクリックしてドラッグする際の動作を細かく制御する必要があるため、その座標を追跡します。

なぜこのアプリ全体が1つの大きなクロージャで構築されているのか、より明確になってきましたかもしそうでなければ、14個のドラッグ可能な植物それぞれのスコープをどのように維持するか考えてみてください。

初期関数を完成させるために、pos4 = e.clientYの下に2つのポインターイベント操作を追加します

document.onpointermove = elementDrag;
document.onpointerup = stopElementDrag;

これで、植物をポインターと一緒にドラッグできるようになり、植物の選択を解除するとドラッグジェスチャーが停止します。onpointermoveonpointerupは、onpointerdownと同じAPIの一部です。インターフェースは現在エラーをスローしますが、これはelementDragstopElementDrag関数がまだ定義されていないためです。次にこれらを構築します。

elementDragとstopElementDrag関数

クロージャを完成させるために、植物をドラッグしたときとドラッグを停止したときに何が起こるかを処理する2つの内部関数を追加します。目指す動作は、いつでもどの植物でもドラッグでき、画面上のどこにでも配置できることです。このインターフェースは非常に自由度が高くドロップゾーンなどはありません、植物を追加、削除、再配置することで、テラリウムを自由にデザインできます。

タスク

pointerDragの閉じ中括弧の直後にelementDrag関数を追加します:

function elementDrag(e) {
	pos1 = pos3 - e.clientX;
	pos2 = pos4 - e.clientY;
	pos3 = e.clientX;
	pos4 = e.clientY;
	console.log(pos1, pos2, pos3, pos4);
	terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px';
	terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px';
}

この関数では、冒頭で設定したローカル変数1〜4を大幅に編集します。ここで何が起こっているのでしょうか

ドラッグ中に、pos1pos3(以前にe.clientXとして設定)から現在のe.clientX値を引いた値に再割り当てします。同様の操作をpos2にも行います。その後、pos3pos4を要素の新しいX座標とY座標にリセットします。これらの変更をドラッグ中にコンソールで確認できます。その後、植物のCSSスタイルを操作して、新しい位置に基づいて植物の新しい位置を設定します。これには、オフセットとこれらの新しい位置を比較して植物の上部と左側のX座標とY座標を計算します。

offsetTopoffsetLeftは、親要素に基づいて要素の位置を設定するCSSプロパティです。親要素はstatic以外の位置に設定されている必要があります。

これらの位置の再計算により、テラリウムとその植物の動作を微調整できます。

タスク

インターフェースを完成させる最後のタスクは、elementDragの閉じ中括弧の後にstopElementDrag関数を追加することです:

function stopElementDrag() {
	document.onpointerup = null;
	document.onpointermove = null;
}

この小さな関数は、onpointeruponpointermoveイベントをリセットします。これにより、植物の進行を再開するか、新しい植物をドラッグし始めることができます。

これらのイベントをnullに設定しないとどうなるでしょうか

これでプロジェクトが完成しました!

🥇おめでとうございます!美しいテラリウムが完成しました! 完成したテラリウム


🚀チャレンジ

クロージャに新しいイベントハンドラを追加して、植物にさらに何かをさせてみましょう。たとえば、植物をダブルクリックして最前面に持ってくるなどです。創造力を発揮してください!

講義後クイズ

講義後クイズ

復習と自己学習

画面上の要素をドラッグするのは一見簡単そうに見えますが、これを実現する方法は多岐にわたり、求める効果によっては多くの落とし穴があります。実際、ドラッグドロップAPIというものがあり、試してみることができます。このモジュールでは、求める効果が少し異なるため使用しませんでしたが、自分のプロジェクトでこのAPIを試してみてください。

ポインターイベントに関する詳細は、W3CドキュメントMDNウェブドキュメントで確認できます。

常にCanIUse.comを使用してブラウザの互換性を確認してください。

課題

DOMを使ったさらなる作業


免責事項:
この文書はAI翻訳サービスCo-op Translatorを使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があります。元の言語で記載された文書が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤解釈について、当社は責任を負いません。