AppBox v6.0中实现子页面和父页面的复杂交互
前言
1. 你可以通过捐赠获取 AppBox 的完整源代码:http://fineui.com/donate/
2. AppBox v3.0于 2013-08 发布,采用了EF CodeFirst开发模式和扁平化的设计理念:http://www.cnblogs.com/sanshi/p/3274122.html
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中实现子页面和父页面的复杂交互的更多相关文章
- FineUI(开源版)v6.0中FState服务器端验证的实现原理
前言 1. FineUI(开源版)是完整开源,最早发起于 2008-04,下载全部源代码:http://fineui.codeplex.com/ 2. 你可以通过捐赠作者来支持FineUI(开源版)的 ...
- 子窗口访问父页面iframe中的iframe,top打开的子窗口访问父页面中的iframe中的iframe
子窗口访问父页面iframe中的iframe 子窗口访问最顶层页面中的iframe中的iframe top打开的子窗口访问父页面中的iframe中的iframe top打开的子窗口访问最顶层页面中的i ...
- js 在iframe子页面获取父页面元素,或在父页面 获取iframe子页面的元素的几种方式
用JS或jquery访问页面内的iframe,兼容IE/FF 注意:框架内的页面是不能跨域的! 假设有两个页面,在相同域下. index.html 文件内含有一个iframe: XML/HTML代码 ...
- iframe子页面获取父页面元素的方法
在iframe子页面获取父页面元素 代码如下: $.('#objld', parent.document); 在父页面获取iframe子页面的元素 代码如下: $("#objid" ...
- 在alert里面加入一个页面,子页面传值父页面
把easyDialog v2.0这个插件加入到了项目中,在做选择部门功能时运用这个插件,在easyDialog.open里面的content函数中套了一个iframe标签,把部门页面的地址放入到src ...
- 使用iframe父页面调用子页面和子页面调用父页面的元素与方法
在实际的项目开发中,iframe框架经常使用,主要用于引入其他的页面.下面主要介绍一下使用iframe引入其他页面后,父页面如何调用子页面的方法和元素以及子页面如何调用父页面的方法和元素. 1.父页面 ...
- 在子页面操作父页面元素和iframe说明
实现功能:在子页面操作父页面元素. 在实际编码的过程中,大家一定有这种需求:在父级页面有一个<iframe scrolling='auto'></iframe>内联框架,而我们 ...
- layui type:2 iframe子页面向父页面传值
需求: 选择子页面表格中的radio或者双击该行,得到的该行数据传到父页面,由父页面渲染. 网上的各种方法都用了,父页面就是获取不到子页面传的值,过了一晚上,睡了一觉,柳暗花明又一村. layui t ...
- jquery读取iframe子页面和父页面的处理
1. jquery 在iframe子页面获取父页面元素代码如下: $("#objid", parent.document) 2. jquery在父页面 获取iframe子页面的元素 ...
随机推荐
- 作为一个程序猿,是不是经常会用到.chm文档,但是我们可能会遇到这样那样的问题,比如.chm文档打不开
.chm文档不能正常打开,一般有两种情形下会造成文档打不开, 1.系统语言栏的语言和文档的语言类别不一同,也就是说比如你的文档是中文版的,但是系统设置的语言是其他国家的.不过一般这种情况很少出现 ,谁 ...
- ASP.NET Core 中文文档 第三章 原理(5)错误处理
原文:Error Handling 作者:Steve Smith 翻译:谢炀(Kiler) 校对:高嵩(jack2gs).何镇汐 当你的ASP.NET应用发生错误的时候, 你可以采用本文所述的各种方法 ...
- 针对每种Windows Server 操作Excel、Word等Office组件遇到“ComException"、”80070005“等COM错误的解决方案大汇总
以下所有Excel错误的解决方案,同样适用于Word.PowerPoint等Office产品. 以下解决方案中,如果出现"安装Excel组件",是适用于遇到Excel错误的.如果是 ...
- Python时间戳和日期的相互转换
Python时间戳和日期的相互转换 (2014-03-17 11:24:35) 转载▼ 分类: Python 当前时间戳:time.time() 当前日期:time.ctime() 1.Pytho ...
- Java迭代器
迭代器在其实就是指针,读取集合或者数组中的一个值,读完以后又指向下一条数据. iterator() 迭代器只读,不能改效率要比for循环高 迭代器的一些方法: HasNext() 如果仍有元素可以迭代 ...
- PHP学习笔记:输入一句话,实现单词倒序输出
约定:句子以空格为词语分割符号,以句号为结束符号. 实现思路: 用函数explode(separator,string,limit)对字符串进行分割,再对得到的数据最后一个成员分割切掉符号.用一个新的 ...
- [转载]C#委托和事件(Delegate、Event、EventHandler、EventArgs)
原文链接:http://blog.csdn.net/zwj7612356/article/details/8272520 14.1.委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托.委 ...
- 利用CSS背景颜色属性使父级div背景透明同时避免子级标签透明。
实现背景色透明效果的代码 实现各个浏览器中具备良好的透明特性的效果,IE中使用私有滤镜filter,高端浏览器使用CSS3中的rgba属性. 输入十六进制的颜色值以及透明度,自动在IE的过渡滤镜以及C ...
- 【web前端面试题整理08】说说最近几次面试(水)
为什么换工作 换工作简单来讲一般会归纳为钱不够或者人不对,我们团队氛围很不错,所以基本就定位到钱不够了,而我更多是考虑到以后的职业发展,简单说来就是对以后几年的工作有想法,而这种想法实现不一定能在现在 ...
- HTTP、HTTP2
HTTP.HTTP2.0.SPDY.HTTPS 你应该知道的一些事 原文链接:http://www.alloyteam.com/2016/07/httphttp2-0spdyhttps-readi ...