假如这个世界上只剩下你一个人,当你正坐在屋子里的时候,这时突然响起了敲门声...

通过MVC模式将Web视图和逻辑代码分离

上一篇 / 下一篇  2008-05-19 22:35:04 / 个人分类:web

查看( 97 ) / 评论( 1 )
本文为原创,如需转载,请注明作者和出处,谢谢!
"ZS u1e;z1j[ f0
1O YAs8X&F"VV0    MVC模式(Model-View-Controller)常被用在Web程序中。如Struts框架就是一个基于MVC模式的Web框架。所谓MVC模式,就是将视图(也就是客户端代码,包括html、javascript等)和模型(和数据库及业务逻辑相关的Java代码)分开。并通过控制器将两者联系起来。这样做的好处可以使客户端开发人员和服务端开发人员的工作尽量分开,以使他们之间的干扰降到最低。
F7?7zgD[0    虽然象Struts这样的框架可以很好地Model和View分离。但是对于客户端的代码,仍然存在着一定的视图和逻辑混合的现象。如下面的代码所示:
g:?6S$n%A-nh0ITPUB个人空间4M |'_s:~!c$Kp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
&~9m+y+B6LL)R-F0<html>ITPUB个人空间)J&s-R~ C^lI6G
    <head>
F {xb/TY0        <title></title>
&|$pEE_Ll'bUo0        <meta. http-equiv="Content-Type" c>
u4]4]4D-}N ~j1vtv0        <script. type="text/javascript" >
{o(}!R4z-K*g0        function fun1(obj) {  }ITPUB个人空间*f1|"C?z;Hr8Q
        function fun2() { }
az:erJO&V@c0        </script>        
Xnvo`6D0    </head>
(Y d.H8k2N/E8ek1c0jJ0    <body>
@ SQ8q$r9H^.j[0        <input type="button" value="按钮1 " />ITPUB个人空间C9l L^&|e%D
        <input type="button" value="按钮2 " />
_A4q\@H0         
:t#Y{j x0    </body>ITPUB个人空间1W;Rw~8|'@C5B3fq(I
</html>ITPUB个人空间$t0G jw7T!|K)D:[
ITPUB个人空间-E]{u,V/I#A
    从上面的代码可以看出,html代码和javascript代码都混在了同一个html文件中。在一般情况下,客户端的界面是由美工设计的,而对于javascript代码,美工一般是不参与实现的。这些代码一般也应属于业务逻辑代码的一部分,虽然它们都在客户端运行,但可能也会处理一定的业务逻辑,如验证数据的正确性。尤其在AJAX应用中,在客户端还会通过http协议从服务端获取数据。这样就和业务逻辑绑定得更紧了。因此,如果将用于描述界面的html和用于处理业务逻辑的javascript(渲染界面的javascript除外)混在一起,非常不利于团队中负责这两方面的人员进行协调。
-wiNb ?0ITPUB个人空间e6}1o2bQyn
    最好的可能就是将这些javascript代码从html代码中分离。也许有很多人马上就会想到,将这些javascript放到.js文件中,然后使用<script>标签引用一下就ok了。代码如下:
D:~!i;}1W\0ITPUB个人空间+T'knm q+z]-d4HmB
fun.js文件ITPUB个人空间%r.uq4U7@nD-H

!{M}g'L0function fun1(obj) { ... }ITPUB个人空间7aH ^ A X x

V@?+Buz%\0function fun2() {... }ITPUB个人空间)w*^-l\ZJ Il

I%P*_F1V X3Z\3~0
y2b _~*Cd6yg7xq0N0index.html文件ITPUB个人空间-O Z'pK9`9C-{7A!_d%]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
4rBh r v$k0<html>
Yh'[{yL0    <head>
;K,S^L\ H1Q.aE0        <title></title>ITPUB个人空间3y+EZ!f8fB
        <meta. http-equiv="Content-Type" c>
`6l+zW^4U9e[0<script. type="text/javascript" src="fun.js">ITPUB个人空间Rz d.^z ex
</script>ITPUB个人空间*d YVKZ)L)VZe(S
    </head>ITPUB个人空间`$Z^7b Z$E@g
    <body>ITPUB个人空间~c1Ew d
        <input type="button" value="按钮1 " />ITPUB个人空间Js#D0Rn+njAHs%f
        <input type="button" value="按钮2 " />ITPUB个人空间H!^Z n@F0S*E
         ITPUB个人空间0~E,ecS\+E
    </body>
1kB(u|5{-_ Sz+d0</html>
0NTt` j5{hfU0ITPUB个人空间C hET K)Q#u'A
    虽然上面的代码从某种程度上达到了视图和逻辑分离的效果。但仍然有着一定的联系。我们可以看到,两个<input>标签的onclick事件不还是引用着fun1和fun2函数吗!其实美工人员是不关心这两个函数到底是做什么的,甚至并不需要知道它们的存在。那么是否有更高的方法呢?答案当然是肯定的,就是通过动态的方式指定onclick事件,而这一切美工人员是完全没有感觉的。
:|4k[#B"nL!IR0
9j*H$n'Y5FE&^0    我们在文章的开头提到了MVC模式。其实在客户端也存在着一个MVC体系结构。我们可以将视图(V)看成是描述界面的html、css和javascript代码,而模型(M)可以看成是处理业务逻辑的javascript代码,而控制器(C)就是将这两类代码连接起来的代码(一般也是javascript代码)。
O j5a(ZWZ#I@$a0
:fC[5B9Ah6oF3y0    在本文中给出了一个小例子来演示一下如何通过动态的方法将V和M分离。这个例子是通过<div>实现的10个小方块,点击其中的某一个,会将相应的数字追加到下方的文本框架中,并且加入了一些用javascript实现的效果,如以一定间隔随机更新方块和数字的颜色,直接在文本框中输入数字后,相应的文本框和数字的颜色也会随机发生变化。界面效果如图1所示。ITPUB个人空间,x6w&`|+}8r
ITPUB个人空间!\z:B1p&{ S}
ITPUB个人空间t&l}JJ ~

IgDH_"z001_mvc_web.jpg

$}ePl i.kf2S;W0ITPUB个人空间W%Q_:Vo{m&I
图1ITPUB个人空间u xE D2l3V

RxAZD0    下面先来实现View。先看看如下的代码:ITPUB个人空间L$c2?gA)MuK

SH$Nfz$mP3U'ws0numberKeys.htmlITPUB个人空间T9S1_ O%W"s*oM
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">ITPUB个人空间FCbB.L%p
  <html>ITPUB个人空间3v-o Z8F0Ay$f
      <head>
NI fSlJ0          <title></title>ITPUB个人空间5c#S\;DN!h wWM3w,Um
          <meta. http-equiv="Content-Type" c>
SiV]3`+m1}Bg0          <link  rel="stylesheet"  type="text/css" href="my.css"/>ITPUB个人空间0v(T9}3aO"~?;E
          <script. type="text/javascript" src="addevents.js">ITPUB个人空间 m3J;nP O/zj6e
          </script>
\/[ S2nMs|0O0
Ix6~;[6C5K [0      </head>ITPUB个人空间%A]s4A9~
      <body>
e&a3Q)I,p5^0          <input id ="changeColor" type="button" value="开始变换颜色" />
Lv A s[`1zc0          <br/><br/>
#X)F:k/I2mgH0
V7^{(C}0          <div id ="nubmerKeys" class="numberKeys"  >   
X `R8ofa X?0ITPUB个人空间 ` \ X3}h%WBn
          </div>
Axj7]B$P0          <br/><br/>ITPUB个人空间;H LE's)r2V
          <br/><br/>
z1q8MtN&UXz4f8?0          <input id="numbers" type="text" size="80"/>ITPUB个人空间 o)@*[R(fk

K1Kb cn&d2I?F0      </body>
+d4s[3B j$Cz'w*tb[0  </html>   
W6\X&YtiJ0
y\dw9B7\0    从上面的代码可以看出,除了一些html代码外,没有任何和业务逻辑有关的javascript代码。但使用<script>引用了一个叫addevents.js的文件。在这个文件中将为这个程序添加相应的逻辑代码,也就是说,这个文件相当于MVC中的M和C。
6lko.sG$vvL |0    动作装载事件是通过window的onload事件完成的,代码如下:
B0x!{`0u0ITPUB个人空间3dWW eCp
window.onload = onLoad;  // 为onload指定事件函数
7q] kD;UC v(y0ITPUB个人空间,F`)@6oX
function onLoad()ITPUB个人空间$GTt7zm4Uu8t
{
6p:ek;ou pB6I0    var text = document.getElementById("numbers");
5p]e+Y|*B D0    if(text)ITPUB个人空间f5e*iP*?:L*AC
    {      ITPUB个人空间O6Yv8{ ?.?`
        text.onkeyup = onKeyup;  // 为文本框指定onkeyup事件ITPUB个人空间@9~b$V6Q2B'a
    }
-h)G+[1}'@*m0    var button = document.getElementById("changeColor");ITPUB个人空间3Jnt J:Ry
    if(button)ITPUB个人空间W9Yb+\ I4l6Hx2s
    {ITPUB个人空间hEd5m1M)P5~W
        button.onclick = stopAndStartTimer;  // 为按钮指定onclick事件ITPUB个人空间KW`;R3}:g5_-O-{
    }  ITPUB个人空间(pJn L1}4{7Gd_
    addButton();  // 用于在<div>中加入10个<div>标签作为小方块,并指定onclick事件ITPUB个人空间&BW t"C3YN
}
/jf#hqi};R9[8L0
!F3w\8\['g#U:kH$x+l0    下面先来看一下addButton函数是如何实现的,代码如下:
V s9c!\+J ^6z q|0ITPUB个人空间Pj[*gZ@O
function addButton()
'pm }'IW0{ITPUB个人空间i.AG6uFsU
    var div = getNumberKeysDiv();  // 获得id为nubmerKeys的<div>标签ITPUB个人空间!O3G(c!E'{ ^
ITPUB个人空间#k`L F8}rb&T5^
    tryITPUB个人空间&ZD3Mz)m_&z&\f
    {
3sM/Ji1Wj@"bIX5GZ0        if(div)
9| zW5CI&N0        {ITPUB个人空间Um4A\~
            // 删除<div>中的所有子元素ITPUB个人空间%c"^ W"na L z:{w*I
            for(var i = div.childNodes.length - 1; i >= 0; i--)
?hrq hl1d%C*ET0            {
YT"Mrg!^8W&X-[0                tryITPUB个人空间l)D(R:f3S`
                {   
#f5xg.b.{lG&M0                    div.removeChild(div.childNodes);ITPUB个人空间&Za[!~i[0KS:@
                }
#_Up,W*lh0                catch(e)
}R+\&\,s]z \8k9X?0                {                    
kg c,b*w0                }            ITPUB个人空间{&^6Jn Z9_2hB;D
            }ITPUB个人空间6mH]l~%MW
            // 为<div>标签加10个子<div>标签ITPUB个人空间8pwM4D2A A7sE0_^G
            for(var i = 0; i < 10; i++)ITPUB个人空间qFa^s:o \[Yo
            {
Y7s7Y}.pq&h0                var button = document.createElement("div");
s(|8U+iN&RsG0            ITPUB个人空间vx/Lh6rYz
                button.className = "button";        
k[w!|)f2cQ0                button.style.left = i * 61 + "px";ITPUB个人空间'q Qo2_9X5V
                button.style.backgroundColor = getRandomColor();
(z(w,S/c P8K)g}E0                button.style.border="solid 1px";ITPUB个人空间$Nj I|s8nz(}
                button.style.textAlign = "center";
k$Cc ?A:RX/p0                button.style.lineHeight = "50px";      
,PK)w ucL.I)H0                button.style.color = getRandomColor();ITPUB个人空间`n5Q8Fi
                        ITPUB个人空间-V7[1DwDE0FHY
                button.onclick = buttonOnClick;
syH0N1H6o0            
v&TQZp r{8[F y0                div.appendChild(button);               
T,} Sx)|,p5[KXn0                button.innerHTML  ="<b>" +i + "</b>";               
:{Fs g(ds\5V0            }            
{p+pr\e?7a0        }ITPUB个人空间*}5X^ H a,T
    }ITPUB个人空间Q"g]]j rDR^
    catch(e)ITPUB个人空间H`+~Z8[EAc nO
    {ITPUB个人空间 Nt8r+~dJ
    }            
q }.gl x?k0}ITPUB个人空间[X4P%_lf`

0?j ZM;Bvg'i0    addButton函数的基本实现原理是先将<div>中的所有元素删除,再向其中加入10个<div>标签。在addButton函数中有几个关键的函数需要讲解一下。
A ^*Efb3i0ITPUB个人空间y{6WQD U
getNumberKeysDiv函数
9HO,HSo"A~8vFf0    这个函数用于获得叫numberKeys的<div>标签,实现代码如下:
Z%o_nSe&g)_0ITPUB个人空间M aZx fnC{
function getNumberKeysDiv()
^8S%X+}0e0{
&b&~ k SN0    var divs = document.getElementsByTagName("div");ITPUB个人空间pp8~ a Q!]|k1S
   
y+\%YsZQn0    if(divs)
`;q$jS `2x!iL.|eF@0    {
;cF}a#MILt0        for(var i = 0; i < divs.length; i++)ITPUB个人空间R6uzJ(Zh
        {ITPUB个人空间7b/Cq9uk+gt
            var div = divs;ITPUB个人空间7~[&fg2M;{/k(vN/sZ
            ITPUB个人空间7c1L-B Y2~
            if(div.className.toString().indexOf("numberKeys", 0) > -1)
C@:A.PGC5Q0            {  ITPUB个人空间/z3iY+u3I:y,g
                return div;               ITPUB个人空间 E0c/v1uq'U&C ?d@8{
            }
v[M'e;bie0        }
i}%^Q]0    }
"?fs%zcM~0}ITPUB个人空间t/Zh N*h k

x)gbt q3Q5U-Pf0    这个函数并不是直接通过<div>的id找到这个<div>,而是通过<div>的class属性,这样可能更灵活,因为如果通过id找<div>,就必须要求美工必须将这个<div>命名为numberKeys,而如果通过查找包含numberKeys的class属性的<div>会对美工的限制更少。因为,只有这个<div>才会使用css中的numberKeys。
*E?fa#t|9c1y0ITPUB个人空间-~aM0d,db#J D[
getRandomColor方法
-U"f*] |!_+G`0这个方法获得了一个随机的演示,返回了字符串类型,格式#FFFFFF。实现代码如下:ITPUB个人空间 [(Y`*]y ?p8f
ITPUB个人空间[g9W F*@w8z
function getRandomArbitary(min, max)
m5Ov Q1y%l#n$y$C0{   
i,f%~q*o0    return Math.round(Math.random() * (max - min) + min);
8G8]`)gl2D0}ITPUB个人空间BjE_0|!hc
function getRandomColor()
Pcs r]^b0G0v5^'Yd0{
;a[L7]#yP:|@0    var red = getRandomArbitary(0, 255).toString(16);   ITPUB个人空间3@b]7p R#d4gm
    var green = getRandomArbitary(0, 255).toString(16);
^yR ? E3Qez,CE0    var blue = getRandomArbitary(0, 255).toString(16);ITPUB个人空间^0P c F r*j
    if(red.length == 1) red = "0" + red;ITPUB个人空间OzD)f2_#Z
    if(green.length == 1) green = "0" + green;
IF$X7t+HD:O4]GQ4eQ*{\0    if(blue.length == 1) blue = "0" + blue;ITPUB个人空间&N1Jr1EYZX.gn+YY o
   
P$RB)G:C~7^9f0    return "#" + red.toString(16) + green.toString(16) + blue.toString(16);ITPUB个人空间:GsyH)tvF*[#G
}
,go~szz0
#e:O7kk D9c*b"R0    getRandomColor通过getRandomArbitary函数获得了三个十进制的随机数(0-255),并将其转换为16进制,并返回最终结果。ITPUB个人空间)e8gk4zKc

+cCy%O8aB6w%hH.~0buttonOnClick函数
$NjgB Z-i)S0
@,^oR5tMNg a0这个函数是<div>标签的onclick事件函数,实现代码如下:ITPUB个人空间.ms^ps Z|
ITPUB个人空间.Q:r]7F0f'[ F1u De0U@
function buttonOnClick()
mtAKuz0{ITPUB个人空间z{x3]!e/O]9H k
    var text = document.getElementById("numbers");   
/P;kPb X,t2['g)?2r0    if(typeof this.innerText == "#ff0000")ITPUB个人空间T*Au;l2O[5?/q#P,J
        text.value = text.value + this.textContent;   
v%MLU+O Z'v0    elseITPUB个人空间'e,Y;e DE,R
        text.value = text.value + this.innerText;   
!X~E"em+a`2ZK0    this.style.backgroundColor = getRandomColor();              ITPUB个人空间,U ]F,p6R+V(Qm[
    this.style.color =  getRandomColor();
O_-}f%dF0   ITPUB个人空间m4n0u-b:R*{%R
}
/lR)l|3OBi i]yR6H0ITPUB个人空间|h1j]+Wf
    这个函数实现很简单,它的功能是将相应<div>标签中的数字追加到numbers文本框中。只是考虑了firefox和ie的不同。在firefox中,获得<div>中的文本要使用textContext,而在ie中要使用innerText。最后再将当前点击的<div>和数字的颜色再次变换。ITPUB个人空间fHt_4yY1Xc-?

u1|_(K PP0    到现在为止,还有两个事件函数代码没有给出,这两个事件函数是onKeyup和stopAndStartTimer。
G(S J"wB8~ {j0ITPUB个人空间&g,~ SC$[A^v?/r
    onKeyup函数
C?1dG j&o0    当numbers文本框输入一个字符后,发生这个事件,实现代码如下:
[P+\p;SP I0
d eB5}-rLz7{'F O0function onKeyup()
,hYD1Uk(T+P0{ITPUB个人空间O&`4a2@-Va
    var value = this.value;
1Q$Nx5G!fa0    if(value.length == 0) return;
hK`T`'^B7M0    var i = value.toString().substr(value.length - 1, 1);ITPUB个人空间 D Rn H!wL
    if(isNaN(i) == false)
uqw-I.]u'K0    {   
x'R(@-ONR{5L/f$OG0        var div = getNumberKeysDiv();   ITPUB个人空间a(e.~!M;sL0ZH
        if(div)ITPUB个人空间 \Vc AE#RR\
        {ITPUB个人空间9oL,z]+r+^%J8o
            var button = div.childNodes;
N'F/Dbfn)t5^0            button.style.backgroundColor = getRandomColor();              ITPUB个人空间jPA)u}Q)h7Scj.ok
            button.style.color =  getRandomColor();
F'ORG MK.?S;Ai"i0         ITPUB个人空间3VS n{ C#R+H
        }ITPUB个人空间DVF Ms1H)R,l
    }ITPUB个人空间 q-_rJE8_
}ITPUB个人空间Qq U|8m%^

'@KR'xz0    这个函数的实现代码也很简单。只是根据用户在文本框中输入的数字来找到相应的<div>标签,并再次随机变换<div>背景和数字的颜色。
(Z ~:Rn o2]0ITPUB个人空间o;Oi%_Dmh
stopAndStartTimer函数ITPUB个人空间4a9^1W{l-yQ

eL"TTy5tER0这个函数是用来控制定时器的,如果启动定时器,浏览器会每隔3秒重新使<div>随机变化一次颜色。实现代码如下:
(n6VD!\'~Ts0
:_QS%@2Hu4Ok`0var time;
0k!_@r;Qe0
TyW/N%VZ"F3xL0function stopAndStartTimer()ITPUB个人空间.eF4E9UY2_
{
.e,^:Kwh:i$O0    if(this.value.toString().indexOf("停止",0) > -1)
$a iF"j{#_0    {ITPUB个人空间"_ f5u5X;m Q/Z
        this.value = "开始变换颜色";ITPUB个人空间*G_I*X)Jv
        clearInterval(time);            
&oQyIu0    }ITPUB个人空间9n J)iUw x l
    elseITPUB个人空间S!h/W` m&B&P
    {ITPUB个人空间,a7l*])Z*@&M8k3a
        this.value = "停止变换颜色";ITPUB个人空间$f ^])X-[C
        time = setInterval(onLoad, 3000);
pp0mlk3Q(]#~0    }
%p&J!R:k4r]0}
%|[B O,i%Z%p8\;o @0
7is&`*{4r8j*cV,YO0    从上面给出的代码可以看出,在View层,除了<script>引用了一个javascript文件外,并未涉及任何和逻辑有关的代码。而设计界面的美工也并不知道开发人员会为<div>及其他的按钮和文本框添加什么动作。而美工要做的是调整和界面有关的东西,如颜色,位置,分割等。只要使用<script>引用了这个js文件,就可以很容易加入相应的动作,而要将这些动作去掉,删除或注释掉这个<script>标签即可。ITPUB个人空间~o`b^#E2K

BR/ld*an0    尤其要提一下<div>标签,美工在设计界面时可以向这个<div>标签添加任何子元素。而在加入addevents.js后,程序会自动将由美工向<div>标签中的加入的内容都删除,而加入由业务逻辑需要的元素。这样美工用来设计界面的元素就不会影响开发人员需要加入的和业务逻辑有关的元素了。
6n(lT'gr[0ITPUB个人空间q.E;`6qb#]2D'm7z
    根据上面的代码不难看出,numberKeys.html属于视图层,所有的事件函数属性模型层,而其他的javascript代码都属性控制器(Controller)。

TAG:

sunly1225的个人空间 sunly1225 发布于2008-05-22 17:15:30
不错,不错,是个好思路,
_9t-M$fZmITPUB个人空间收藏,多谢分享!
我来说两句

(可选)

日历

« 2008-09-07  
 123456
78910111213
14151617181920
21222324252627
282930    

数据统计

  • 访问量: 9799
  • 日志数: 106
  • 建立时间: 2008-02-08
  • 更新时间: 2008-09-05

RSS订阅

Open Toolbar