菜鸟解决“子页面关闭刷新父页面局部”问题的历程
引子
昨天晚上做一个项目,遇到的一个问题,这个项目是一个在线考试系统,新建一份试卷的页面,要添加一些试题策略。点击添加试题策略,弹出添加策略的页面,策略编辑好之后提交,添加策略页关闭,当前添加试题页面策略列表刷新。那么就遇到一个问题,在“添加试卷页”中点击“添加策略”按钮弹出添加策略页,添加策略后,父页面只能局部刷新(整体刷新会丢掉页面输入框未保存的数据)。
综上总结,浓缩成一句话啊,就是“父页面打开子页面,子页面完成操作后触发父页面的事件。”
过程
我在百度和必应里面搜一下,很多解决方案是用window.showModalDialog来实现的,因为它有返回值,可以根据返回值来实现。但是chrome37以后就不支持window.showModalDialog,考虑兼容性,就不能使用window.showModalDialog。所以说,只能用window.open打开,但是window.open没有返回值,所以只能在子页面中想办法触发父页面的事件。
当时第一反应想到的就是,在父页面写一个公用事件,让子页面调用,很傻的一个想法,这想法实在太不靠谱了(但是我觉得程序员还是要敢于想象),因为每个页面都是一个对象实例,你调用公用方法,都不知道是在作用那个页面,其次,被直接调用的必须是静态方法,静态方法又是不能对页面控件做直接操作的,如果不是静态方法,就需要new一个页面,完全没有意义。
接着想着从C#中来获取父页面,从而触发父页面的事件,找了一个发现,C#并没有好的方法能获取到父页面。那么就只能从js入手,我对js不是太了解,菜鸟都算不上的菜鸟,我的想法就是用js找到父页面(js在找父页面还是很方便的)。搜了一下,有下面几种方法:
window.opener.document在页面运行结果如下:
window.parent.document在页面运行结果如下:
发现:
window.opener.document获取的是父级页面。
window.parent.document获得的是本身,很奇怪了。
之后查阅了一些资料得出结论:
window.parent能获取一个框架的父窗口或父框架。顶层窗口的parent引用的是它本身。
window.opener引用的是window.open打开的页面的父页面。
opener即谁打开我的,比如A页面利用window.open弹出了B页面窗口,那么A页面所在窗口就是B页面的opener,在B页面通过opener对象可以访问A页面。
parent表示父窗口,比如一个A页面利用iframe或frame调用B页面,那么A页面所在窗口就是B页面的parent。
之后,就很顺利了的使用“window.opener.document.getElementById('Button1').click(); ”触发页面事件(我实现的是通过一个按钮来实现这个事件)。我们可以把这个按钮隐藏起来。
经过以上种种实验和思考,终于实现了通过子页面js触发父页面某个按钮的单击事件,实现子页面刷新父页面局部数据的方法。
结果
截图如下:
打开父页面,在文本框中随便输入一些内容(便于测试是不是仅仅刷新了局部)。
点击打开子页面:
点击刷新父级页局部
可以看出,父页面仅仅局部被刷新了。
<html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>父级页</title> </head> <body> <form id="form1" runat="server"> <div> <label runat="server" id="label1" style="color:blue"> 原始标记</label> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <input type="button" value="打开子页面" onclick="window.open('WebForm2.aspx')" /> <div style="display: none"> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" /> </div> </div> </form> </body> </html>
using System; namespace WebDemo { public partial class WebForm1 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void Button1_Click(object sender, EventArgs e) { label1.InnerText = "被局部刷新了"; label1.Style.Add("color", "red"); } } }
<html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>子级页</title> </head> <body> <form id="form1" runat="server"> <asp:Button ID="Button1" runat="server" Text="刷新父级页局部" OnClick="Button1_Click" /> </form> </body> </html>
using System; namespace WebDemo { public partial class WebForm2 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void Button1_Click(object sender, EventArgs e) { Response.Write("<script language='javascript'>window.opener.document.getElementById('Button1').click(); </script>"); } } }