MVC パターンは、ソフトウェア エンジニアリングにおけるソフトウェア アーキテクチャ パターンであり、通常、モデル + ビュー + コントローラーの 3 つの部分に分かれています。
モデル: モデルは、アプリケーションのビジネス ロジックとデータ処理のメソッドに関連するデータをカプセル化するために使用されます。モデルはデータに直接アクセスできます。このモデルは「ビュー」と「コントローラー」に依存しません。つまり、モデルはページがどのように表示され、どのように操作されるかを気にしません。ビュー: ビュー層で最も重要なことは、モデル層のデータ変更を監視し、HTML ページをリアルタイムで更新することです。もちろん、これには一部のイベントまたは Ajax リクエスト操作 (イベントの発行) の登録も含まれており、これらはすべてビュー層で行われます。
コントローラー: コントローラーはユーザーの操作を受け取ります。最も重要なことは、ビューレイヤーのイベントをサブスクライブしてから、モデルまたはビューを呼び出してユーザーの操作を完了することです。たとえば、イベントがトリガーされたとき。ページでは、コントローラーは何も出力せず、応答します。ページは、リクエストを受信するだけで、リクエストを処理するために呼び出すモデル内のメソッドを決定し、返されたデータを表示するためにビュー内のどのメソッドを呼び出すかを決定します。 。
下の図に示すように、追加および削除できる単純なドロップダウン ボックス コントロールを実装してみましょう。
コードは次のとおりです:
/* 模型用于封装与应用程序的业务逻辑相关的数据以及对数据处理的方法。模型有对数据直接访问的权利。 模型不依赖 "视图" 和 "控制器", 也就是说 模型它不关心页面如何显示及如何被操作. */ function Mode(elems) { // 所有元素 this._elems = elems; // 被选中元素的索引 this._selectedIndex = -1; // 增加一项 this.itemAdd = new Event(this); // 删除一项 this.itemRemoved = new Event(this); this.selectedIndexChanged = new Event(this); } Mode.prototype = { constructor: 'Mode', // 获取所有的项 getItems: function(){ return [].concat(this._elems); }, // 增加一项 addItem: function(elem) { this._elems.push(elem); this.itemAdd.notify({elem:elem}); }, // 删除一项 removeItem: function(index) { var item = this._elems[index]; this._elems.splice(index,1); this.itemRemoved.notify({elem:item}); if(index === this._selectedIndex) { this.setSelectedIndex(-1); } }, getSelectedIndex: function(){ return this._selectedIndex; }, setSelectedIndex: function(index){ var previousIndex = this._selectedIndex; this._selectedIndex = index; this.selectedIndexChanged.notify({previous : previousIndex}); } }; /* 下面是观察者模式类,它又叫发布---订阅模式;它定义了对象间的一种一对多的关系, 让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。 */ function Event(observer) { this._observer = observer; this._listeners = []; } Event.prototype = { constaructor: 'Event', attach : function(listeners) { this._listeners.push(listeners); }, notify: function(objs){ for(var i = 0,ilen = this._listeners.length; i ) { this._listeners[i](this._observer,objs); } } }; /* * 视图显示模型数据,并触发UI事件。 */ function View(model,elements){ this._model = model; this._elements = elements; this.listModified = new Event(this); this.addButtonClicked = new Event(this); this.delButtonClicked = new Event(this); var that = this; // 绑定模型监听器 this._model.itemAdd.attach(function(){ that.rebuildList(); }); this._model.itemRemoved.attach(function(){ that.rebuildList(); }); // 将监听器绑定到HTML控件上 this._elements.list.change(function(e){ that.listModified.notify({index: e.target.selectedIndex}); }); // 添加按钮绑定事件 this._elements.addButton.click(function(e){ that.addButtonClicked.notify(); }); // 删除按钮绑定事件 this._elements.delButton.click(function(e){ that.delButtonClicked.notify(); }); } View.prototype = { constructor: 'View', show: function(){ this.rebuildList(); }, rebuildList: function(){ var list = this._elements.list, items, key; list.html(""); items = this._model.getItems(); for(key in items) { if(items.hasOwnProperty(key)) { list.append('' +items[key]+ ''); } } this._model.setSelectedIndex(-1); } }; /* 控制器响应用户操作,调用模型上的变化函数 负责转发请求,对请求进行处理 */ function Controller(model,view) { this._model = model; this._view = view; var that = this; this._view.listModified.attach(function(sender,args){ that.updateSelected(args.index); }); this._view.addButtonClicked.attach(function(){ that.addItem(); }); this._view.delButtonClicked.attach(function(){ that.delItem(); }); } Controller.prototype = { constructor: 'Controller', addItem: function(){ var item = window.prompt('Add item:', ''); if (item) { this._model.addItem(item); } }, delItem: function(){ var index = this._model.getSelectedIndex(); if(index !== -1) { this._model.removeItem(index); } }, updateSelected: function(index){ this._model.setSelectedIndex(index); } };
<select id="list" size="10" style="width: 10rem">select>br/> <button id="plusBtn"> + button> <button id="minusBtn"> - button>
$(function () { var model = new Mode(['PHP', 'JavaScript']), view = new View(model, { 'list' : $('#list'), 'addButton' : $('#plusBtn'), 'delButton' : $('#minusBtn') }), controller = new Controller(model, view); view.show(); });
まず、実現したい機能の種類を分析してみましょう。
基本機能は次のとおりです。 ユーザーが項目を追加したり、ユーザー入力操作によって項目を選択した後に項目を削除したりできるドロップダウン ボックス。
もちろん、ユーザーがその項目に切り替えるためのイベントも追加されます。
たとえば、ここでデータを追加するときは、次のコードに示すように、ビュー レイヤーにリッスン イベントを追加します。
// 添加按钮绑定事件 this._elements.addButton.click(function(e){ that.addButtonClicked.notify(); });
this._view.addButtonClicked.attach(function(){ that.addItem(); });
モデル層 (モデル) のメソッド addItem() を呼び出し、選択ボックスにデータを挿入します。モデル (モデル層) の addItem() メソッドのコードは次のとおりです。
addItem: function(){ var item = window.prompt('Add item:', ''); if (item) { this._model.addItem(item); } }
上記のコードは項目を追加し、this.itemAdd を通じてメッセージを公開し、ビュー レイヤー (View) で次のコードを通じてメッセージを監視します。コードは次のとおりです。
// 增加一项 addItem: function(elem) { this._elems.push(elem); this.itemAdd.notify({elem:elem}); },
モデル層 (モデル) は主にビジネス データのカプセル化操作を担当します。ビュー層 (View) は主にイベント操作を発行し、モデル層のデータを監視し、モデル層のデータが変更された場合は、ページ操作を更新し、最終的にページに表示します。ビュー レイヤー (View) イベントを監視し、モデル レイヤー (Model) のメソッドを呼び出してモデル上のデータを更新します。モデル レイヤーのデータが更新された後、最後にビュー レイヤー (View) が発行されます。モデル層(Model)のデータ変更を監視してページを更新する 以上がMVCの基本的な処理です。
// 绑定模型监听器 this._model.itemAdd.attach(function(){ that.rebuildList(); });
ビューレイヤーとビジネスレイヤーが分離されており、ページ上の表示が変更された場合、モデルに触れることなくビューレイヤーで直接変更できます。レイヤーとコントロール レイヤー上のコード、つまりビューレイヤー、モデルレイヤー、コントロールレイヤー
すでに分離されているため、データ層とアプリケーション層のビジネスルールを簡単に変更できます。
2. 保守性: ビュー層とビジネスロジック層を分離することで、WEB アプリケーションの保守と変更も容易になります。
MVC の欠点:
個人的には、大規模なプロジェクトには適していると思いますが、単純な追加、削除、変更操作を実現するために必要な JS コードはほんの少しだけですが、MVC モードのコードの量が多くなるため、中小規模のプロジェクトには適していないと思います。が大幅に増加しました。
もちろん、学習コストも増加しますが、カプセル化された MVC ライブラリやフレームワークを使用した方がよいでしょう。
上記は、JavaScript における MVC パターンの実装方法の長所と短所を詳細に分析したものであり、皆様の学習に役立つことを願っています。