JSX を使用してコンポーネント システムを構築する前に、例を使用してコンポーネントの実装原理とロジックを学習しましょう。ここでは、学習例としてカルーセル コンポーネントを使用します。カルーセルの英語名は「Carousel」で、回転木馬を意味します。 前回の記事「JSX を使用してマークアップ コンポーネント スタイルを確立する」で実装したコードは、実際にはコンポーネント システムとは言えません。せいぜい、DOM の単純なカプセル化として機能し、DOM をカスタマイズできるようになります。 このカルーセル コンポーネントを作成するには、最も単純な DOM 操作から始める必要があります。まず DOM 操作を使用してカルーセル機能全体を実装し、その後、段階的にコンポーネント システムに設計する方法を検討します。
カルーセルなので当然画像を使う必要があるので、ここではUnsplashからオープンソースの画像4枚を用意しました。もちろん、自分の画像に置き換えることもできます。まず、次の 4 つの写真を ギャラリー = [ 'https://source.unsplash.com/Y8lCoTRgHPE/1142x640', 'https://source.unsplash.com/v7daTKlZzaw/1142x640', 'https://source.unsplash.com/DlkF4-dbCOU/1142x640', 'https://source.unsplash.com/8SQ6xjkxkCo/1142x640', ]; 私たちの目標は、これら 4 つの画像を回転させることです。 コンポーネントの最下層のカプセル化まず、このコンポーネントの記述を開始できるように、以前に記述したコードをカプセル化する必要があります。
このようにして、コンポーネントの基盤となるフレームワークのコードをカプセル化しました。コード例は次のとおりです。 関数createElement(type, 属性, ...children) { // 要素を作成する let element; if (typeof type === 'string') { 要素 = 新しい ElementWrapper(type); } それ以外 { 要素 = 新しいタイプ(); } // 属性をハングする for (let name in attribute) { 要素.setAttribute(名前、属性[名前]); } // すべての子要素をハングする for (let child of children) { if (typeof child === 'string') child = new TextWrapper(child); 要素.appendChild(子); } //最終的に要素はノードなので、直接返すことができます return element; } エクスポートクラスComponent { コンストラクタ() { } // 要素の属性をマウントする setAttribute(name, attribute) { this.root.setAttribute(名前、属性); } // 要素の子要素をマウントする appendChild(child) { 子をマウントします(this.root); } // 現在の要素をマウントする mountTo(parent) { 親.appendChild(this.root); } } クラスElementWrapperはComponentを拡張します{ // コンストラクタ // DOMノードを作成するconstructor(type) { 要素を作成します。 } } TextWrapperクラスはComponentを拡張します{ // コンストラクタ // DOMノードを作成するconstructor(content) { ルートディレクトリに document.createTextNode(content); } } カルーセルの実装次に、 コンポーネントを継承した後、 ここで正式にコンポーネントの開発を開始できますが、毎回 webpack を使用して手動でパッケージ化する必要がある場合は非常に面倒です。したがって、コードのデバッグを容易にするために、ここで webpack 開発サーバーをインストールしてこの問題を解決しましょう。 npm をインストール --save-dev webpack-dev-server webpack-cli 上記の結果を見ると、インストールが成功したことがわかります。 webpack サーバーの実行フォルダーを構成することをお勧めします。ここでは、パッケージ化された これを設定するには、 モジュール.エクスポート = { エントリ: './main.js', モード: '開発'、 開発サーバー: { コンテンツベース: './dist', }, モジュール: { ルール: { テスト: /\.js$/, 使用: { ローダー: 'babel-loader', オプション: プリセット: ['@babel/preset-env'], プラグイン: [['@babel/plugin-transform-react-jsx', { プラグマ: 'createElement' }]], }, }, }, ]、 }, }; Vue や React を使用したことがある人なら、ローカル デバッグ環境サーバーを起動するには npm コマンドを実行するだけでよいことをご存知でしょう。ここでクイックスタートコマンドも設定します。 { "名前": "jsx-コンポーネント", "バージョン": "1.0.0", "説明": ""、 "メイン": "index.js", 「スクリプト」: { "test": "echo \"エラー: テストが指定されていません\" && exit 1", 「開始」: 「webpack サーブ」 }, "著者": ""、 「ライセンス」: 「ISC」、 「devDependencies」: { "@babel/core": "^7.12.3", "@babel/plugin-transform-react-jsx": "^7.12.5", "@babel/プリセット環境": "^7.12.1", "バベルローダー": "^8.1.0", "webpack": "^5.4.0", "webpack-cli": "^4.2.0", "webpack-dev-server": "^3.11.0" }, 「依存関係」: {} } この方法では、次のコマンドを直接実行して、ローカル デバッグ サーバーを起動できます。 npm スタート これをオンにすると、ファイルを変更するとそれが監視され、ファイルがリアルタイムでパッケージ化されるので、デバッグに非常に便利です。上の図に示すように、リアルタイム ローカル サーバーのアドレスは ここで注意すべき点は、実行ディレクトリを dist に変更したことです。以前の main.html はルート ディレクトリに配置されていたため、localhost:8080 でこの HTML ファイルを見つけることができません。そのため、main.html を dist ディレクトリに移動し、main.js のインポート パスを変更する必要があります。 <!-- main.html コード --> <本文></本文> <script src="./main.js"></script> リンクを開くと、Carousel コンポーネントが正常にマウントされていることがわかりました。これは、コードのカプセル化に問題がないことを証明しています。 次に、カルーセル機能の実装を続けます。まず、画像データをカルーセル コンポーネントに渡す必要があります。 a = <Carousel src={gallery}/> とします。 このようにして したがって、この src にデータを個別に保存し、後でそれを使用してカルーセルの画像表示要素を生成する必要があります。 React では、要素のプロパティを格納するために 受信した属性を 次に、これらの属性を要素ノードにマウントするのではなく、クラス プロパティに保存する必要があります。したがって、コンポーネント クラスで コンポーネントがレンダリングされる前に src 属性の値を取得する必要があるため、レンダリング トリガーを CarouselクラスはComponentを拡張します{ // コンストラクタ // DOMノードを作成するconstructor() { 素晴らしい(); this.attributes = Object.create(null); } setAttribute(名前、値) { this.attributes[名前] = 値; } 与える() { コンソールにログを記録します。 document.createElement('div') を返します。 } マウントする() { 親要素に子要素を追加します。 } } 次に、実際に実行した結果を見て、画像データが取得できるかどうかを確認してみましょう。 次にこれらの写真を表示します。ここで、レンダリング メソッドを変更し、画像をレンダリングするロジックを追加する必要があります。
CarouselクラスはComponentを拡張します{ // コンストラクタ // DOMノードを作成するconstructor() { 素晴らしい(); this.attributes = Object.create(null); } setAttribute(名前、値) { this.attributes[名前] = 値; } 与える() { this.root = document.createElement('div'); for (this.attributes.src の画像) { 子要素を document.createElement('img') にします。 child.src = 画像; this.root.appendChild(子); } this.root を返します。 } マウント先(親) { 親要素に子要素を追加します。 } } このようにして、画像がページ上に正しく表示されていることを確認できます。 タイポグラフィとアニメーションまず、画像の要素はすべて img タグですが、このタグを使用すると、クリックしてドラッグするときにドラッグできます。もちろん、これは解決できますが、この問題をより簡単に解決するために、img を div に置き換えてから background-image を使用します。 デフォルトでは、div には幅も高さもないので、コンポーネントの div レイヤーに // メイン.js CarouselクラスはComponentを拡張します{ // コンストラクタ // DOMノードを作成するconstructor() { 素晴らしい(); this.attributes = Object.create(null); } setAttribute(名前、値) { this.attributes[名前] = 値; } 与える() { this.root = document.createElement('div'); this.root.addClassList('carousel'); // カルーセルクラスを追加 for (this.attributes.src の画像) { 子要素を document.createElement('div') にします。 child.backgroundImage = `url('${picture}')`; this.root.appendChild(子); } this.root を返します。 } マウント先(親) { 親要素に子要素を追加します。 } } <!-- main.html --> <ヘッド> <スタイル> .carousel > div { 幅: 500ピクセル; 高さ: 281px; 背景サイズ: 含む; } </スタイル> </head> <本文></本文> <script src="./main.js"></script> ここでは幅は 500 ピクセルですが、高さを 300 ピクセルに設定すると、画像の下部に画像が繰り返されることがわかります。これは、画像の比率が したがって、比例計算により、高さは次のようになります: 500 ÷ 1900 × 900 = 281.xxx 500\div1900\times900 = 281.xxx 500÷1900×900=281.xxx。したがって、500px の幅に対応する高さは約 281px になります。この方法では、画像を div 内で正常に表示できます。 カルーセルですべての画像を表示するのは明らかに不可能です。私たちが知っているカルーセルは、画像を 1 枚ずつ表示します。まず、画像の外側にあるカルーセル div 要素に、画像と同じ幅と高さのボックスを作成し、次に
すると、別の問題が出てきます。カルーセル画像は一般的に左右にスライドし、上下にスライドすることはほとんどありません。しかし、ここではデフォルトで画像が上から下に配置されています。したがって、ここでは写真が一列に並ぶようにレイアウトを調整する必要があります。 ここでは通常のフローを使用できるため、div に <ヘッド> <スタイル> .カルーセル{ 幅: 500ピクセル; 高さ: 281px; 空白: ラップなし; オーバーフロー: 非表示; } .carousel > div { 幅: 500ピクセル; 高さ: 281px; 背景サイズ: 含む; 表示: インラインブロック; } </スタイル> </head> <本文></本文> <script src="./main.js"></script> 次に、自動カルーセル効果を実装しましょう。その前に、これらの画像要素にいくつかのアニメーション プロパティを追加しましょう。ここでは、要素アニメーションの継続時間を制御するために
<ヘッド> <スタイル> .カルーセル{ 幅: 500ピクセル; 高さ: 281px; 空白: ラップなし; オーバーフロー: 非表示; } .carousel > div { 幅: 500ピクセル; 高さ: 281px; 背景サイズ: 含む; 表示: インラインブロック; 遷移: 0.5 秒の緩和; } </スタイル> </head> <本文></本文> <script src="./main.js"></script> 自動カルーセルを実装するアニメーション効果プロパティを使用すると、JavaScript にタイマーを追加して、3 秒ごとに画像を切り替えることができます。この問題は しかし、写真を回転させたり動かしたりするにはどうすればいいのでしょうか? HTML での移動について考えるとき、CSS のどの属性を使用して要素を移動できるか考えたことがありますか? そうです、CSS で要素を移動するために特に使用される しかし、これで移動できるのは 1 つの画像だけなので、2 回目に移動して 3 番目の画像に移動する必要がある場合は、各画像を 200% オフセットするなどする必要があります。したがって、現在のページ番号を表す値 CarouselクラスはComponentを拡張します{ // コンストラクタ // DOMノードを作成するconstructor() { 素晴らしい(); this.attributes = Object.create(null); } setAttribute(名前、値) { this.attributes[名前] = 値; } 与える() { this.root = document.createElement('div'); this.root.classList.add('カルーセル'); for (this.attributes.src の画像) { 子要素を document.createElement('div') にします。 child.style.backgroundImage = `url('${picture}')`; this.root.appendChild(子); } 電流を 0 にします。 間隔を設定する(() => { children = this.root.children; とします。 ++現在; for (let child of children) { child.style.transform = `translateX(-${100 * current}%)`; } }, 3000); this.root を返します。 } マウント先(親) { 親要素に子要素を追加します。 } } ここで問題が見つかりました。カルーセルが停止せず、左に移動し続けます。最後の画像にカルーセルする必要がある場合は、前の写真に戻る必要があります。 この問題を解決するには、数学的なトリックを使うことができます。数値を 1 から N の間で循環させたい場合は、それを n を法として計算するだけです。私たちの要素では、children の長さは 4 なので、current が 4 に達すると、4 ÷ 4 4\div4 4÷4 の余りは 0 になります。そのため、current を、current の余りを children の長さで割った値に設定するたびに、無限ループを実現できます。
このロジックを使用してカルーセルを実装すると、確かに画像が無限にループする可能性がありますが、実行して確認すると、別の問題が見つかります。最後の画像を再生した後、すぐに最初の画像にスライドすると、巻き戻し効果が表示されます。これは確かにあまり良くありません。私たちが望んでいるのは、最後の画像に到達した後、最初の画像が直接後ろに接続されることです。 それでは、一緒にこの問題を解いてみましょう。観察してみると、画面上には一度に 2 つの画像しか表示されません。したがって、実際には、これら 2 つの画像を正しい位置に移動するだけで済みます。 したがって、現在見ている画像と次の画像を見つけ、次の画像に移動するたびに次の画像を見つけて、次の画像を正しい位置に移動する必要があります。 この時点ではまだ少し混乱しているかもしれませんが、それは問題ではありません。論理を整理しましょう。 現在の画像のインデックスと次の画像のインデックスを取得します
画像が移動する距離を計算し、現在の画像の後ろに移動を待つ画像を保持します。
2枚目の写真を配置し、カルーセル効果を開始できます
次に、上記のロジックを JavaScript に変換します。 CarouselクラスはComponentを拡張します{ // コンストラクタ // DOMノードを作成するconstructor() { 素晴らしい(); this.attributes = Object.create(null); } setAttribute(名前、値) { this.attributes[名前] = 値; } 与える() { this.root = document.createElement('div'); this.root.classList.add('カルーセル'); for (this.attributes.src の画像) { 子要素を document.createElement('div') にします。 child.style.backgroundImage = `url('${picture}')`; this.root.appendChild(子); } // 現在の画像のインデックス 現在のインデックスを 0 にします。 間隔を設定する(() => { children = this.root.children; とします。 // 次の画像のインデックス nextIndex = (currentIndex + 1) % children.length; とします。 // 現在の画像のノード let current = children[currentIndex]; // 次の画像のノード let next = children[nextIndex]; // 画像アニメーションを無効にする next.style.transition = 'none'; // 次の画像を正しい位置に移動します next.style.transform = `translateX(${-100 * (nextIndex - 1)}%)`; // カルーセル効果を実行し、1フレームを16ミリ秒遅延します setTimeout(() => { // CSS でアニメーションを有効にする next.style.transition = ''; // まず現在の画像を現在の位置から移動します current.style.transform = `translateX(${-100 * (currentIndex + 1)}%)`; // 次の画像を現在表示されている位置に移動します next.style.transform = `translateX(${-100 * nextIndex}%)`; // 最後に現在の位置のインデックスを更新します 現在のインデックス = 次のインデックス; }, 16); }, 3000); this.root を返します。 } マウント先(親) { 親要素に子要素を追加します。 } } 最初に ドラッグアンドドロップカルーセルを実装する一般的に言えば、自動カルーセル機能に加えて、カルーセル コンポーネントをマウスでドラッグして回転させることもできます。それでは、この手動カルーセル機能を一緒に実装してみましょう。 自動カルーセルと手動カルーセルの間には一定の競合があるため、先ほど実装した自動カルーセル コードをコメント アウトする必要があります。次に、このカルーセル コンポーネントの下の子 (子要素)、つまりすべての画像の要素を使用して、手動ドラッグ カルーセル機能を実装できます。 ドラッグ機能は主に画像のドラッグを伴うため、画像にマウス リスニング イベントを追加する必要があります。操作手順の観点から考えると、次のような一連のロジックを思いつくことができます。 まずマウスを画像の上に移動してから、画像をクリックする必要があります。したがって、監視する必要がある最初のイベントは this.root.addEventListener('mousedown', イベント => { console.log('マウスダウン'); }); this.root.addEventListener('mousemove', イベント => { console.log('マウス移動'); }); this.root.addEventListener('mouseup', イベント => { console.log('マウスアップ'); }); 上記のコードを実行すると、マウスを画像の上に置いて移動すると、 したがって、マウスが押されたときに移動とリリースのアクションを正しく監視できるように、mousemove イベントと mouseup イベントを mousedown イベントのコールバック関数に配置する必要があります。また、マウスを離すと、mousemove と mouseup の 2 つのリスニング イベントを停止する必要があるため、それらを別々に保存する関数を使用する必要があることも考慮する必要があります。 this.root.addEventListener('mousedown', イベント => { console.log('マウスダウン'); 移動 = イベント => { console.log('マウス移動'); }; let up = イベント => { this.root.removeEventListener('mousemove', 移動); this.root.removeEventListener('mouseup', up); }; this.root.addEventListener('mousemove', 移動); this.root.addEventListener('mouseup', up); }); ここでは、マウスアップ時に mousemove イベントと mouseup イベントを削除します。これは、ドラッグするときに通常使用する基本コードです。 しかし、別の問題が見つかります。マウスをクリックしてドラッグし、放した後、画像上でマウスを再度動かすと、mousemove イベントが引き続きトリガーされます。 これは、マウスの動きが したがって、これら 2 つのイベントを this.root.addEventListener('mousedown', イベント => { console.log('マウスダウン'); 移動 = イベント => { console.log('マウス移動'); }; let up = イベント => { document.removeEventListener('mousemove', 移動); document.removeEventListener('mouseup', up); }; document.addEventListener('mousemove', 移動); document.addEventListener('mouseup', 上); }); この完全な監視メカニズムを使用して、mousemove でカルーセルの移動機能を実装することができます。この関数のロジックを整理してみましょう。 これを行うには、まずマウスの位置を知る必要があります。ここでは、mousemove の this.root.addEventListener('mousedown', イベント => { children = this.root.children; とします。 startX = event.clientX; とします。 移動 = イベント => { x = event.clientX - startX とします。 for (let child of children) { child.style.transition = 'なし'; child.style.transform = `translateX(${x}px)`; } }; let up = イベント => { document.removeEventListener('mousemove', 移動); document.removeEventListener('mouseup', up); }; document.addEventListener('mousemove', 移動); document.addEventListener('mouseup', 上); }); さて、ここで 2 つの問題が見つかりました。 最初にクリックしてドラッグすると、画像の開始位置は正しいのですが、もう一度クリックすると、画像の位置が間違っています。画像をドラッグした後、マウスボタンを放すと、画像はドラッグを終了した位置に留まります。ただし、通常のカルーセルコンポーネントでは、画像を特定の位置を超えてドラッグすると、自動的に次の画像に回転します。 これら 2 つの問題を解決するには、次のように計算できます。これは、作成しているのがカルーセル コンポーネントであるためです。現在の一般的なカルーセル コンポーネントによると、画像を画像の半分より大きい位置にドラッグすると、次の画像に回転します。位置が半分未満の場合、現在ドラッグしている画像の位置に戻ります。 このような要件に従って、現在の画像(0 から始まる)を記録する まず、マウスを動かすときに、現在の画像が開始点からどれだけ移動したかを計算する必要があります。これは N * 500 で計算できます。ここで、N は現在の画像の this.root.addEventListener('mousedown', イベント => { children = this.root.children; とします。 startX = event.clientX; とします。 移動 = イベント => { x = event.clientX - startX とします。 for (let child of children) { child.style.transition = 'なし'; child.style.transform = `translateX(${x - current * 500}px)`; } }; let up = イベント => { x = event.clientX - startX とします。 現在の値 = 現在の値 - Math.round(x / 500); for (let child of children) { child.style.transition = ''; child.style.transform = `translateX(${-current * 500}px)`; } document.removeEventListener('mousemove', 移動); document.removeEventListener('mouseup', up); }; document.addEventListener('mousemove', 移動); document.addEventListener('mouseup', 上); });
これを実行すると、ドラッグを使用して写真を回転できますが、最後の写真までドラッグすると、最後の写真の後に空白があり、最初の写真が最後の写真に接続されていないことがわかります。 その後、この機能を改善していきます。これは、実際には自動カルーセルと非常によく似ています。自動カルーセルを作成していたとき、写真をカルーセルするたびに最大 2 枚の写真しか表示されないことがわかっていました。カルーセルの幅がページに対して非常に狭いため、3 枚の写真が表示される可能性は非常に低かったです。この問題は、ユーザーが 2 枚目の写真をドラッグするのに十分なスペースがない限り発生しません。しかし、ここではこの要素については考慮しません。 ドラッグするたびに 2 つの画像しか表示されないことが確実なので、ドラッグ カルーセルも自動カルーセルのように処理できます。しかし、ここでは違いが 1 つあります。画像を自動的に回転すると、画像は左または右のいずれかの方向にのみ移動します。ただし、手動で左または右にドラッグすると、画像を任意の方向に移動できます。したがって、この機能を実装するために自動カルーセル コードを直接使用することはできません。カルーセルの最初と最後の無限ループのロジックを自分で再処理する必要があります。
この式を通じて、この時点で前の画像と次の画像のポインターを取得して、ノードでオブジェクトを取得し、CSSDOMを使用して、すべての要素を最初に変更する必要があります。 ロジック全体を整理しました。MouseMoveイベントコールバック関数コードをどのように記述するかを見てみましょう。 move = event => { x = event.clientx -startx; current = position -math.round(x/500); for([-1、0、1]のオフセットとしましょう){ pos = current + offsetとします。 //画像が配置されているインデックスを計算します pos =(pos + children.length)%children.length; console.log( 'pos'、pos); 子供[pos] .style.transition = 'none'; 子供[pos] .style.transform = `translatex($ { - pos * 500 + offset * 500 +(x%500)} px)`; } };
最後に、小さな問題があります。前の写真と次の写真に奇妙なジャンプがあることがわかります。 この問題は 整数を摂取するのと同じ効果を達成するには、ここで 実際には、MouseUpイベントでロジックを変更していません。次に、ロジックをどのように実装するかを見てみましょう。 ここで変更する必要があるのは、子供のループのコードです。ここでのロジックは、実際には基本的に移動と同じですが、ここに変更する必要がある場所がいくつかあります。 まず、遷移禁止は削除できます。これは、 これは、Match.Round()の特性のためです。250(500pxは正確に半分)であるため、絵をラウンドにする必要がある方向を計算した後、 最終的に、私たちのコードは次のようなものです: LET UP = event => { x = event.clientx -startx; position = position -math.round(x/500); for([0、-math.sign(math.round(x / 500)-x + 250 * math.sign(x))のオフセットを){ pos = position + offsetとします。 //画像が配置されているインデックスを計算します pos =(pos + children.length)%children.length; 子供[pos] .style.transition = ''; 子供[pos] .style.transform = `translatex($ { - pos * 500 + offset * 500} px)`; } document.removeEventListener('mousemove', 移動); document.removeeventlistener( 'mouseup'、up); }; UP機能を変更した後、このマニュアルカルーセルコンポーネントを本当に完成させました。 これは、JSXを使用してCarousel Carouselコンポーネントを実装するための詳細については、以下の記事を検索してください。 以下もご興味があるかもしれません:
|
<<: MySql バージョンの問題に対する完璧なソリューション sql_mode=only_full_group_by
ソフトウェアバージョンウィンドウズ: ウィンドウズ10 MySQL: mysql-8.0.17-wi...
HTML ファイルとは何ですか? HTML は Hyper Text Markup Language...
目次MySQLデータベースの名前を変更する方法最初の方法: データベースの名前を変更することは非推奨...
MySQL Select ステートメントはどのように実行されますか?最近、Geek Time で D...
目次1. Ubuntuソースの変更2. MySQLをインストールする3. 新しいユーザーを作成し、権...
仮想マシンは使用中であるか、接続できません次のようなエラーが報告された場合解決まずこのページにアクセ...
序文scp は secure copy の略です。scp は、Linux システムの ssh ログイ...
データベースでcreate tableステートメントを実行する テーブル `sys_acl` を作成...
HTML ウェブ ページのハイパーリンク タグの学習チュートリアル リンク タグの属性 リンクは、ウ...
<br />最近、UCDChina は「インターフェース上のテキストに注意を払う」という...
目次1. Dockerをインストールする2. GitLabをインストールする3. GitLabを初期...
[LeetCode] 196.重複したメールを削除するSQL クエリを記述して、Person とい...
カバーインデックスとは何ですか?クエリで使用されるすべてのフィールドを含むインデックスを作成すること...
データベース内のトランザクションとロックを表示するための一般的なステートメントトランザクションの待機...
情報の最適化と改良は常にデザインの最初のステップです。 「これは百度アライアンスユーザーエクスペリエ...