MVC
模式
(Model-View-Controller)
常被用在
Web
程序中。如
Struts
框架就是一个基于
MVC
模式的
Web
框架。所谓
MVC
模式,就是将视图(也就是客户端代码,包括
html
、
javascript
等)和模型(和数据库及业务逻辑相关的
Java
代码)分开。并通过控制器将两者联系起来。这样做的好处可以使客户端开发人员和服务端开发人员的工作尽量分开,以使他们之间的干扰降到最低。
虽然象
Struts
这样的框架可以很好地
Model
和
View
分离。但是对于客户端的代码,仍然存在着一定的视图和逻辑混合的现象。如下面的代码所示:
index.html文件
下面先来看一下 addButton 函数是如何实现的,代码如下:
<!
DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
>
< html >
< head >
< title ></ title >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" >
< script type ="text/javascript" >
function fun1(obj) { }
function fun2() { }
</ script >
</ head >
< body >
< input type ="button" value ="按钮1 " onclick ="fun1(this)" />
< input type ="button" value ="按钮2 " onclick ="fun2()" />
</ body >
</ html >
< html >
< head >
< title ></ title >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" >
< script type ="text/javascript" >
function fun1(obj) { }
function fun2() { }
</ script >
</ head >
< body >
< input type ="button" value ="按钮1 " onclick ="fun1(this)" />
< input type ="button" value ="按钮2 " onclick ="fun2()" />
</ body >
</ html >
从上面的代码可以看出,html
代码和javascript
代码都混在了同一个html
文件中。在一般情况下,客户端的界面是由美工设计的,而对于javascript
代码,美工一般是不参与实现的。这些代码一般也应属于业务逻辑代码的一部分,虽然它们都在客户端运行,但可能也会处理一定的业务逻辑,如验证数据的正确性。尤其在AJAX
应用中,在客户端还会通过http
协议从服务端获取数据。这样就和业务逻辑绑定得更紧了。因此,如果将用于描述界面的html
和用于处理业务逻辑的javascript
(渲染界面的javascript
除外)混在一起,非常不利于团队中负责这两方面的人员进行协调。
最好的可能就是将这些javascript
代码从html
代码中分离。也许有很多人马上就会想到,将这些javascript
放到.js
文件中,然后使用<script>
标签引用一下就ok
了。代码如下:
fun.js
文件
function fun1(obj) { ... }
function fun2() {... }
index.html文件
<!
DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
>
< html >
< head >
< title ></ title >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" >
< script type ="text/javascript" src ="fun.js" >
</ script >
</ head >
< body >
< input type ="button" value ="按钮1 " onclick ="fun1(this)" />
< input type ="button" value ="按钮2 " onclick ="fun2()" />
</ body >
</ html >
< html >
< head >
< title ></ title >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" >
< script type ="text/javascript" src ="fun.js" >
</ script >
</ head >
< body >
< input type ="button" value ="按钮1 " onclick ="fun1(this)" />
< input type ="button" value ="按钮2 " onclick ="fun2()" />
</ body >
</ html >
虽然上面的代码从某种程度上达到了视图和逻辑分离的效果。但仍然有着一定的联系。我们可以看到,两个<input>
标签的onclick
事件不还是引用着fun1
和fun2
函数吗!其实美工人员是不关心这两个函数到底是做什么的,甚至并不需要知道它们的存在。那么是否有更高的方法呢?答案当然是肯定的,就是通过动态的方式指定onclick
事件,而这一切美工人员是完全没有感觉的。
我们在文章的开头提到了
MVC
模式。其实在客户端也存在着一个
MVC
体系结构。我们可以将视图
(V)
看成是描述界面的
html
、
css
和
javascript
代码,而模型(
M
)可以看成是处理业务逻辑的
javascript
代码,而控制器(
C
)就是将这两类代码连接起来的代码(一般也是
javascript
代码)。
在本文中给出了一个小例子来演示一下如何通过动态的方法将V
和M
分离。这个例子是通过<div>
实现的10
个小方块,点击其中的某一个,会将相应的数字追加到下方的文本框架中,并且加入了一些用javascript
实现的效果,如以一定间隔随机更新方块和数字的颜色,直接在文本框中输入数字后,相应的文本框和数字的颜色也会随机发生变化。界面效果如图1
所示。
图1
图1
下面先来实现View
。先看看如下的代码:
numberKeys.html
<!
DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
>
< html >
< head >
< title ></ title >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" >
< link rel ="stylesheet" type ="text/css" href ="my.css" />
< script type ="text/javascript" src ="addevents.js" >
</ script >
</ head >
< body >
< input id ="changeColor" type ="button" value ="开始变换颜色" />
< br />< br />
< div id ="nubmerKeys" class ="numberKeys" >
</ div >
< br />< br />
< br />< br />
< input id ="numbers" type ="text" size ="80" />
</ body >
</ html >
< html >
< head >
< title ></ title >
< meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" >
< link rel ="stylesheet" type ="text/css" href ="my.css" />
< script type ="text/javascript" src ="addevents.js" >
</ script >
</ head >
< body >
< input id ="changeColor" type ="button" value ="开始变换颜色" />
< br />< br />
< div id ="nubmerKeys" class ="numberKeys" >
</ div >
< br />< br />
< br />< br />
< input id ="numbers" type ="text" size ="80" />
</ body >
</ html >
从上面的代码可以看出,除了一些html
代码外,没有任何和业务逻辑有关的javascript
代码。但使用<script>
引用了一个叫addevents.js
的文件。在这个文件中将为这个程序添加相应的逻辑代码,也就是说,这个文件相当于MVC
中的M
和C
。
动作装载事件是通过
window
的
onload
事件完成的,代码如下:
window.onload
=
onLoad;
//
为onload指定事件函数
function onLoad()
{
var text = document.getElementById( " numbers " );
if (text)
{
text.onkeyup = onKeyup; // 为文本框指定onkeyup事件
}
var button = document.getElementById( " changeColor " );
if (button)
{
button.onclick = stopAndStartTimer; // 为按钮指定onclick事件
}
addButton(); // 用于在<div>中加入10个<div>标签作为小方块,并指定onclick事件
}
function onLoad()
{
var text = document.getElementById( " numbers " );
if (text)
{
text.onkeyup = onKeyup; // 为文本框指定onkeyup事件
}
var button = document.getElementById( " changeColor " );
if (button)
{
button.onclick = stopAndStartTimer; // 为按钮指定onclick事件
}
addButton(); // 用于在<div>中加入10个<div>标签作为小方块,并指定onclick事件
}
下面先来看一下 addButton 函数是如何实现的,代码如下:
function
addButton()
{
var div = getNumberKeysDiv(); // 获得id为nubmerKeys的<div>标签
try
{
if (div)
{
// 删除<div>中的所有子元素
for ( var i = div.childNodes.length - 1 ; i >= 0 ; i -- )
{
try
{
div.removeChild(div.childNodes[i]);
}
catch (e)
{
}
}
// 为<div>标签加10个子<div>标签
for ( var i = 0 ; i < 10 ; i ++ )
{
var button = document.createElement( " div " );
button.className = " button " ;
button.style.left = i * 61 + " px " ;
button.style.backgroundColor = getRandomColor();
button.style.border = " solid 1px " ;
button.style.textAlign = " center " ;
button.style.lineHeight = " 50px " ;
button.style.color = getRandomColor();
button.onclick = buttonOnClick;
div.appendChild(button);
button.innerHTML = " <b> " + i + " </b> " ;
}
}
}
catch (e)
{
}
}
{
var div = getNumberKeysDiv(); // 获得id为nubmerKeys的<div>标签
try
{
if (div)
{
// 删除<div>中的所有子元素
for ( var i = div.childNodes.length - 1 ; i >= 0 ; i -- )
{
try
{
div.removeChild(div.childNodes[i]);
}
catch (e)
{
}
}
// 为<div>标签加10个子<div>标签
for ( var i = 0 ; i < 10 ; i ++ )
{
var button = document.createElement( " div " );
button.className = " button " ;
button.style.left = i * 61 + " px " ;
button.style.backgroundColor = getRandomColor();
button.style.border = " solid 1px " ;
button.style.textAlign = " center " ;
button.style.lineHeight = " 50px " ;
button.style.color = getRandomColor();
button.onclick = buttonOnClick;
div.appendChild(button);
button.innerHTML = " <b> " + i + " </b> " ;
}
}
}
catch (e)
{
}
}
addButton
函数的基本实现原理是先将<div>
中的所有元素删除,再向其中加入10
个<div>
标签。在addButton
函数中有几个关键的函数需要讲解一下。
getNumberKeysDiv
函数
这个函数用于获得叫
numberKeys
的
<div>
标签,实现代码如下:
function
getNumberKeysDiv()
{
var divs = document.getElementsByTagName( " div " );
if (divs)
{
for ( var i = 0 ; i < divs.length; i ++ )
{
var div = divs[i];
if (div.className.toString().indexOf( " numberKeys " , 0 ) > - 1 )
{
return div;
}
}
}
}
{
var divs = document.getElementsByTagName( " div " );
if (divs)
{
for ( var i = 0 ; i < divs.length; i ++ )
{
var div = divs[i];
if (div.className.toString().indexOf( " numberKeys " , 0 ) > - 1 )
{
return div;
}
}
}
}
这个函数并不是直接通过<div>
的id
找到这个<div>
,而是通过<div>
的class
属性,这样可能更灵活,因为如果通过id
找<div>
,就必须要求美工必须将这个<div>
命名为numberKeys
,而如果通过查找包含numberKeys
的class
属性的<div>
会对美工的限制更少。因为,只有这个<div>
才会使用css
中的numberKeys
。
getRandomColor
方法
这个方法获得了一个随机的演示,返回了字符串类型,格式
#FFFFFF
。实现代码如下:
function
getRandomArbitary(min, max)
{
return Math.round(Math.random() * (max - min) + min);
}
function getRandomColor()
{
var red = getRandomArbitary( 0 , 255 ).toString( 16 );
var green = getRandomArbitary( 0 , 255 ).toString( 16 );
var blue = getRandomArbitary( 0 , 255 ).toString( 16 );
if (red.length == 1 ) red = " 0 " + red;
if (green.length == 1 ) green = " 0 " + green;
if (blue.length == 1 ) blue = " 0 " + blue;
return " # " + red.toString( 16 ) + green.toString( 16 ) + blue.toString( 16 );
}
{
return Math.round(Math.random() * (max - min) + min);
}
function getRandomColor()
{
var red = getRandomArbitary( 0 , 255 ).toString( 16 );
var green = getRandomArbitary( 0 , 255 ).toString( 16 );
var blue = getRandomArbitary( 0 , 255 ).toString( 16 );
if (red.length == 1 ) red = " 0 " + red;
if (green.length == 1 ) green = " 0 " + green;
if (blue.length == 1 ) blue = " 0 " + blue;
return " # " + red.toString( 16 ) + green.toString( 16 ) + blue.toString( 16 );
}
getRandomColor
通过getRandomArbitary
函数获得了三个十进制的随机数(0-255
),并将其转换为16
进制,并返回最终结果。
buttonOnClick
函数
这个函数是<div>
标签的onclick
事件函数,实现代码如下:
function
buttonOnClick()
{
var text = document.getElementById( " numbers " );
if ( typeof this .innerText == " #ff0000 " )
text.value = text.value + this .textContent;
else
text.value = text.value + this .innerText;
this .style.backgroundColor = getRandomColor();
this .style.color = getRandomColor();
}
{
var text = document.getElementById( " numbers " );
if ( typeof this .innerText == " #ff0000 " )
text.value = text.value + this .textContent;
else
text.value = text.value + this .innerText;
this .style.backgroundColor = getRandomColor();
this .style.color = getRandomColor();
}
这个函数实现很简单,它的功能是将相应<div>
标签中的数字追加到numbers
文本框中。只是考虑了firefox
和ie
的不同。在firefox
中,获得<div>
中的文本要使用textContext
,而在ie
中要使用innerText
。最后再将当前点击的<div>
和数字的颜色再次变换。
到现在为止,还有两个事件函数代码没有给出,这两个事件函数是onKeyup
和stopAndStartTimer
。
onKeyup
函数
当
numbers
文本框输入一个字符后,发生这个事件,实现代码如下:
function
onKeyup()
{
var value = this .value;
if (value.length == 0 ) return ;
var i = value.toString().substr(value.length - 1 , 1 );
if (isNaN(i) == false )
{
var div = getNumberKeysDiv();
if (div)
{
var button = div.childNodes[i];
button.style.backgroundColor = getRandomColor();
button.style.color = getRandomColor();
}
}
}
{
var value = this .value;
if (value.length == 0 ) return ;
var i = value.toString().substr(value.length - 1 , 1 );
if (isNaN(i) == false )
{
var div = getNumberKeysDiv();
if (div)
{
var button = div.childNodes[i];
button.style.backgroundColor = getRandomColor();
button.style.color = getRandomColor();
}
}
}
这个函数的实现代码也很简单。只是根据用户在文本框中输入的数字来找到相应的<div>
标签,并再次随机变换<div>
背景和数字的颜色。
stopAndStartTimer
函数
这个函数是用来控制定时器的,如果启动定时器,浏览器会每隔3
秒重新使<div>
随机变化一次颜色。实现代码如下:
var
time;
function stopAndStartTimer()
{
if ( this .value.toString().indexOf( " 停止 " , 0 ) > - 1 )
{
this .value = " 开始变换颜色 " ;
clearInterval(time);
}
else
{
this .value = " 停止变换颜色 " ;
time = setInterval(onLoad, 3000 );
}
}
function stopAndStartTimer()
{
if ( this .value.toString().indexOf( " 停止 " , 0 ) > - 1 )
{
this .value = " 开始变换颜色 " ;
clearInterval(time);
}
else
{
this .value = " 停止变换颜色 " ;
time = setInterval(onLoad, 3000 );
}
}
从上面给出的代码可以看出,在View
层,除了<script>
引用了一个javascript
文件外,并未涉及任何和逻辑有关的代码。而设计界面的美工也并不知道开发人员会为<div>
及其他的按钮和文本框添加什么动作。而美工要做的是调整和界面有关的东西,如颜色,位置,分割等。只要使用<script>
引用了这个js
文件,就可以很容易加入相应的动作,而要将这些动作去掉,删除或注释掉这个<script>
标签即可。
尤其要提一下<div>
标签,美工在设计界面时可以向这个<div>
标签添加任何子元素。而在加入addevents.js
后,程序会自动将由美工向<div>
标签中的加入的内容都删除,而加入由业务逻辑需要的元素。这样美工用来设计界面的元素就不会影响开发人员需要加入的和业务逻辑有关的元素了。
根据上面的代码不难看出,numberKeys.html
属于视图层,所有的事件函数属性模型层,而其他的javascript
代码都属性控制器(Controller)
。
本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/215345,如需转载请自行联系原作者