AppBox v6.0中實現子頁面和父頁面的複雜互動
前言
AppBox v3.0中的子頁面向父頁面傳值
AppBox中實現子頁面向父頁面傳值,邏輯程式碼比較簡單,完全使用FineUI的內建封裝,沒有引入JavaScript程式碼。首先來看下實現效果:
當點選所屬角色的觸發器輸入框(TriggerBox)時,會在當前頁面彈出一個包含IFrame的窗體控制元件(Window),在其中選擇需要的資料後關閉。
父頁面程式碼和邏輯
在父頁面,我們通過一個 TriggerBox 來記錄選中的文字資訊,一個隱藏欄位 HiddenField 來記錄選中的值資訊:
<f:TriggerBox ID="tbSelectedRole"EnableEdit="false" EnablePostBack="false" TriggerIcon="Search" Label="所屬角色" runat="server"> </f:TriggerBox> <f:HiddenField ID="hfSelectedRole" runat="server"> </f:HiddenField>
點選 TriggerBox 觸發圖示的客戶端操作是通過伺服器端初始化的,這其實是符合FineUI最初的設計目標:儘量減少客戶端指令碼,降低程式碼複雜度。
privatevoid InitUserRole(User current) { tbSelectedRole.Text = String.Join(",", current.Roles.Select(u => u.Name).ToArray()); hfSelectedRole.Text = String.Join(",", current.Roles.Select(u => u.ID).ToArray()); // 開啟編輯角色的視窗 string selectRoleURL = String.Format("./user_select_role.aspx?ids=<script>{0}</script>", hfSelectedRole.GetValueReference()); tbSelectedRole.OnClientTriggerClick = Window1.GetSaveStateReference(hfSelectedRole.ClientID, tbSelectedRole.ClientID) + Window1.GetShowReference(selectRoleURL, "選擇使用者所屬的角色"); }
仔細觀察這段程式碼,可以看到FineUI的努力和身影,我們儘量將常用操作提取成公共的方法。
比如這裡的:
hfSelectedRole.GetValueReference()
則是返回一段JavaScript指令碼,本質上點選操作是客戶端完成的,因此需要在點選的時候獲取隱藏輸入框的值,而不是呼叫InitUserRole初始化的時候!!
再比如這裡:
Window1.GetSaveStateReference(hfSelectedRole.ClientID, tbSelectedRole.ClientID)
這是FineUI提供的另一個機制:告訴FineUI子頁面回發資料時,需要將資料儲存到父頁面的哪些控制元件中?
子頁面程式碼和邏輯
看完父頁面的程式碼,再來看下子頁面怎麼返回值。首先,子頁面有一個選擇的按鈕,和一個複選框列表控制元件:
<f:Button ID="btnSaveClose" ValidateForms="SimpleForm1" Icon="SystemSaveClose" OnClick="btnSaveClose_Click" runat="server" Text="選擇後關閉"> </f:Button> <f:CheckBoxList ID="cblRole" ColumnNumber="4" Label="所屬角色" ShowLabel="false" runat="server"> </f:CheckBoxList>
點選按鈕會觸發一個伺服器端事件:
protected void btnSaveClose_Click(object sender, EventArgs e) { string roleValues = String.Join(",", cblRole.SelectedItemArray.Select(c => c.Value)); string roleTexts = String.Join(",", cblRole.SelectedItemArray.Select(c => c.Text)); PageContext.RegisterStartupScript(ActiveWindow.GetWriteBackValueReference(roleValues, roleTexts) + ActiveWindow.GetHideReference()); }
首先獲取複選框列表中,使用者選擇的文字資訊和值資訊,然後通過 PageContext.RegisterStartupScript 向子頁面註冊一段指令碼。
在內部FineUI其實隱藏了很多複雜的邏輯:
1. 彈出窗體可以在父頁面彈出,可以在父頁面的父頁面彈出,也可以在頂層頁面彈出。
2. 如果在子頁面最快的找到我們所說的父頁面,而不是window.parent!!,這裡FineUI封裝了一個ActiveWindow類。
ActiveWindow表示的是當前啟用的窗體(也就是我們所說的子頁面IFrame所在的Window控制元件),用來聯絡業務邏輯上的子頁面和父頁面。
ActiveWindow.GetWriteBackValueReference(roleValues, roleTexts)
這段程式碼和前面的 GetSaveStateReference 相對應,用來將使用者選擇的值寫入父頁面相應的控制元件中。
至此,我們沒寫一行JavaScript程式碼,實現了子頁面向父頁面傳值這個本來需要JavaScript互動的示例。
AppBox v6.0中的子頁面和父頁面的複雜互動
首先一點宣告,AppBox v6.0雖然和 v3.0版本號變化很大,但是程式碼改變並不多,主要是為了跟著 FineUI(開源版)的版本走。
AppBox v6.0中,我們首先想做的一點改變是:為選擇角色的觸發器輸入框增加清空圖示!!
看下最後的實現效果:
之所以放了 5 張圖在這裡,是因為這是FineUI(開源版)v6.0.0中內建的 5 種主題。
看似一個簡單的改變,其實一點都不簡單,因為在子頁面傳值這個已有邏輯基礎上,還要進行清空圖示是否可見的邏輯改變:
1. 預設如果所屬角色存在值,則顯示清空圖示;否則不顯示清空圖示
2. 點選清空圖示時,清空兩個控制元件的值,然後隱藏清空圖示
3. 從子頁面返回資料時,需要顯示清空圖示
由於存在這些邏輯,FineUI內建的伺服器端做法已經滿足不了需求了。因為我們決定自己寫JavaScript程式碼來實現。
父頁面程式碼和邏輯
首先是將 TriggerBox 改為 TwinTriggerBox 控制元件,並在客戶端實現兩個觸發圖示的點選操作:
<f:TwinTriggerBox ID="tbSelectedRole" EnableEdit="false" EnableTrigger1PostBack="false" EnableTrigger2PostBack="false" Trigger1Icon="Clear" Trigger2Icon="Search" ShowTrigger1="false" ShowTrigger2="true" OnClientTrigger1Click="onSelectedRoleTrigger1Click();" OnClientTrigger2Click="onSelectedRoleTrigger2Click();" Label="所屬角色" runat="server"> </f:TwinTriggerBox>
預設是不顯示清空圖示的,所以需要在頁面載入完畢後,進行邏輯判斷:
var tbSelectedRoleClientID = '<%= tbSelectedRole.ClientID %>'; var hfSelectedRoleClientID = '<%= hfSelectedRole.ClientID %>'; function checkSelectedRoleTriggerStatus() { if (F(tbSelectedRoleClientID).getValue()) { F(tbSelectedRoleClientID).showTrigger1(); } else { F(tbSelectedRoleClientID).hideTrigger1(); } } F.ready(function () { checkSelectedRoleTriggerStatus(); });
然後再來看下點選兩個觸發圖示的操作:
function onSelectedRoleTrigger1Click() { F(tbSelectedRoleClientID).setValue(''); F(hfSelectedRoleClientID).setValue(''); checkSelectedRoleTriggerStatus(); } function onSelectedRoleTrigger2Click() { F('Window1').f_show(F.baseUrl + 'admin/user_select_role.aspx?ids=' + F(hfSelectedRoleClientID).getValue() + '', '選擇使用者所屬的角色'); }
點選第二個觸發按鈕時,會彈出包含IFrame頁面的Window控制元件,並向IFrame地址傳入角色值資訊。
同時,我們還需要一個函式供子頁面呼叫(更新使用者所屬角色的兩個控制元件值):
function updateSelectedRole(roleNames, roleIds) { F(tbSelectedRoleClientID).setValue(roleNames); F(hfSelectedRoleClientID).setValue(roleIds); checkSelectedRoleTriggerStatus(); }
子頁面程式碼和邏輯
子頁面點選選擇按鈕時,所有程式碼邏輯在客戶端完成,這樣也減少了一個HTTP回發:
<f:Button ID="btnSaveClose" ValidateForms="SimpleForm1" Icon="SystemSaveClose" EnablePostBack="false" runat="server" Text="選擇後關閉"> <Listeners> <f:Listener Event="click" Handler="onSaveCloseClick" /> </Listeners> </f:Button>
在客戶端指令碼,我們需要完成幾個邏輯:
1. 通過JavaScript程式碼獲取複選框列表的文字和值資訊
2. 獲取對應的業務父頁面(不是window.parent!!)
3. 呼叫父頁面的 updateSelectedRole 函式
4. 關閉彈出窗體
下面來看下實現程式碼,還是很清晰的:
var cblRoleClientID = '<%= cblRole.ClientID %>'; function onSaveCloseClick() { // 資料來源 - 複選框列表 var cblRole = F(cblRoleClientID); var roleNames = [], roleIds = []; cblRole.items.each(function (item) { // 是否選中 if (item.getValue()) { roleNames.push(item.boxLabel); roleIds.push(item.inputValue); } }); // 返回當前活動Window物件(瀏覽器視窗物件通過F.getActiveWindow().window獲取) var activeWindow = F.getActiveWindow(); activeWindow.window.updateSelectedRole(roleNames, roleIds); activeWindow.f_hide(); }
獲取複選框列表的值,用到了 extjs 公開的API介面,不難。
而獲取業務父頁面就不那麼簡單了,原因前面已經提到了,要特別注意,這個業務父頁面不是window.parent!!!!
FineUI也提供了相應的客戶端介面:
1. F.getActiveWindow() 獲取子頁面所在的Window伺服器控制元件物件(不是JS的window物件)
2. F.getActiveWindow().window 獲取業務父頁面所在的window物件(注意不是Window伺服器控制元件)
理解這兩個介面後,就簡單了,呼叫父頁面定義的 updateSelectedRole 函式:
F.getActiveWindow().window.updateSelectedRole(roleNames, roleIds);
小結
通過本篇文章的介紹,我們知道了如何不寫一行JavaScript程式碼來實現子頁面向父頁面傳值。而對於複雜的互動邏輯,我們也可以手工寫JavaScript程式碼來實現。
由於子頁面在作為IFrame放在Window控制元件中的,而Window控制元件可以在父頁面彈出、可以在父頁面的父頁面彈出,也可以在頂層頁面彈出,這就讓如何在子頁面中獲取業務父頁面變得撲所迷離(不是window.parent!),幸運的是FineUI對此提供了伺服器端支援(ActiveWindow類)和客戶端的支援(F.getActiveWindow函式)。
關於開源和堅持
AppBox作為FineUI(開源版)的一個演示專案,從 2009 年就一直存在了,期間經歷了 v3.0 的大版本更新,其他版本的改動都不多。但是我們一直在更新FineUI(開源版)和AppBox,至今已經有 8 年時間了。
8 年間,我們看過太多的開源專案轟轟烈烈的來,平平淡淡的去,那些曾經熟悉的身影,曾經陪伴我們的程式碼,都已經不復存在。其實很多時候,開源專案不是被新技術淘汰,而是被開源作者所丟棄,不免讓人扼腕嘆息。
每個存在都有存在的價值,時間總會讓之前的東西看起來不再那麼新奇好玩,但是還有那麼一幫曾經關注的網友,一直在使用的使用者,只有不斷的更新,才不會讓關心你的人失望。
任何事物的存在價值是無限的!
相關推薦
AppBox v6.0中實現子頁面和父頁面的複雜互動
前言 AppBox v3.0中的子頁面向父頁面傳值 AppBox中實現子頁面向父頁面傳值,邏輯程式碼比較簡單,完全使用FineUI的內建封裝,沒有引入JavaScript程式碼。首先來看下實現效果: 當點選所屬角色的觸發器輸入框(TriggerBox)時,會在當前頁面彈出一個包含IF
C#中實現 子窗體控制呼叫父窗體成員和控制元件
因專案需要,我要在一個子窗體form6中呼叫建立它的父窗體form4的一個combobox的方法和屬性。 網上搜集的,沒有統一答案,試驗了下。 可行方法如下: 在form6的class類定義中加入一個私有成員變數,用來記錄父窗體; private form M; 在f
js中實現子頁面向父頁面中賦值
父頁面: <input id="input1" type="text" /> <ahref="javascript:GetReturnValue();void(0)">彈出新的模態子視窗</a> <script type="text/javascript" langu
Java中實現String.padLeft和String.padRight
toc 還要 color for 失去 1-1 arraycopy ace pre 因為習慣了C#中的padLeft和padRight,接觸Java後突然失去這兩個功能,覺得別扭,就試著實現了這兩個方法。 Java中String.format()中帶有字符串對齊功能如下
對象序列化中 子類和父類構造函數的調用問題
images png http 分享 com 函數 對象 情況 序列 第三種情況: 對象序列化中 子類和父類構造函數的調用問題
ThinkPHP5.0中Redis的使用和封裝
ted ids 數據緩存 目錄 代碼 插入 comment number efi Redis是一種常用的非關系型數據庫,主要用作數據緩存,數據保存形式為key-value,鍵值相互映射.它的數據存儲跟MySQL不同,它數據存儲在內存之中,所以數據讀取相對而言很快,用來做高並
vue2.0中實現首字母大寫的過濾器
過濾器1:實現一個首字母大寫的過濾器(vue2.0中已經去除了內置的過濾器)過濾器本身就是一個函數vue2.0中實現首字母大寫的過濾器
【轉】子類和父類實現同一個接口的意義
style inf bottom 父類 100% csdn 一個 article mage 原文作者的疑惑和我的一模一樣...所以沒什麽好解釋的,直接截圖參考即可。原文鏈接:子類和父類實現同一個接口的意義 - CSDN博客 https://blog.csdn.net/s33
Android中實現短音訊和震動的一些總結
好長時間沒有寫部落格了,因為最近事情比較多。所以好長時間沒有寫部落格了。堅持是一件很辛苦的事情。但還需要努力。。。好了,閒話不扯了。因為最近專案中用到了相應的短音訊和震動的功能,所以這裡總結一下相應的內容! 本文知識點: 音訊中的一些知識和常用的API介紹;
關於子類和父類中的this的用法
1 public class Demo { 2 public static void main(String[] args) { 3 Fu f = new Zi(); 4 f.show(); 5 } 6 } 7 8 cla
vue2.0中的:is和is的區別
此文首發於 lijing0906.github.io/ 最近,工作之餘在翻閱vue.js的官方文件,在檢視到動態元件和解析 DOM 模板時的注意事項的時候,講到一個特殊的is特性,覺得很有意思,就來寫一篇自己理解的總結。 現場 寫栗子實踐 其實看過之後,其實是有點懵的,
VC 6 0中新增庫檔案和標頭檔案
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
微信小程式從子頁面返回父頁面實現資料的區域性重新整理
問題描述 A頁面有一個儲存欄位的物件陣列items,從A頁面跳轉到B頁面,B頁面自定義欄位,並新增到items中。當返回A頁面時,顯示items的部分能夠區域性重新整理 items:[{name: '0', value: '姓名', checked: true, isNecessar
在OpenCV中實現決策樹和隨機森林
目錄 1.決策樹 2.隨機森林 1.決策樹 需要注意的點: Ptr<TrainData> data_set = TrainData::loadFromCSV("mushroom.data",//檔名
**TP5.0中如何使用extend和vendor的第三方類庫
舉例說明: (一) 1、首先在extend目錄下新建資料夾my,然後新建Test.php,程式碼如下 <?php namespace my; class Test { public function hello() { echo 'hello,world'; } }
父元件中呼叫子元件,父元件資料更新傳到子元件後,子元件頁面未更新的問題
問題描述:父元件呼叫了一個子元件,傳遞了一個id的屬性到子元件,但是在子元件中將這個id的props屬性賦值給了data裡面定義的另外一個屬性myId,並且寫了watch監聽這個id的props。 結果:第一次的時候子元件並沒有更新介面(即data裡面的myId屬性沒有更新);第二次及以後就
【微信】運用fragment和viewpage實現主頁面和副頁面切換效果
這個專案是我自己學習時寫出來的,所以難免有些瑕疵或者種種不足,歡迎各位大佬挑刺,也歡迎其他菜鳥們一起學習。 先放張程式結構圖,大致結構還是比較清晰的 首先可以建好xml佈局檔案,一個主佈局(存放四個切換圖示),四個分佈局fragment 程式碼貼上: `
子頁面呼叫父頁面中的dom元素並回傳資訊
當我們在多個頁面間做互動時免不了要進行頁面間的傳值問題,比如說下面就是這個的一個簡單的例子. 在這裡我們採用的是HTML DOM中的Browser 物件,該物件為我們提供了DOM Window物件,通過該物件下的open()方法,我們可以開
在Tomcat7.0中設定預設伺服器和不加埠名訪問
最近申請了一個域名,想嘗試一下關聯自己的伺服器,首先要做的就是在阿里雲上申請一個域名,此操作不寫,跟著網站提示就可以搞定。 準備條件,新建web專案,部署到tomcat7.0伺服器上,所用工具為Eclipse。 第一步:設定WEB專案的歡迎頁 在WEB-INF資料夾下有個w
RxJava2.0中flatMap操作符用法和原始碼分析(五)
flatMap基本使用 flatMap是變換操作符,使用一個指定的函式對原始Observable發射的每一項資料執行變換操作,這個函式返回一個本身也發射資料的Observable,然後flatMap合併這些Observable發射的資料,最後將合併後的結果當作