jQuery:动态改变html表单的目标页(Target)

看到Rick Strahl的最新博客Changing an HTML Form’s Target with jQuery,读完之后感觉文中给出的解决方案很简单很实用。借鉴原文,断断续续重新整理小结一下,本文最后提供一个简单demo下载,希望对您也有帮助。

1、问题来源

“页面中有一个form,有些个submit按钮或者链接按钮需要点击后打开新页面。我们如何让这些个按钮将表单信息提交到正确的对应页面?”

这个问题看上去很简单。

熟悉asp.net开发的都应该很清楚,通过asp.net webform,我们可以对runat=”server”的form进行属性设置:

<form method="post" action="default.aspx" id="form1">

如你所知,method属性是http数据传输方法,action属性是要提交的目标页,至于打开新页面,设置target为_blank即可。

对于通常的页面交互,一个或多个按钮提交一个相同的表单这样做没有问题,可是如果按钮需要post的页面不尽相同,这个方法就显得无能为力。因为这种解决方法是“全局”的,设置一次,影响所有表单提交元素。

2、runat=server的form

到这里,也许有人会“幸灾乐祸”地说这都是web form的form机制不好,一个页面只能有一个runat=server的form。我们完全可以在一个页面中多定义几个form,对于不同的提交按钮,我们给它设置不同的form(即分割提交按钮到不同的表单),这样不就解决问题了吗(新浪、网易和搜狐等很多页面,打开一个网页并查看源码可以看到很多form,我估计都是这么用的)?

但是,这不是web form独有的“错”,其他开发框架也有类似问题:

Although this discussion uses ASP.NET WebForms as an example, realistically this is a general HTML problem although likely more common in WebForms due to the single form metaphor it uses. In ASP.NET MVC for example you'd have more options by breaking out each button into separate forms with its own distinct target tag. However, even with that option it's not always possible to break up forms - for example if multiple targets are required but all targets require the same form data to the be posted.

原文的评论中一个哥们回复说:

“Good post, as always, but have you noticed that literally everything you want to do with webforms requires a hack or workaround? It's always some rudimentary thing that is easy to do in any other web platform or framework, but the webforms abstraction always rears it's ugly head. Bleh, the further I get away from webforms, the more productive I have become.

”ugly“一词用的真是形象且险恶。好在Rick及时回复说:

# re: Changing an HTML Form's Target with jQuery
by Rick StrahlFebruary 03, 2011 @ 12:00 am @Jeff - this isn't specific to WebForms as I pointed out at the top of the page. The same applies to MVC or any other framework that has multiple POSTable options for submission. Admittedly, with WebForms your options are more limited as you can't easily add additional forms, but when you need to submit form variables to multiple target actions there are no choices regardless of platform...

还有,我感觉回复者Jeff这个名字挺有喜感的。

3、简单实用的解决方案

(1)、直接使用linkbutton或者链接控件?

通常情况下,我们很容易想到用现成的link控件的属性来实现页面提交。比如LinkButton吧:

  <asp:LinkButton runat="server" ID="btnNewTarget" Text="New Target" 
                     target="_blank"  OnClick="bnNewTarget_Click" />

虽然LinkButton没有Target属性,但是像上面那样设置也没有问题。

但是,最怕的就是这个但是。在查看生成的html源码的时候:

<a id="btnNewTarget" target="_blank"    href="javascript:__doPostBack(&#39;btnNewTarget&#39;,&#39;&#39;)">New Target</a>

我们发现生成的html源码里a元素的href属性已经被设置了一段让人眼熟的控制回发脚本。就是这一段脚本,让我们提交数据到新窗口的目的落空。为什么呢?

What happens with a target tag is that before the JavaScript actually executes a new window is opened and the focus shifts to the new window. The new window of course is empty and has no __doPostBack() function nor access to the old document. So when you click the link a new window opens but the window remains blank without content - no server postback actually occurs.

原文解释的还算清楚简单,good,fabulous,excellect…词穷。

(2)、为这些个按钮设置form的Target吧!

通过下面的脚本,可以轻松实现我们的预定功能:

    $("#btnButtonNewTarget,#btnNewTarget").click(function () {
            $("form").attr("target", "_blank");
        });

对于同一个页面post(示例中是default.aspx页面),它和(1)的效果截然不同。可能您习惯要问为什么,原文是这样解释的:

So why does this work where the target attribute did not? The difference here is that the script fires BEFORE the target is changed to the new window. When you put a target attribute on a link or form the target is changed as the very first thing before the link actually executes. IOW, the link literally executes in the new window when it's done this way.
By attaching a click handler, though we're not navigating yet so all the operations the script code performs (ie. __doPostBack()) and the collection of Form variables to post to the server all occurs in the current page. By changing the target from within script code the target change fires as part of the form submission process which means it runs in the correct context of the current page. IOW - the input for the POST is from the current page, but the output is routed to a new window/frame. Just what we want in this scenario.

看原文这里可能有点绕人,解释太多,有点抓不住重点。我认为关键要理解原文中的“表单提交进程(form submission process)”。点击按钮的时候,在当前页面通过脚本改变表单的Target,这只是表单提交进程的一部分(By changing the target from within script code the target change fires as part of the form submission process)。

那么真正的“表单提交进程”发生了什么呢?顺着原文的意思,看上去好像是新页面打开,前一页的表单数据提交到新打开的页面,貌似是前一页(current page)的_doPostPack函数“跳”到当前新打开的页面(也叫current page)触发ClickHandler……不就是“current page”的置换吗?可能我自己的理解现在还有偏差,英语水平下降得令人抓狂,必须要补补了。如果您有更合适的好理解的解释说明,请不吝赐教。

多说一句,点击前一个页面,在新打开的页面触发事件。我kao,这多像江湖中传说已久的乾坤大挪移啊?

By the way,我们还可以在不同的新页面中post传参,您可以将demo中的Default页面的form的action设置为“TargetPage.aspx”试一下。其实我自己在开发中也曾经碰到过Rick文中所述的类似问题。我的解决方法通常都是对于某一个按钮,直接通过javascript写个函数:先找到要操作的form,修改action,然后调用form的submit方法打开新窗口,真不如Rick原文中的来得简洁。

demo下载:SimpleWebApp

posted on 2011-02-14 19:28  JeffWong  阅读(18126)  评论(5编辑  收藏  举报