Sys.UI.Data.DataNavigator与Sys.UI.Data.SortBehavior

简介:
  这次我想讨论与分析的内容是 Sys.UI.Data.DataNavigator与Sys.UI.Data.SortBehavior。在这之前,可能感兴趣的朋友们需要先了解一下 Atlas Client Script中Data Control的使用方法。可以先学习一些别的文章,例如官方说明《 Start > Quickstart Developer Tasks > Performing Data Access》,而Dflying兄的 Atlas介绍系列也实属精品。

Sys.UI.Data.DataNavigator和Sys.UI.Data.SortBehavior的作用都是配合DataView进行数据操 作:一个操作分页功能,一个操作排序功能。事实上这两个类都是属于辅助类,它们的功能是更加方便了开发,而提供的额外功能却不多。

Sys.UI.Data.SortBehavior使用了DataView的自带的属性与方法为DataView的内容进行了排序。当一个 SortBehavior被应用到了一个控件时,它会根据控件的点击来决定DataView的排序顺序(在ASC和SESC之间切换),并且根据当前的排 序顺序为control应用不同的样式(sortAscendingCssClass或sortDescendingCssClass)。如果没有这个控 件,我们可能就需要配合使用setProperty,invokeMethod进行较为复杂的应用了。换个角度说,如果某个功能比较复杂并且需要复用的 话,我们可以像SortBehavior一样封装起一系列操作。

Atlas中的控件设计并不随意,而是实实在在地“有用”。

但是,与Sys.UI.Data.SortBehavior相比,Sys.UI.Data.DataNavigator就有些古怪了。

Sys.UI.Data.DataNavigator提供了DataView的分页功能,不过无论是上一页也好,最后一页也罢,它的实现其实只是简单的 使用了DataView的一个函数:set_pageIndex。配合get_pageIndex获得当前的页数,实现这些功能自不必说。不过非常有趣 (或者继续使用上面的说法:古怪)的是触发DataNavigator那些功能的方式。DataNavigator没有提供任何的方法来触发它的那些操 作,它的那些操作都是定义在DataNavigator的onBubbleEvent方法中。它的onBubbleEvent里判断了 Sys.UI.Button对象传给它的Sys.UI.CommandEventArgs对象中commandName属性的值,然后进行不同的操作。

onBubbleEvent是我觉得在Atlas中比较奇特的玩意儿之一。它是定义在Sys.UI.Control类中的虚函数,直接或间接继承 Sys.UI.Control的类可以对它进行重载。不过在代码中并不会调用onBubbleEvent,如果需要bubble event,那么就需要调用定义在Sys.UI.Control类中的raiseBubbleEvent方法。熟悉ASP.NET Server Control开发的朋友们应该可以发现这和ASP.NET中System.Web.UI.Control的OnBubbleEvent和 RaiseBubbleEvent非常的类似,只可惜在Javascript中无法定义protected方法,只得把它们暴露在外了。

可以看出Atlas有多么深厚的ASP.NET背景。与ASP.NET一样,Atlas中的raiseBubbleEvent方法也不是个虚函数,它的定义无法改变,我们来看一下它的代码:
this .raiseBubbleEvent  =   function (source, args) {
    
var  currentTarget  =   this .get_parent();
    
while  (currentTarget) {
        
if  (currentTarget.onBubbleEvent(source, args)) {
            
return ;
        }
        currentTarget 
=  currentTarget.get_parent();
    }
}
  从当前控件开始,调用onBubbleEvent方法,如果返回false,则继续向parent传递,这样event就被bubble了。这是很标准的raiseBubbleEvent功能实现。

但是事情没有这么简单。在raiseBubbleEvent中可以看出,代码是通过parent属性获得上一级控件的引用。parent也是个无法重载 的非虚成员,它定义在Sys.UI.Control中。不知道为什么,在官方的Client Library中缺少这个属性。我们来看一下它的实现。
this .get_parent  =   function () {
    
if  (_parent) {
        
return  _parent;
    }
    
else  {
        
var  parentElement  =   this .element.parentNode;
        
while  (parentElement) {
            
if  (parentElement.control) {
                
return  parentElement.control;
            }
            parentElement 
=  parentElement.parentNode;
        }
        
return   null ;
    }
}
  可以看出这个属性的逻辑,如果曾经定义了 parent,那么就返回parent引用,如果没有的话,那么就沿着DOM向父级元素找,找到第一个具有Atlas控件对象的元素。因此可以发现, parent并不需要被强制定义。为了证实这一点,在这里我借用一下Dflying兄在其文章《 使用ASP.NET Atlas PageNavigator控件实现客户端分页导航》中编写的例子,我将对其进行简单的修改。

在Dflying兄的例子里有如下的定义:
<!--  PageNavigator  -->
< div  id ="pageNavigator" >
    
< input  type ="button"  id ="btnFirstPage"  value ="&lt;&lt;"   />
    
< input  type ="button"  id ="btnPrevPage"  value ="&lt;"   />
    
< span  id ="lblPageNumber" ></ span >  /  < span  id ="lblPageCount" ></ span >
    
< input  type ="button"  id ="btnNextPage"  value ="&gt;"   />
    
< input  type ="button"  id ="btnLastPage"  value ="&gt;&gt;"   />
</ div >

< script  type ="text/xml-script" >
    
< page xmlns:script = " [url]http://schemas.microsoft.com/xml-script/2005[/url] " >
        
< components >
            ...
            
< dataNavigator id = " pageNavigator "  dataView = " view "   />
            
< button id = " btnFirstPage "  parent = " pageNavigator "  command = " FirstPage "   />
            
< button id = " btnPrevPage "  parent = " pageNavigator "  command = " PreviousPage " >
                ...
            
</ button >
            
< button id = " btnNextPage "  parent = " pageNavigator "  command = " NextPage " >
                ...
            
</ button >
            
< button id = " btnLastPage "  parent = " pageNavigator "  command = " LastPage "   />
            ...
        
</ components >
    
</ page >
</ script >
  在这里,dataNavigator是那些 <input type="button" />的父结点,而在Atlas Xml Scripts中也为每个button指定了自身的parent属性。我们先尝试着去除上方HTML定义的元素父子关系,保留下方Script不变:
< div  id ="pageNavigator" ></div>
    
< input  type ="button"  id ="btnFirstPage"  value ="&lt;&lt;"   />
    
< input  type ="button"  id ="btnPrevPage"  value ="&lt;"   />
    
< span  id ="lblPageNumber" ></ span >  /  < span  id ="lblPageCount" ></ span >
    
< input  type ="button"  id ="btnNextPage"  value ="&gt;"   />
    
< input  type ="button"  id ="btnLastPage"  value ="&gt;&gt;"   />
</ div >
  运行,一切正常。可以发现作为dataNavigator的元素无需为那些button的父结点。

接着,我们保留HTML元素的父子关系,在下方撤销在Atlas Scripts中的parent定义,如下:
< script  type ="text/xml-script" >
    
< page xmlns:script = " [url]http://schemas.microsoft.com/xml-script/2005[/url] " >
        
< components >
            ...
            
< dataNavigator id = " pageNavigator "  dataView = " view "   />
            
< button id = " btnFirstPage "  parent = " pageNavigator "  command = " FirstPage "   />
            
< button id = " btnPrevPage "  parent = " pageNavigator "  command = " PreviousPage " >
                ...
            
</ button >
            
< button id = " btnNextPage "  parent = " pageNavigator "  command = " NextPage " >
                ...
            
</ button >
            
< button id = " btnLastPage "  parent = " pageNavigator "  command = " LastPage "   />
            ...
        
</ components >
    
</ page >
</ script >
  运行,依旧一切正常。可见,Atlas会自动在DOM树中寻找作为dataNavigator的control。感兴趣的朋友也可以尝试着将上述两者都去除,这样分页功能就会失效了。

不过,我的疑惑也就出现了……既然这样,为什么DataNavigator要设计成为一个控件?很明显,它只是提供了一个分页功能,而不具备任何显示作 用!我们可以在任意一个地方定义任意一个元素作为所谓的“DataNavigator”,还是能够实现分页。从这一点上说,我们完全可以定义个类似于 DataNavBehavior的东西来实现相同的效果。还有,为什么要使用bubble event的方式来作为实现DataNavigator的功能呢?纵观所有的Atlas控件,只有button一个类调用了 raiseBubbleEvent方法,而在PageNavigator中直接把args参数作为CommandEventArgs对象来处理,这表明它 已经作为一个特定实现而出现了。

有时候我想,DataNavigator的这个设计,莫非只是为了“演示”一下 raiseBubbleEvent和onBubbleEvent的方式?事实上,DataNavigator只是集中了分页的功能,通过一个独立的对象来 管理了操作,照这样说,我们可以为它提供相关方法或属性,然后依靠Button来invokeMethod或者setProperty。另外,熟悉 ASP.NET Server Control开发的朋友们可以知道,在ASP.NET中RaiseBubbleEvent和OnBubbleEvent的作用是为了配合 PostBack模型,在复合控件中将子控件的事件向父控件传递的一种方式。而在Client端,根本不需要这样的做法,所有的控件都是顶级元素,都能被 直接访问并且注册事件,这样raiseBubbleEvent和onBubbleEvent方法似乎也就没有什么必要性了。

目前DataNavigator的设计,似乎只有在资源消耗上小一些。

不过现在,在Client端存在raiseBubbleEvent和onBubbleEvent的必要性,它们能否带来开发概念和方式上的改变,以及如何正确地使用它们,这些事情还在我脑子里激烈地进行着斗争,可能我以后会单独写一篇文章来仔细讨论这点。

似乎这片文章已经完成使命了,不过,事实上,在这里我还想提一下DataNavigator的一个bug。DataNavigator的部分代码如下:
 1  Sys.UI.Data.DataNavigator  =   function (associatedElement) {
 2      Sys.UI.Data.DataNavigator.initializeBase( this , [associatedElement]);
 3      
 4      ...
 5 
 6       this .getDescriptor  =   function () {
 7           var  td  =  Sys.UI.Data.DataControl.callBaseMethod( this , 'getDescriptor');
 8          
 9          td.addProperty('dataView', Object);
10          
11           return  td;
12      }
13      Sys.UI.Data.DataNavigator.registerBaseMethod( this , 'getDescriptor');
14 
15       this .onBubbleEvent  =   function (source, args) {
16          ...
17      }
18      Sys.UI.Control.registerBaseMethod( this , 'onBubbleEvent');
19  }
20  Sys.UI.Data.DataNavigator.registerClass('Sys.UI.Data.DataNavigator', Sys.UI.Control);

  看看第5行和第18行的代码,是不是觉得很奇怪?还好,由于DataNavigator是继承了Sys.UI.Control类,因此在运行效果上没有什么问题。幸甚!


本文转自 jeffz 51CTO博客,原文链接:http://blog.51cto.com/jeffz/60948,如需转载请自行联系原作者

相关实践学习
基于Hologres轻量实时的高性能OLAP分析
本教程基于GitHub Archive公开数据集,通过DataWorks将GitHub中的项⽬、行为等20多种事件类型数据实时采集至Hologres进行分析,同时使用DataV内置模板,快速搭建实时可视化数据大屏,从开发者、项⽬、编程语⾔等多个维度了解GitHub实时数据变化情况。
阿里云实时数仓实战 - 用户行为数仓搭建
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求:熟练掌握 SQL 语法熟悉 Linux 命令,对 Hadoop 大数据体系有一定的了解 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
小程序 开发工具 Android开发
uni-app使用HBuilder X编辑器本地打包apk步骤说明
uni-app使用HBuilder X编辑器本地打包apk步骤说明
2807 0
|
存储 传感器 算法
如何选择合适的 CRC 多项式
CRC(循环冗余校验)多项式的选取对数据传输的错误检测至关重要。选择时需考虑多项式的长度、检测性能及实现复杂度,常用多项式有CRC-8、CRC-16、CRC-32等,适用于不同场景以确保高效准确的错误检测。
1269 4
|
存储 安全 Shell
Python 3.8.8 以及 openpyxl 3.0.7 的下载和安装!
Python 3.8.8 以及 openpyxl 3.0.7 的下载和安装!
2481 0
|
Java Maven
解决遇到的问题idea maven无法加载导入子模块的依赖包
遇到问题idea maven无法加载导入子模块的依赖包
1454 0
解决遇到的问题idea maven无法加载导入子模块的依赖包
|
1天前
|
数据采集 人工智能 安全
|
11天前
|
云安全 监控 安全
|
2天前
|
自然语言处理 API
万相 Wan2.6 全新升级发布!人人都能当导演的时代来了
通义万相2.6全新升级,支持文生图、图生视频、文生视频,打造电影级创作体验。智能分镜、角色扮演、音画同步,让创意一键成片,大众也能轻松制作高质量短视频。
950 150
|
2天前
|
编解码 人工智能 机器人
通义万相2.6,模型使用指南
智能分镜 | 多镜头叙事 | 支持15秒视频生成 | 高品质声音生成 | 多人稳定对话