ホームページ > ウェブフロントエンド > jsチュートリアル > Vanilla JavaScriptのMVC設計パターン

Vanilla JavaScriptのMVC設計パターン

Lisa Kudrow
リリース: 2025-02-16 12:22:10
オリジナル
568 人が閲覧しました

The MVC Design Pattern in Vanilla JavaScript

コアポイント

  • MVC(Model-View-Controller)設計パターンは、懸念を明確に分離することにより、保守性と読みやすさを高めるためにJavaScriptコードを整理するための強力な方法です。
  • 特定の実装を課す可能性のあるフレームワークとは異なり、MVCパターンは、開発者がアプリケーションをより簡単に適応およびスケーリングできるようにする柔軟な構造を提供します。
  • ペンギンのデモンストレーションを使用して、ネイティブJavaScriptにMVCを適用して、ユーザーの相互作用、データ管理、UIの更新を体系的に処理する方法を示しています。
  • MVCパターンの持続性と適応性により、プログラミングスキルを厳密でスケーラブルな方法で磨きたい開発者にとって貴重な資産となります。
  • MVCパターンの主要なコンポーネントには、データを管理するためのモデル、ディスプレイのビュー、およびユーザーの入力とアプリケーション出力を調整するためのコントローラーが含まれます。
  • この記事は、クリーンなコードの重要性とフレームワークによる依存関係のロックを回避することを強調し、アプリケーションが成長して発展するにつれてコードの管理可能性とスケーラビリティを維持するための戦略としてMVCを使用することを提唱しています。
設計パターンは、多くの場合、一般的なフレームワークに統合されます。たとえば、Model-View-Controller(MVC)の設計パターンはどこにでもあります。 JavaScriptでは、フレームワークをデザインパターンから分離することは困難です。多くの場合、特定のフレームワークには、このデザインパターンの独自の解釈が付属します。フレームには視点が付いており、各フレームは何らかの形で考えるように強制されます。

The MVC Design Pattern in Vanilla JavaScript 最新のフレームワークMVCモデルの特定の実装方法を決定します。すべての説明が異なる場合、これは混乱を招く可能性があり、それによりノイズと混乱を加えます。いずれかのコードベースが複数のフレームワークを採用すると、イライラする混乱が発生します。私の心の問題は、より良い方法があるかということです。

MVCパターンはクライアントフレームワークに適していますが、最新のフレームワークは変更されます。今日の近代化は時間とともに死にます。この場合、私は代替案を探求し、ちょっとした規律が私たちを連れて行くことができる場所を見たいと思います。

現代のjavascriptを読んで、javascriptの絶えず変化する世界に遅れないようにしてください!この本を読むMVCモデル自体は数十年前にさかのぼることができます。これにより、プログラミングスキルへの投資に値するデザインパターンになります。 MVCモードは、独立して存在できるモードです。問題は、これがどこまで私たちを連れて行くことができるかということです。

待って、これは別のフレームワークですか? The MVC Design Pattern in Vanilla JavaScript

まず、この一般的な誤解を排除したいと思います。デザインパターンはフレームワークではありません。設計パターンは、コードの問題を解決する厳密な方法です。これには特定のスキルレベルが必要であり、プログラマーに責任を負います。デザインパターンは、懸念を分離し、クリーンコードの書き込みを促進します。

フレームは、デザインパターンに従う必要がないため、異なります。フレームワークとパターンを区別する1つの方法は、ハリウッドの原則を探すことです。ハリウッドの原則は、「私たちに電話しないでください、あなたがそれを使用することを決定するためにいつでも依存しています。フレームワークはハリウッドによく似ており、何をすべきか、どうすればよいかを決めることはできません。実際、開発者は俳優のようで、行動を求められたときにスクリプトに従っています。

クライアントフレームワークを避けるための多くの正当な理由があります:

  • フレームワークは、ソリューションに複雑さとリスクを追加します
  • 依存関係ロックに遭遇します。これにより、コードの維持が困難になります。
  • 新しい人気フレームワークの出現により、既存のレガシーコードを書き換えることは困難です
mvcモード

MVCデザインパターンは、1970年代および1980年代のXerox SmallTalk Research Projectから生まれました。これは、フロントエンドグラフィカルユーザーインターフェイスの時間テストモードです。このパターンはデスクトップアプリケーションからのものですが、Webアプリケーションにも適していることが証明されています。

そのコアは、MVC設計パターンが懸念の明確な分離についてであることです。目的は、ソリューションを明確で理解しやすくすることです。特定の変更を行いたいプログラマは、適切な場所を簡単に見つけることができます。

ペンギンデモ

ペンギン!かわいくて毛皮のような、地球上で最もかわいい生き物の1つ。実際、彼らは17種類のペンギンがあり、すべてが南極の環境に住んでいるわけではありません。

ペンギンのデモを作る時が来ました!ページにいくつかの種を示すデッキを見せます。このために、MVCデザインパターンと少し規律を使用したいと思います。極端なプログラミング方法を使用して、ユニットテストと簡単な方法を使用して、手元の問題を解決します。最後に、それぞれが独自のデータとプロフィール写真を備えたいくつかのペンギンを閲覧できるはずです。

この例の終わりまでに、純粋なJavaScriptでMVCデザインパターンを使用するのに十分なことを学ぶべきでした。パターン自体はテストが非常に簡単であるため、優れたユニットテストが予想されます。

クロスブラウザーの互換性の理由については、このデモでES5に固執します。実証済みの言語機能をこの永続的なデザインパターンと組み合わせて使用​​することは理にかなっています。

準備はできていますか?待って見てみましょう。

skeleton

デモは、コントローラー、ビュー、モデルの3つの主要な部分で構成されます。各セクションには、解決する必要がある独自の懸念と問題があります。

以下は、その外観の視覚化です:

The MVC Design Pattern in Vanilla JavaScript Penguincontrollerはイベントを処理し、ビューとモデルの間の仲介者です。ユーザーがアクションを実行したときに何が起こるかを計算します(たとえば、ボタンをクリックしたり、キーを押したりします)。クライアント固有のロジックをコントローラーに配置できます。やるべきことがたくさんある大規模なシステムでは、モジュールに分解できます。コントローラーは、イベントのエントリポイントであり、ビューとデータの間の唯一のメディエーターです。

ペンギンビューはdomを気にします。 DOMは、HTML操作を実行するために使用するブラウザAPIです。 MVCでは、ビューを除いて変更domの一部はありません。ビューはユーザーイベントを添付できますが、イベントの処理問題をコントローラーに残します。ビューの主なコマンドは、ユーザーが画面に表示するステータスを変更することです。このデモンストレーションでは、ViewはDOM操作に純粋なJavaScriptを使用します。

PenguinModelはデータを気にします。クライアントJavaScriptでは、これはAjaxを意味します。 MVCパターンの利点の1つは、サーバー側のAjaxコール用の単一の場所があることです。これにより、ソリューションに精通していない他のプログラマーが開始することが容易になります。この設計パターンのモデルは、サーバーのJSONまたはオブジェクトのみを気にしています。

1つのアンチパターンは、この懸念のこの固有の分離に反しています。たとえば、モデルはHTMLを気にしてはなりません。ビューはAjaxを気にしてはなりません。コントローラーは、実装の詳細を心配することなく、メディエーターとして機能する必要があります。

このパターンを使用すると、開発者は最初は善意を持っていますが、懸念を漏らします。すべてをWebコンポーネントに変えて混乱に陥るのは魅力的です。機能とユーザー指向の懸念に焦点を当てます。ただし、機能的な懸念は機能的な懸念とは異なります。

プログラミングで私が気に入っているのは、機能的な懸念を明確に分離することです。個々のプログラミングの問題は一貫して解決されます。これにより、コードを読むときに理解しやすくなります。目的は、他の人がプラスの貢献をすることができるように、わかりやすいコードを書くことです。

あなたが見て触れることができる本当の例がなければ、それは良いデモではありません。言うまでもなく、ここにペンギンのデモを示すCodepenがあります:

SitePoint(@SitePoint)を表示すると、CodePenでペンギンのデモをペンします。

私は十分に言った、今度はコードを書く時が来た。

コントローラー

ビューとモデルは、コントローラーが使用する2つのコンポーネントです。コントローラーには、コンストラクターでジョブを行うために必要なすべてのコンポーネントが含まれています。

<code>var PenguinController = function PenguinController(penguinView, penguinModel) {
  this.penguinView = penguinView;
  this.penguinModel = penguinModel;
};
</code>
ログイン後にコピー
ログイン後にコピー
コンストラクターは制御の反転を使用し、この方法でモジュールを注入します。このモードを使用すると、高度な契約を満たすコンポーネントを注入できます。コードを抽象化し、詳細を実装する素晴らしい方法と考えてください。このパターンを使用すると、純粋なJavaScriptでクリーンコードを作成できます。

ユーザーイベントは接続され、この方法で処理されます。

このイベントは、現在のターゲットを使用して、国家をDOMに保存することに注意してください。この場合、DOMはその現在のステータスについてすべてを教えてくれます。 DOMの現在のステータスは、ユーザーがブラウザで見るものです。コントローラーがステータスを変更しない限り、ステータスデータをDOM自体に保存できます。
<code>PenguinController.prototype.initialize = function initialize() {
  this.penguinView.onClickGetPenguin = this.onClickGetPenguin.bind(this);
};

PenguinController.prototype.onClickGetPenguin = function onClickGetPenguin(e) {
  var target = e.currentTarget;
  var index = parseInt(target.dataset.penguinIndex, 10);

  this.penguinModel.getPenguin(index, this.showPenguin.bind(this));
};
</code>
ログイン後にコピー
ログイン後にコピー

イベントがトリガーされた後、コントローラーはデータを取得し、次に何が起こるかを説明します。 this.showpenguin()コールバックは興味深いものです:

コントローラーは各ペンギンのインデックスを計算し、それをレンダリングするビューを伝えます。モデルからデータを取得し、ビューが理解し、気にかけているオブジェクトに変換します。
<code>PenguinController.prototype.showPenguin = function showPenguin(penguinModelData) {
  var penguinViewModel = {
    name: penguinModelData.name,
    imageUrl: penguinModelData.imageUrl,
    size: penguinModelData.size,
    favoriteFood: penguinModelData.favoriteFood
  };

  penguinViewModel.previousIndex = penguinModelData.index - 1;
  penguinViewModel.nextIndex = penguinModelData.index + 1;

  if (penguinModelData.index === 0) {
    penguinViewModel.previousIndex = penguinModelData.count - 1;
  }

  if (penguinModelData.index === penguinModelData.count - 1) {
    penguinViewModel.nextIndex = 0;
  }

  this.penguinView.render(penguinViewModel);
};
</code>
ログイン後にコピー
ログイン後にコピー

以下は、ペンギンのときの幸せな道を示すユニットテストです。

<code>var PenguinController = function PenguinController(penguinView, penguinModel) {
  this.penguinView = penguinView;
  this.penguinModel = penguinModel;
};
</code>
ログイン後にコピー
ログイン後にコピー

PenguinviewMockは、実際の実装と同じ契約を結んでいます。これにより、ユニットテストを作成してアサーションを作成できます。アサーションはノードアサーションから来ており、チャイアサーションにも存在します。これにより、ノードおよびブラウザで実行できるテストを作成できます。

コントローラーは実装の詳細を気にしないことに注意してください。 This.render()など、ビューが提供する契約を使用します。それは、クリーンコードを書くために必要な規律です。コントローラーは、すべてのコンポーネントがそれが言うことを行うことができると信頼することができます。これにより、透明性が向上し、コードの読み取りが容易になります。

view

ビューは、DOM要素と接続イベントのみを気にしています。

<code>PenguinController.prototype.initialize = function initialize() {
  this.penguinView.onClickGetPenguin = this.onClickGetPenguin.bind(this);
};

PenguinController.prototype.onClickGetPenguin = function onClickGetPenguin(e) {
  var target = e.currentTarget;
  var index = parseInt(target.dataset.penguinIndex, 10);

  this.penguinModel.getPenguin(index, this.showPenguin.bind(this));
};
</code>
ログイン後にコピー
ログイン後にコピー
ユーザーが見たステータスを変更すると、実装は次のとおりです。

その主な関心事は、ビューモデルデータをHTMLに変換し、状態を変更することであることに注意してください。 2つ目は、クリックイベントを接続し、コントローラーをエントリポイントとして機能させることです。ステータスが変更された後、イベントハンドラーがDOMに接続されます。このテクノロジーは、一度にイベント管理を処理します。
<code>PenguinController.prototype.showPenguin = function showPenguin(penguinModelData) {
  var penguinViewModel = {
    name: penguinModelData.name,
    imageUrl: penguinModelData.imageUrl,
    size: penguinModelData.size,
    favoriteFood: penguinModelData.favoriteFood
  };

  penguinViewModel.previousIndex = penguinModelData.index - 1;
  penguinViewModel.nextIndex = penguinModelData.index + 1;

  if (penguinModelData.index === 0) {
    penguinViewModel.previousIndex = penguinModelData.count - 1;
  }

  if (penguinModelData.index === penguinModelData.count - 1) {
    penguinViewModel.nextIndex = 0;
  }

  this.penguinView.render(penguinViewModel);
};
</code>
ログイン後にコピー
ログイン後にコピー
これをテストするために、要素が更新されていることを確認でき、ステータスを変更しました。

これは、すべての主要な問題、状態の変更、および接続イベントを解決します。しかし、データはどこから来るのでしょうか?

モデル
<code>var PenguinViewMock = function PenguinViewMock() {
  this.calledRenderWith = null;
};

PenguinViewMock.prototype.render = function render(penguinViewModel) {
  this.calledRenderWith = penguinViewModel;
};

// Arrange
var penguinViewMock = new PenguinViewMock();

var controller = new PenguinController(penguinViewMock, null);

var penguinModelData = {
  name: 'Chinstrap',
  imageUrl: 'http://chinstrapl.jpg',
  size: '5.0kg (m), 4.8kg (f)',
  favoriteFood: 'krill',
  index: 2,
  count: 5
};

// Act
controller.showPenguin(penguinModelData);

// Assert
assert.strictEqual(penguinViewMock.calledRenderWith.name, 'Chinstrap');
assert.strictEqual(penguinViewMock.calledRenderWith.imageUrl, 'http://chinstrapl.jpg');
assert.strictEqual(penguinViewMock.calledRenderWith.size, '5.0kg (m), 4.8kg (f)');
assert.strictEqual(penguinViewMock.calledRenderWith.favoriteFood, 'krill');
assert.strictEqual(penguinViewMock.calledRenderWith.previousIndex, 1);
assert.strictEqual(penguinViewMock.calledRenderWith.nextIndex, 3);
</code>
ログイン後にコピー
MVCでは、すべてのモデルがAJAXに関心があります。たとえば、

モジュールXMLHTTPREQUESTがコンストラクターに注入されることに注意してください。これは、他のプログラマーにこのモデルが必要とするコンポーネントを知らせる方法です。モデルに単純なAJAX以上のものが必要な場合は、より多くのモジュールを使用してこれを表すことができます。また、ユニットテストを使用して、元のモジュールとまったく同じ契約を持つモックを注入できます。

インデックスに基づいてペンギンを取得する時が来ました:

<code>var PenguinView = function PenguinView(element) {
  this.element = element;

  this.onClickGetPenguin = null;
};
</code>
ログイン後にコピー

これはエンドポイントを指し、サーバーからデータを取得します。ユニットテストでデータをock笑することでこれをテストできます:

ご覧のとおり、モデルは元のデータのみを気にします。これは、AJAXおよびJavaScriptオブジェクトを使用することを意味します。純粋なJavaScriptのAjaxを知っていない場合は、詳細な記事があります。
<code>PenguinView.prototype.render = function render(viewModel) {
  this.element.innerHTML = '<h3>' + viewModel.name + '</h3>' +
    '<img alt="' + viewModel.name + '" src="'%20+%20viewModel.imageUrl%20+%0A%20%20%20%20%20%20'">' +
    '<p><b>Size:</b> ' + viewModel.size + '</p>' +
    '<p><b>Favorite food:</b> ' + viewModel.favoriteFood + '</p>' +
    '<a href="https://www.php.cn/link/f0b875eb6cff6fd5f491e6b6521c7510">      ' data-penguin-index="' + viewModel.previousIndex + '">Previous</a> ' +
    '<a href="https://www.php.cn/link/f0b875eb6cff6fd5f491e6b6521c7510">      ' data-penguin-index="' + viewModel.nextIndex + '">Next</a>';

  this.previousIndex = viewModel.previousIndex;
  this.nextIndex = viewModel.nextIndex;

  // Wire up click events, and let the controller handle events
  var previousPenguin = this.element.querySelector('#previousPenguin');
  previousPenguin.addEventListener('click', this.onClickGetPenguin);

  var nextPenguin = this.element.querySelector('#nextPenguin');
  nextPenguin.addEventListener('click', this.onClickGetPenguin);
  nextPenguin.focus();
};
</code>
ログイン後にコピー

単位テスト

<code>var ElementMock = function ElementMock() {
  this.innerHTML = null;
};

// Stub functions, so we can pass the test
ElementMock.prototype.querySelector = function querySelector() { };
ElementMock.prototype.addEventListener = function addEventListener() { };
ElementMock.prototype.focus = function focus() { };

// Arrange
var elementMock = new ElementMock();

var view = new PenguinView(elementMock);

var viewModel = {
  name: 'Chinstrap',
  imageUrl: 'http://chinstrap1.jpg',
  size: '5.0kg (m), 4.8kg (f)',
  favoriteFood: 'krill',
  previousIndex: 1,
  nextIndex: 2
};

// Act
view.render(viewModel);

// Assert
assert(elementMock.innerHTML.indexOf(viewModel.name) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.imageUrl) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.size) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.favoriteFood) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.previousIndex) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.nextIndex) > 0);
</code>
ログイン後にコピー
どんな規律でも、保証された作業を取得することが重要です。 MVC設計パターンは、問題を解決する方法を規定していません。デザインパターンは、クリーンコードを作成できるようにする幅広い境界セットを提供します。これにより、依存から救われます。

私にとって、これは、各ユースケースに完全な一連のユニットテストを提供することを意味します。テストは、コードがどのように役立つかについてのガイダンスを提供します。これにより、特定の変更を行いたいプログラマーに開いて魅力的になります。

ユニットテストのセット全体を自由に表示してください。これは、このデザインパターンを理解するのに役立つと思います。各テストは、特定のユースケースをターゲットにしています。ユニットテストは、各コーディングの問題を独立して検討し、それを解決するのに役立ちます。 MVCにおける機能的懸念のこの分離は、すべての単位テストに反映されています。

楽しみにしています ペンギンのデモンストレーションには、MVCがどれほど有用であるかを示す基本的な実行可能な概念のみが含まれています。ただし、多くの改善点を反復させることができます:

  • ペンギンのすべてのリストを表示する画面を追加します
  • キーボードイベントを追加して、ペンギンをめくって、スワイプ関数を追加できる
  • データを視覚化するためのSVGチャート、ペンギンのサイズなどのデータポイントを選択します

もちろん、私の読者、あなたはこのデモをさらに改善することができます。これらは、このデザインパターンの力を紹介できるアイデアにすぎません。

結論

MVCの設計パターンと少しの規律があなたを連れて行く場所を見ることができることを願っています。優れたデザインパターンは、邪魔にならずにクリーンコードを書くことを容易にします。手元の問題を解決するとき、タスクに集中し続けます。それはあなたをより良く、より効率的なプログラマにするでしょう。

プログラミングでは、目的は、冗長性を排除しながら、手元の問題に密接に焦点を当てることです。プログラミングの技術は、一度に1つの問題を解決することです。 MVCでは、これは一度に機能的な問題を解決することを意味します。

開発者として、あなたが論理的であり、感情に対処しないと信じるのは簡単です。真実は、一度に問題が多すぎるとイライラすることです。これは、私たち全員が対処しなければならない通常の人間の反応です。実際、フラストレーションはコードの品質に悪影響を与える可能性があります。この気持ちがあなたを捕らえてあなたの仕事をリードするとき、それはもはや論理に関するものではありません。ソリューションがより多くのリスクと複雑な依存関係をとるため、これはイライラする可能性があります。

私が好きなのは、単一の焦点に焦点を当てることです。一度に1つの問題を解決し、肯定的なフィードバックを取得します。このようにして、集中力を維持し、効率的に保ち、意味のないことを避けることができます。

この記事は、Vildan Softicによって査読されました。 SitePointコンテンツを最高の状態にしてくれたすべてのSitePointピアレビューアに感謝します!

JavaScript MVCデザインパターン

に関するよくある質問

JavaScript MVCデザインパターンの重要性は何ですか?

JavaScriptのモデル-View-Controller(MVC)設計パターンは、簡潔で体系的な方法でコードを整理するのに役立つため、重要です。アプリケーションの焦点を3つの相互に関連するコンポーネントに分割します。モデルはデータとビジネスロジックを処理し、ビューはデータの表示を管理し、コントローラーはユーザー入力を処理します。この分離により、効率的なコード管理、デバッグが容易になり、スケーラビリティが向上します。

MVCパターンは、コードの読みやすさと保守性をどのように改善しますか?

MVCモードは、責任を分離することにより、コードの読みやすさと保守性を向上させます。 MVCパターンの各コンポーネントの関数は異なります。この分離は、開発者が他のコンポーネントに影響を与えることなく個々のコンポーネントを処理できることを意味します。また、1つのコンポーネントの変更が他のコンポーネントに影響を与えないため、エラーを見つけて修正したり、機能を更新したり、コードをリファクタリングしたりすることができます。

MVCパターンにおけるモデルの役割を説明できますか?

MVCパターンのモデルは、データとビジネスロジックの管理を担当します。データベースからデータを取得し、データで動作し、データを更新します。モデルはユーザーインターフェイスとは無関係で、ビューやコントローラーと直接対話しません。代わりに、州が変更されたときに通知を送信します。

MVCモードでのビューの機能は何ですか?

MVCモードのビューは、ユーザーにデータを表示する責任があります。モデルからデータを受信し、ユーザーフレンドリーな形式でデータを提示します。ビューはモデルと直接相互作用しません。代わりに、コントローラーから更新を受信します。

コントローラーはMVCモードをどのように宣伝していますか?

MVCモードのコントローラーは、モデルとビューの間のメディエーターとして機能します。ユーザーの入力を処理し、モデルを更新し、それに応じて表示します。ユーザーがビューと対話すると、コントローラーは入力を解釈し、モデルに必要な変更を加えます。また、これらの変更を反映するためにビューを更新します。

MVCモードはスケーラビリティをどのように強化しますか?

MVCモードは、フォーカスポイントを分離することによりスケーラビリティを向上させます。この分離により、開発者は他のコンポーネントに影響を与えることなく、1つのコンポーネントを変更または拡張できます。たとえば、データの表示方法を変更する必要がある場合は、モデルやコントローラーに触れずにビューを変更できます。このモジュール性により、時間の経過とともにアプリケーションのスケーリングと成長が容易になります。

MVCパターンは他のJavaScriptフレームワークで使用できますか?

はい、MVCパターンは、Angularjs、ember.js、backbone.jsなどのさまざまなJavaScriptフレームワークで使用できます。これらのフレームワークは、MVCパターンを実装するための構造化されたアプローチを提供し、複雑なアプリケーションの構築を容易にします。

JavaScriptにMVCパターンを実装することの課題は何ですか?

JavaScriptの動的な性質のため、

JavaScriptにMVCパターンを実装することは困難です。言語を十分に理解する必要があり、モデル、ビュー、コントローラーが適切に分離され、正しく相互作用することを保証するために慎重な計画が必要です。さらに、これらのコンポーネント間の更新の管理は複雑になる可能性があります。

MVCモデルはチームの開発をどのようにサポートしていますか?

MVCモードは、異なる開発者が異なるコンポーネントを同時に処理できるようにすることにより、チーム開発をサポートします。たとえば、ある開発者はモデルを処理でき、別の開発者はビューを処理できます。この懸念の分離は、生産性を向上させるだけでなく、コードの重複による競合やエラーの可能性を減らします。

MVCモードを使用してモバイルアプリケーションを開発できますか?

はい、MVCモードを使用してモバイルアプリケーションを開発できます。複雑なモバイルアプリケーションの管理を容易にするアプリケーション開発への構造化されたアプローチを提供します。 React NativeやIonicなどの多くの人気のあるモバイル開発フレームワークは、MVCモードをサポートしています。

以上がVanilla JavaScriptのMVC設計パターンの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート