菜鸟解决“子页面关闭刷新父页面局部”问题的历程

引子

      昨天晚上做一个项目,遇到的一个问题,这个项目是一个在线考试系统,新建一份试卷的页面,要添加一些试题策略。点击添加试题策略,弹出添加策略的页面,策略编辑好之后提交,添加策略页关闭,当前添加试题页面策略列表刷新。那么就遇到一个问题,在“添加试卷页”中点击“添加策略”按钮弹出添加策略页,添加策略后,父页面只能局部刷新(整体刷新会丢掉页面输入框未保存的数据)。

      综上总结,浓缩成一句话啊,就是“父页面打开子页面,子页面完成操作后触发父页面的事件。”

过程

      我在百度和必应里面搜一下,很多解决方案是用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>
WebForm1.aspx
技术分享
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");

        }
    }
}
WebForm1.aspx.cs
技术分享
<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>
WebForm2.aspx
技术分享
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>");
        }
        
    }
}

WebForm2.aspx.cs

 下载Demo源码

以上都是转载部分。。。。

我的项目的实际情况和引子描述基本一致,原作者用的是window.open来弹出窗口。我用的是div包着iframe情况略有不同但是大同小异。

子页面触发父页面局部刷新按钮事件

protected void Button1_Click(object sender, System.EventArgs e)
		{
            ScriptManager.RegisterStartupScript(Page, this.GetType(), "msg", "parent.window.document.getElementById('txt_tx').value='" + Request.Form["xz"] + "';parent.window.document.getElementById('btnTixi').click();parent.layer.close(parent.layer.getFrameIndex(window.name))", true);
		}

 这里我用了layer框架的弹窗,并且给隐藏的textbox赋值,达到页面之间传值的效果。而父页面也是有一个隐藏的button等待子页面来触发,做局部刷新用

<div style="display: none;">
                    <asp:Button ID="btnTixi" runat="server" Text="Button" CausesValidation="false" OnClick="btnTixi_Click" />
                </div>
protected void btnTixi_Click(object sender, EventArgs e)
        {
            xs_fw(this.txt_tx.Text.Trim());
        }

这样就完成了,点击子页面上的某个按钮来触发父页面局部刷新


原文地址:https://www.cnblogs.com/yanergui/p/5624771.html