検索
ホームページウェブフロントエンドjsチュートリアルJavaScript で MVC_javascript テクニックを実装するためのコードはわずか 30 行です

2009 年頃から、MVC はフロントエンドの分野で徐々に頭角を現し、2015 年の React Native の立ち上げでついに大爆発を迎えました: AngularJS、EmberJS、Backbone、ReactJS、RiotJS、VueJS... ..一連の名前が出現し、派手に変化してきましたが、その中には徐々に人々の目から消えていくものもあれば、現在も急速に成長しているものもあれば、すでに特定の生態環境の中で独自の役割を果たしているものもあります。しかし、何があっても、MVC はフロントエンド エンジニアの考え方や仕事のやり方に大きな影響を与えてきましたし、これからも影響し続けるでしょう。

MVC を説明する多くの例は、Backbone のコレクションや AngularJS のモデルなど、特定のフレームワークの特定の概念から始まります。これは確かに良いアプローチです。しかし、フレームワークがクラ​​ス ライブラリ (jQuery) やツール セット (アンダースコア) ではなくフレームワークである理由は、その背後に多くの優れた設計コンセプトとベスト プラクティスがあるためです。これらの設計エッセンスは相互に補完し、連動しており、が不可欠ですが、複雑なフレームワークを通して短期間で特定のデザインパターンの本質を理解するのは簡単ではありません。

これがこのエッセイの原点です。誰もが概念を理解できるように作成されたプロトタイプ コードは、できる限り単純である必要があります。誰もが概念を理解できる程度に単純である必要があります。

1. MVC の基礎はオブザーバー パターンであり、これがモデルとビュー間の同期を実現するための鍵となります
簡単にするために、各モデル インスタンスにはプリミティブ値が 1 つだけ含まれています。

function Model(value) {
  this._value = typeof value === 'undefined' ? '' : value;
  this._listeners = [];
}
Model.prototype.set = function (value) {
  var self = this;
  self._value = value;
  // model中的值改变时,应通知注册过的回调函数
  // 按照Javascript事件处理的一般机制,我们异步地调用回调函数
  // 如果觉得setTimeout影响性能,也可以采用requestAnimationFrame
  setTimeout(function () {
    self._listeners.forEach(function (listener) {
      listener.call(self, value);
    });
  });
};
Model.prototype.watch = function (listener) {
  // 注册监听的回调函数
  this._listeners.push(listener);
};
// html代码:
<div id="div1"></div>
// 逻辑代码:
(function () {
  var model = new Model();
  var div1 = document.getElementById('div1');
  model.watch(function (value) {
    div1.innerHTML = value;
  });
  model.set('hello, this is a div');
})();

オブザーバー パターンの助けを借りて、モデルの set メソッドがその値を変更するために呼び出されるとき、テンプレートも同期的に更新されることがわかりました。しかし、この実装は、変更を手動で監視する必要があるため、非常に扱いにくいです。モデル値を (watch メソッドを介して) 取得し、コールバック関数に渡します。ビュー (1 つ以上の dom ノード) をモデルにバインドすることを簡単にする方法はありますか?

2. binding メソッドを実装し、モデルとビューをバインドします

Model.prototype.bind = function (node) {
  // 将watch的逻辑和通用的回调函数放到这里
  this.watch(function (value) {
    node.innerHTML = value;
  });
};
// html代码:
<div id="div1"></div>
<div id="div2"></div>
// 逻辑代码:
(function () {
  var model = new Model();
  model.bind(document.getElementById('div1'));
  model.bind(document.getElementById('div2'));
  model.set('this is a div');
})();

シンプルなカプセル化により、複数のビューをバインドする必要がある場合でも、ビューとモデル間のバインディングが簡単に実装できます。バインドは Function クラスのプロトタイプのネイティブ メソッドですが、作者はバインドという言葉を非常に気に入っているので、ここでは単にネイティブ メソッドについて説明します。 。さらに言えば、バインディングの複雑さは軽減されましたが、このステップでは依然としてバインディング ロジックをビジネス コードから完全に分離することが可能でしょうか。

3. ロジック コードからバインディングを分離するコントローラーを実装します

注意深い人は、MVC について話しているにもかかわらず、上の記事には Model クラスしか登場していないことに気づいたかもしれません。結局のところ、HTML は既成の View であることは理解できます。 、この記事でも最初から最後まで言及していますが、HTML を View として使用するだけでは、View クラスは JavaScript コードに表示されません)、では、なぜコントローラー クラスが表示されないのでしょうか。心配しないでください。実際、いわゆる「ロジック コード」は、フレームワーク ロジック (この記事のプロトタイプをフレームワークと呼ぶことにします) とビジネス ロジックの間の高度な結合を持つコード セグメントです。これを分解してみましょう。
バインディング ロジックをフレームワークに任せたい場合は、バインディングを完了する方法をフレームワークに指示する必要があります。 JS でアノテーションを完了するのは難しいため、ビューでこのマークアップ層を実行できます。HTML のタグ属性を使用するのが簡単で効果的な方法です。

function Controller(callback) {
  var models = {};
  // 找到所有有bind属性的元素
  var views = document.querySelectorAll('[bind]');
  // 将views处理为普通数组
  views = Array.prototype.slice.call(views, 0);
  views.forEach(function (view) {
    var modelName = view.getAttribute('bind');
    // 取出或新建该元素所绑定的model
    models[modelName] = models[modelName] || new Model();
    // 完成该元素和指定model的绑定
    models[modelName].bind(view);
  });
  // 调用controller的具体逻辑,将models传入,方便业务处理
  callback.call(this, models);
}




// html:
<div id="div1" bind="model1"></div>
<div id="div2" bind="model1"></div>
// 逻辑代码:
new Controller(function (models) {
  var model1 = models.model1;
  model1.set('this is a div');
});


そんなに簡単ですか?それはとても簡単です。 MVC の本質は、コントローラー内でビジネス ロジックを完成させ、同時にモデルを変更することで、これらのロジックが上記のコードに反映され、複数のビューと複数のモデルをサポートします。本番プロジェクトには十分ではありませんが、皆様の MVC 学習に少しでもお役に立てれば幸いです。

コメントが削除された整理された「フレームワーク」コード:

function Model(value) {
  this._value = typeof value === 'undefined' &#63; '' : value;
  this._listeners = [];
}
Model.prototype.set = function (value) {
  var self = this;
  self._value = value;
  setTimeout(function () {
    self._listeners.forEach(function (listener) {
      listener.call(self, value);
    });
  });
};
Model.prototype.watch = function (listener) {
  this._listeners.push(listener);
};
Model.prototype.bind = function (node) {
  this.watch(function (value) {
    node.innerHTML = value;
  });
};
function Controller(callback) {
  var models = {};
  var views = Array.prototype.slice.call(document.querySelectorAll('[bind]'), 0);
  views.forEach(function (view) {
    var modelName = view.getAttribute('bind');
    models[modelName] = models[modelName] || new Model();
    models[modelName].bind(view);
  });
  callback.call(this, models);
}

後記:

筆者在​​學習flux和redux的過程中,雖然掌握了工具的使用方法,但只是知其然而不知其所以然,對ReactJS官方文件中一直強調的"Flux eschews MVC in favor of a unidirectional data flow"不甚理解,始終覺得單向資料流和MVC並不衝突,不明白為什麼在ReactJS的文檔中這二者會被對立起來,有他無我,有我無他(eschew,避開)。終於下定決心,回到MVC的定義上重新研究,雖然平日工作里大大咧咧複製粘貼,但是咱們偶爾也得任性一把,咬文嚼字一番,對吧?這樣的方式也的確幫助了我對這句話的理解,這裡可以把自己的思考分享給大家:之所以覺得MVC和flux中的單向資料流相似,可能是因為沒有區分清楚MVC和觀察者模式的關係所造成的-MVC是基於觀察者模式的,flux也是,因此這種相似性的由來是觀察者模式,而不是MVC和flux本身。這樣的理解也在四人組的設計模式原著中得到了印證:"The first and perhaps best-known example of the Observer pattern appears in Smalltalk Model/View/Controller (MVC), the user interface framework in the Smalltalk environment [KP88]. MVC's Model class plays the role of Subject, while View is the base class for observers. "。

如果讀者有興趣在這樣一個原型玩具的基礎上繼續拓展,可以參考下面的一些方向:

  • 1. 實作對input類別標籤的雙向綁定
  • 2. 實現對controller所控制的scope的精準控制,這裡一個controller就控制了整個dom樹
  • 3. 實作view層有關dom node隱藏/顯示、建立/銷毀的邏輯
  • 4. 整合virtual dom,增加dom diff的功能,提高渲染效率
  • 5. 提供依賴注入功能,實現控制反轉
  • 6. 對innerHTML的賦值內容進行安全檢查,防止惡意注入
  • 7. 實作model collection的邏輯,這裡每個model只有一個值
  • 8. 利用es5中的setter改變set方法的實現,使得model的修改更加簡單
  • 9. 在view層中增加對屬性和css的控制
  • 10.支援類似AngularJS中雙大括號的語法,只綁定部分html
  • ……

一個完善的框架要經過無數的提煉和修改,這裡只是最初最初的第一步,道路還很漫長,希望大家再接再厲。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
JavaScriptとWeb:コア機能とユースケースJavaScriptとWeb:コア機能とユースケースApr 18, 2025 am 12:19 AM

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンの理解:実装の詳細JavaScriptエンジンの理解:実装の詳細Apr 17, 2025 am 12:05 AM

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

Python vs. JavaScript:コミュニティ、ライブラリ、リソースPython vs. JavaScript:コミュニティ、ライブラリ、リソースApr 15, 2025 am 12:16 AM

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへ:すべてがどのように機能するかC/CからJavaScriptへ:すべてがどのように機能するかApr 14, 2025 am 12:05 AM

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

JavaScriptエンジン:実装の比較JavaScriptエンジン:実装の比較Apr 13, 2025 am 12:05 AM

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

ブラウザを超えて:現実世界のJavaScriptブラウザを超えて:現実世界のJavaScriptApr 12, 2025 am 12:06 AM

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)Apr 11, 2025 am 08:23 AM

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール

Dreamweaver Mac版

Dreamweaver Mac版

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)