FineUI 官方论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

本论坛已关闭(禁止注册、发帖和回复)
请移步 三石和他的朋友们

FineUI首页 WebForms - MVC & Core - JavaScript 常见问题 - QQ群 - 十周年征文活动

FineUI(开源版) 下载源代码 - 下载空项目 - 获取ExtJS - 文档 在线示例 - 版本更新 - 捐赠作者 - 教程

升级到 ASP.NET Core 3.1,快、快、快! 全新ASP.NET Core,比WebForms还简单! 欢迎加入【三石和他的朋友们】(基础版下载)

搜索
查看: 2049|回复: 2

FineUI IFrame页面间交互 - 学生CRUD示例

[复制链接]
发表于 2020-2-13 17:01:25 | 显示全部楼层 |阅读模式
本帖最后由 棕榈 于 2020-2-13 16:54 编辑

FineUI IFrame页面间交互 - 学生CRUD示例





上面的示例是一个学生CRUD示例,也是在项目中经常会出现的场景。在这里我们并不会去讨论CRUD的实现,而是探讨在这个过程中IFrame间页面的通讯。


我先说一下这个示例的构成,它一共有4个页面,StudentCrud是主页,它包含School(学校Tree)及StudentList(学生列表)这两个页面,在StudentList页面中又包含一个F.Window控件,它用于显示Student页面。它的操作也比较简单,当School页面中学校被选择时,StudentList页面会加载相应学校的学生,这里并不是重新加载StudentList页面,而是通过Ajax加载学生数据,StudentList页面中的按钮也就是CRUD相应的操作。


首先,我要先说一下如果采用常规的方式,它之间的交互是怎样的。School页面与StudentList页面都是在StudentCrud页面中,它们俩之间的交互需要通过StudentCrud页面来完成,也就是说StudentCrud页面中要含有操作StudentList页面代码,School页面再去调用StudentCrud页面中的代码。关于School页面,由于它是被F.Window控件显示出来,它需要在后台或前台去操作ActiveWindow,在添加或编辑学生时需要重新加载学生,隐藏ActiveWindow时,还需要拼接一个调用SchoolList页面加载学生方法。这里只是一个简单的嵌套,如果因业务需求,需要更加复杂的嵌套,那上面的操作会更加的复杂,同时相互交结在一起的代码也会增加,维护难度及Bug查找也会更加困难。


下面我说一个当前示例采用的方法,这也是一个全新的IFrame页面间的交互方式,当然当前示例只是一个演示,示例中的代码可能还需要进一步的优化及封装(这里指的是IFrame页面间的交互代码,业务代码只是演示)。


在这之前,请大家看一下之前的关于IFrame页面间通讯的帖子(https://fineui.com/bbs/forum.php?mod=viewthread&tid=22357&extra=)。


先看一下下面的这行代码:


  1. F.eventBus = top.F.eventBus ? top.F.eventBus : $('<fineui-event-bus>');
复制代码



这行代码需要放到每一个页面中,它的意思是每个页面中的F.eventBus都是引用最顶层F.eventBus对象,而F.eventBus其实就是一个JQuery对象,这样我们就可以借用JQuery中事件的操作,来完成消息的订阅及发布。


下面代码是一个订阅


  1. F.eventBus.on('refresh', function(e,data){});
复制代码



这样我无论在哪个页面进行发布消息,这个订阅都会收到消息。


  1. F.eventBus.trigger('refresh');
复制代码



这样也就实现了页面间通讯的基础,是不是很简单。当然我们这里借用的是JQuery事件机制,你也可以采用其它的EventBus。

到这里并没有结束,这样虽然实现了页面间的通讯,但大家有没有发现,所有发布及订阅都是全局,当你页面很多时,又没有很好的组织,那将是很混乱的。

我这里就说一下对F.Window控件的封装,由于F.Window展示方式与WinForm中的对话框基本一致,而对话框基本上都有确认(ok)及取消(cancel)按钮,我以这个为基础来对F.Window进行封装。

首先看一下代码:

  1. var query = document.location.search
  2.         .replace(/(^\?)/, '')
  3.         .split('&')
  4.         .map(
  5.                 function (p) {
  6.                         return p = p.split('='), this[p[0]] = p[1], this;
  7.                 }.bind({})
  8.         )[0];

  9. if (query._page_id_) {
  10.         $(document).data('page-id', query._page_id_);
  11. }

  12. F.Window.prototype.getPageId = function () {
  13.         if (this.options) {
  14.                 if (this.options.attrs) {
  15.                         return this.attrs['data-page-id'];
  16.                 }
  17.         }
  18.         return null;
  19. }

  20. var showWindow = F.Window.prototype.show;
  21. F.Window.prototype.show = function () {
  22.         var url = arguments[0];
  23.         if (typeof url === 'string') {
  24.                 var pageId = this.getPageId();
  25.                 if (pageId) {
  26.                         url += (url.indexOf('?') >= 0 ? '&' : '?') + '_page_id_=' + pageId;
  27.                         arguments[0] = url;
  28.                 }
  29.         }
  30.         showWindow.apply(this, arguments);
  31. }

  32. $('.f-window[data-page-id]').each(function (index, ele) {
  33.         var win = F.ui[$(ele).attr('id')];
  34.         if (win) {
  35.                 var pageId = win.getPageId();
  36.                 if (pageId) {
  37.                         F.eventBus.on('ok', function (e, data) {
  38.                                 if (win.ok && data && data.PageId === pageId) {
  39.                                         win.ok(data);
  40.                                 }
  41.                         });
  42.                         F.eventBus.on('cancel', function (e, data) {
  43.                                 if (win.cancel && data && data.PageId === pageId) {
  44.                                         win.cancel(data);
  45.                                 }
  46.                         });
  47.                 }
  48.         }
  49. });

  50. $.ajaxPrefilter(function (options) {
  51.         var pageId = $(document).data('page-id');
  52.         if (pageId) {
  53.                 options.data = options.data ? options.data + '&' : '';
  54.                 options.data += '_page_id_=' + pageId;
  55.         }
  56. });
复制代码

这段代码也是要出现在每一个页面中,这里说一个代码所做的操作,在这个之前需要在F.Window控件中添加一个Attribute,代码


  1. <f:Window ID="winStudent" Title="学生" Hidden="true" EnableIFrame="true" Target="Top" IsModal="true" Width="500" Height="400">
  2.         <Attributes>
  3.                 <f:Attribute Key="data-page-id" Value="@Guid.NewGuid()"></f:Attribute>
  4.         </Attributes>
  5. </f:Window>
复制代码

这里的pageId是用于标识每一个页面的,用于在服务器端触发客户端事件时识别是哪一个F.Window。
在上面的代码中,对pageId进行了封装,在使用时感知不到它的存在。


下面是添加学生按钮的操作代码:

View:

  1. <f:Button Text="添加" OnClientClick="addStudent()"></f:Button>
复制代码

Script:

  1. function addStudent() {
  2.         F.ui.winStudent.show("@Url.Content("~/Student")?schoolId=" + schoolId);
  3. }

  4. F.ui.winStudent.ok = function () {
  5.         this.close();
  6.         loadStudents();
  7. }
复制代码


F.ui.winStudent.ok 是在单击确定按钮需要执行的操作,取消按钮的操作代码如下:


  1. F.ui.winStudent.cancel = function () {
  2.         this.close();
  3. }
复制代码

就这几行代码,就完成了,显示、确定、取消的操作,甚至也可以添加其它的操作,与WinForm中的操作基本保持一致,当然WinForm是同步的,这里是异步的。

这里只是客户端的封装,服务器端也需要做一些代码的包装,我就不在一一举例了,代码也很简单,一看就明白,大家可以通过示例代码来查看。

示例代码请到知识星球下载。





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
发表于 2020-2-14 12:35:11 | 显示全部楼层
赞,感谢无私奉献!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|FineUI 官方论坛 ( 皖ICP备2021006167号-1 )

GMT+8, 2024-3-28 19:05 , Processed in 0.059967 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表