原文:Model-View-Controller (MVC) with JavaScript
作者:Alex@Net
译文:JavaScript 的 MVC 模式
译者:justjavac
本文介绍了模型-视图-控制器模式在 JavaScript 中的实现。
我喜欢 JavaScript,因为它是在世界上最灵活的语言之一。 在 JavaScript 中,程序员可以根据自己的口味选择编程风格:面向过程或面向对象。 如果你是一个重口味,JavaScript 一样可以应付自如: 面向过程,面向对象,面向方面, 使用 JavaScript 开发人员甚至可以使用函数式编程技术。
这篇文章中,我的目标是编写一个简单的 JavaScript 组件,来向大家展示一下 JavaScript 的强大。 该组件是一个可编辑的项目列表(HTML中的 select 标签):用户可以选择某一项并删除它,或者添加新的项目到列表中。 组件将由三个类构成,分别对应着 MVC 设计模式的模型-视图-控制器。
这篇文章只是一个简单的指导。 如果你希望在实际的项目中使用它,你需要进行适当的修改。 我相信你拥有创建和运行 JavaScript 程序的一切:大脑,双手,文本编辑器(如记事本),浏览器(例如我的最爱 Chrome)。
既然我们的代码要使用 MVC 模式,因此我在这里简单介绍一个这个设计模式。 MVC 模式的英文名称是 Model-View-Controller pattern,顾名思义,其主要部分组成:
"codetitle">复制代码 代码如下:
/**
* 模型。
*
* 模型存储所有元素,并在状态变更时通知观察者(Observer)。
*/
function ListModel(items) {
this._items = items; // 所有元素
this._selectedIndex = -1; // 被选择元素的索引
this.itemAdded = new Event(this);
this.itemRemoved = new Event(this);
this.selectedIndexChanged = new Event(this);
}
ListModel.prototype = {
getItems : function () {
return [].concat(this._items);
},
addItem : function (item) {
this._items.push(item);
this.itemAdded.notify({item : item});
},
removeItemAt : function (index) {
var item;
item = this._items[index];
this._items.splice(index, 1);
this.itemRemoved.notify({item : item});
if (index === this._selectedIndex) {
this.setSelectedIndex(-1);
}
},
getSelectedIndex : function () {
return this._selectedIndex;
},
setSelectedIndex : function (index) {
var previousIndex;
previousIndex = this._selectedIndex;
this._selectedIndex = index;
this.selectedIndexChanged.notify({previous : previousIndex});
}
};
Event 是一个简单的实现了观察者模式(Observer pattern)的类:
复制代码 代码如下:
function Event(sender) {
this._sender = sender;
this._listeners = [];
}
Event.prototype = {
attach : function (listener) {
this._listeners.push(listener);
},
notify : function (args) {
var index;
for (index = 0; index < this._listeners.length; index += 1) {
this._listeners[index](this._sender, args);
}
}
};
View 类需要定义控制器类,以便与它交互。 虽然这个任务可以有许多不同的接口(interface),但我更喜欢最简单的。 我希望我的项目是在一个 ListBox 控件和它下面的两个按钮:“加号”按钮添加项目,“减”删除所选项目。 组件所提供的“选择”功能则需要 select 控件的原生功能的支持。
一个 View 类被绑定在一个 Controller 类上, 其中「…控制器处理用户输入事件,通常是通过一个已注册的回调函数」(wikipedia.org)。
下面是 View 和 Controller 类:
复制代码 代码如下:
/**
* 视图。
*
* 视图显示模型数据,并触发 UI 事件。
* 控制器用来处理这些用户交互事件
*/
function ListView(model, elements) {
this._model = model;
this._elements = elements;
this.listModified = new Event(this);
this.addButtonClicked = new Event(this);
this.delButtonClicked = new Event(this);
var _this = this;
// 绑定模型监听器
this._model.itemAdded.attach(function () {
_this.rebuildList();
});
this._model.itemRemoved.attach(function () {
_this.rebuildList();
});
// 将监听器绑定到 HTML 控件上
this._elements.list.change(function (e) {
_this.listModified.notify({ index : e.target.selectedIndex });
});
this._elements.addButton.click(function () {
_this.addButtonClicked.notify();
});
this._elements.delButton.click(function () {
_this.delButtonClicked.notify();
});
}
ListView.prototype = {
show : function () {
this.rebuildList();
},
rebuildList : function () {
var list, items, key;
list = this._elements.list;
list.html('');
items = this._model.getItems();
for (key in items) {
if (items.hasOwnProperty(key)) {
list.append($('<option>' + items[key] + '</option>'));
}
}
this._model.setSelectedIndex(-1);
}
};
/**
* 控制器。
*
* 控制器响应用户操作,调用模型上的变化函数。
*/
function ListController(model, view) {
this._model = model;
this._view = view;
var _this = this;
this._view.listModified.attach(function (sender, args) {
_this.updateSelected(args.index);
});
this._view.addButtonClicked.attach(function () {
_this.addItem();
});
this._view.delButtonClicked.attach(function () {
_this.delItem();
});
}
ListController.prototype = {
addItem : function () {
var item = window.prompt('Add item:', '');
if (item) {
this._model.addItem(item);
}
},
delItem : function () {
var index;
index = this._model.getSelectedIndex();
if (index !== -1) {
this._model.removeItemAt(this._model.getSelectedIndex());
}
},
updateSelected : function (index) {
this._model.setSelectedIndex(index);
}
};
当然,Model, View, Controller 类应当被实例化。
下面是一个使用此 MVC 的完整代码:
复制代码 代码如下:
$(function () {
var model = new ListModel(['PHP', 'JavaScript']),
view = new ListView(model, {
'list' : $('#list'),
'addButton' : $('#plusBtn'),
'delButton' : $('#minusBtn')
}),
controller = new ListController(model, view);
view.show();
});
<select id="list" size="10" style="width: 15em"></select><br/>
<button id="plusBtn"> + </button>
<button id="minusBtn"> - </button>
JavaScript,MVC模式
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 【雨果唱片】中国管弦乐《鹿回头》WAV
- APM亚流新世代《一起冒险》[FLAC/分轨][106.77MB]
- 崔健《飞狗》律冻文化[WAV+CUE][1.1G]
- 罗志祥《舞状元 (Explicit)》[320K/MP3][66.77MB]
- 尤雅.1997-幽雅精粹2CD【南方】【WAV+CUE】
- 张惠妹.2007-STAR(引进版)【EMI百代】【WAV+CUE】
- 群星.2008-LOVE情歌集VOL.8【正东】【WAV+CUE】
- 罗志祥《舞状元 (Explicit)》[FLAC/分轨][360.76MB]
- Tank《我不伟大,至少我能改变我。》[320K/MP3][160.41MB]
- Tank《我不伟大,至少我能改变我。》[FLAC/分轨][236.89MB]
- CD圣经推荐-夏韶声《谙2》SACD-ISO
- 钟镇涛-《百分百钟镇涛》首批限量版SACD-ISO
- 群星《继续微笑致敬许冠杰》[低速原抓WAV+CUE]
- 潘秀琼.2003-国语难忘金曲珍藏集【皇星全音】【WAV+CUE】
- 林东松.1997-2039玫瑰事件【宝丽金】【WAV+CUE】