1. 程式人生 > >AppBox v6.0中實現子頁面和父頁面的複雜互動

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最初的設計目標:儘量減少客戶端指令碼,降低程式碼複雜度。

private
void 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.padLeftString.padRight

toc 還要 color for 失去 1-1 arraycopy ace pre 因為習慣了C#中的padLeft和padRight,接觸Java後突然失去這兩個功能,覺得別扭,就試著實現了這兩個方法。 Java中String.format()中帶有字符串對齊功能如下

對象序列化 類構造函數的調用問題

images png http 分享 com 函數 對象 情況 序列 第三種情況: 對象序列化中 子類和父類構造函數的調用問題

ThinkPHP5.0Redis的使用封裝

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的:isis的區別

此文首發於 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如何使用extendvendor的第三方類庫

舉例說明: (一) 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屬性沒有更新);第二次及以後就

【微信】運用fragmentviewpage實現主頁面頁面切換效果

這個專案是我自己學習時寫出來的,所以難免有些瑕疵或者種種不足,歡迎各位大佬挑刺,也歡迎其他菜鳥們一起學習。 先放張程式結構圖,大致結構還是比較清晰的 首先可以建好xml佈局檔案,一個主佈局(存放四個切換圖示),四個分佈局fragment 程式碼貼上: `

頁面呼叫頁面的dom元素並回傳資訊

        當我們在多個頁面間做互動時免不了要進行頁面間的傳值問題,比如說下面就是這個的一個簡單的例子.         在這裡我們採用的是HTML DOM中的Browser 物件,該物件為我們提供了DOM Window物件,通過該物件下的open()方法,我們可以開

在Tomcat7.0設定預設伺服器不加埠名訪問

最近申請了一個域名,想嘗試一下關聯自己的伺服器,首先要做的就是在阿里雲上申請一個域名,此操作不寫,跟著網站提示就可以搞定。 準備條件,新建web專案,部署到tomcat7.0伺服器上,所用工具為Eclipse。 第一步:設定WEB專案的歡迎頁 在WEB-INF資料夾下有個w

RxJava2.0flatMap操作符用法原始碼分析(五)

flatMap基本使用 flatMap是變換操作符,使用一個指定的函式對原始Observable發射的每一項資料執行變換操作,這個函式返回一個本身也發射資料的Observable,然後flatMap合併這些Observable發射的資料,最後將合併後的結果當作