引子
昨天晚上做一個項目,遇到的一個問題,這個項目是一個在線考試系統,新建一份試卷的頁面,要添加一些試題策略。點擊添加試題策略,彈出添加策略的頁面,策略編輯好之后提交,添加策略頁關閉,當前添加試題頁面策略列表刷新。那么就遇到一個問題,在“添加試卷頁”中點擊“添加策略”按鈕彈出添加策略頁,添加策略后,父頁面只能局部刷新(整體刷新會丟掉頁面輸入框未保存的數據)。
綜上總結,濃縮成一句話啊,就是“父頁面打開子頁面,子頁面完成操作后觸發父頁面的事件。”
過程
我在百度和必應里面搜一下,很多解決方案是用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>"); } } }
WebForm2.aspx.cs
以上都是轉載部分。。。。
我的項目的實際情況和引子描述基本一致,原作者用的是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());
}
這樣就完成了,點擊子頁面上的某個按鈕來觸發父頁面局部刷新






