2008年1月25日星期五

艰难的实验——Prototype Window试用手记

现在终于能够深切的了解公司开发一定要使用成熟的技术,这样一句话的含义了。因为使用了DNN做产品的架构,所以在进行设计的时候,希望可以让用户较为灵活的做一些选择,于是采用了已经看了若干时间的Prototype Window,用它来做DIV的弹出窗口、Dialog,而不是Javascript传统意义上的ShowModalDialog。不过过程并不顺利,发现了太多问题,到目前为止,还有一个很关键的问题没办法解决,如果这个问题得不到解决的话,简直就没办法进行下去了。

第一个问题就是由于基于DNN的架构,所以最好不要使用aspx页面的问题:DNN的架构中,整个框架都是基于一个default.aspx文件;而且基本上整个网站就只有一个aspx文件,这个文件用来动态的加载其他的用户控件(ascx文件)。DNN所提供的模块开发手册,都是基于这种架构的,也就是说,全部都是开发ascx文件,而不是增加aspx文件。因此,在对系统进行扩展的时候,如果仍然采用aspx文件的话,将会大大的削弱系统的扩展性。包括皮肤、各种参数等,都很难从环境变量中获取。最简单的就是ModuleID、UserID这样的参数,需要通过URL来传递,这样做并不好。所以,尽量不要使用ShowModalDialog方法来弹出一个新的aspx页面。

Prototype提供了一个较好的选择,就是在本页面中,可以创建一个win对象,弹出一个普通的DIV窗口;或者是可以通过Dialog.confirm方法,来弹出一个对话框。这两种问题都不大,但是问题是,一开始看到的创建Window的方法,都是外挂一个url参数,通过这个参数来传递数据的,比如,可能如下所示:

win = new Window({url: "123.htm", className: "spread", height: "400", width: "400", okLabel:"Send", destroyOnClose: false});

其中,url参数就是用来传输一个URL的,这里的URL,就不能是ascx文件,因为ascx文件是不能单独作为一个页面被访问的。所以,一直找不到好的办法,不知道该怎么办;直到后来发现了Dialog对象可以支持一个隐藏的DIV的内容,这个DIV的内容就是在同一个页面里面的,只不过是缺省被隐藏而已。如下所示:

Dialog.confirm($('test').innerHTML, {className:"alphacube", height:400, width:400, onOk:function(win){ alert('OK'); return true;}, destoryOnClose:false});

其中的test,就是一个在本页面中定义的DIV,可能是这样的:

<div id="test" style="display:none">
Hello,World
</div>

用这种方式,可以将本页面上一个隐藏的div“提取”到Prototype Window的窗口上,这样,就不用去创建新的aspx页面了,使用的方便程度会比较高。

但是,如何让一个Window也支持Div呢?

一开始没找到,后来才发现,原来定义Window的时候,可以使URL参数为空,这样的话,就可以用win.getContent().update()方法,将隐藏的DIV的内容赋值到窗口中,所以,如果要显示一个本页的DIV,代码是这样的:

win = new Window({className: "spread", height: "400", width: "400", okLabel:"Send", destroyOnClose: false});
win.getContent().update($('test').innerHTML);
第二个问题就是如何返回值,根据目前所看到的,win好象是没有返回值的,所以不知道如何返回;而Dialog则是可以返回值的;而且,目前的Window,还不知道怎么样关闭(除了右上角的关闭按钮、以及定义的ESC关闭键之外)。于是,就采取了第一个弹出的是Window、本页的DIV(这样,当页面Postback的时候,当前的弹出DIV会自然的被关掉),而第二个弹出的选择窗口则是一个Dialog.confirm(这样,可以返回值)。为了在第二个页面上使用到asp.Net的PostBack,干脆就同样在本页上定义了另外一个隐藏的DIV,但是这个DIV中包含一个iFrame,iFrame链接到另外一个页面。

于是,最终的情况是这样的:
第一个页面:

<html>
<head>
<script language="javascript" type="text/javascript">
function Popup1()
{
win = new Window({className: "spread", height: "400", width: "400", okLabel:"Send", destroyOnClose: false});
win.getContent().update($('test1').innerHTML);
}

function Popup2()
{
Dialog.confirm($('test2').innerHTML, {});
}

</script>
<body>

<a href="javascript:Popup1()">Popup1</a>

<div id="test1" style="display:none">
<a href="javascript:popup2()">Popup2</a>
</div>

<div id="test2" style="display:none">
<iframe frameborder="0" src="another.aspx">
</iframe>
</div>

</body>
</html>

简单的来说,就是在第一个窗口里面弹出第二个窗口,然后由第二个窗口返回值。结果……

  1. 这种情况下,如果第二个窗口没有PostBack倒还没问题,但是如果有PostBack的话,经常会导致当前窗口的任何控件都没办法获取焦点(还不是失去焦点,一般的失去焦点只要鼠标Click一下就可以了;但是这里的是完全没有任何办法获取焦点,即使是按下CTRL+A也没办法选中任何内容,整个页面完全是“死”的,只有链接可以点,asp:TextBox控件完全不能做任何的输入动作,除非是手工刷新一下页面;
  2. 这种情况下,设置了ESC作为Close键,第一次是正常的,先关闭第二个窗口,然后再关闭第一个窗口;但是如果再次打开两个窗口的话,按下ESC键的时候,所有的窗口都会同时关闭掉,这个还是小事;
  3. 这种情况下,第一次的客户端赋值的Script运行正确,但是如果页面没有刷新(等于是取消操作),然后再重复的话,就没办法正常的取道值了;
  4. 以上的情况是在IE浏览器下;在Firefox下倒是不会失去控件的焦点,但是显然其他的问题还是没办法解决;

正在痛苦之中……,或许不应该用Prototype Window,尽管它看起来那么漂亮……

没有评论: