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' ? '' : 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
- ……
一個完善的框架要經過無數的提煉和修改,這裡只是最初最初的第一步,道路還很漫長,希望大家再接再厲。

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

SublimeText3 Linux 新バージョン
SublimeText3 Linux 最新バージョン

EditPlus 中国語クラック版
サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

SublimeText3 中国語版
中国語版、とても使いやすい

メモ帳++7.3.1
使いやすく無料のコードエディター

Dreamweaver Mac版
ビジュアル Web 開発ツール
