首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

浅谈如何将项目中的 Dojo 从 1.6 升级至 1.8(4)升级过程中的建议与准则

浅谈如何将项目中的 Dojo 从 1.6 升级至 1.8(4)升级过程中的建议与准则

升级过程中的建议与准则按照笔者的升级经验,有以下几点建议供您参考:
详细阅读与升级相关的 Dojo 版本的 Release note因为里面会有最权威的版本变化与升级注意事项。但需要注意的是,这些注意事项只会出现在当前版本的下一个版本的声明中。例如上文谈到的 acme 问题,它只出现在 Dojo1.7 的 Release note 里,在 Dojo 1.8 里是找不到相关声明的。图 2 摘自 Dojo1.7 的 Release note,主要描述了关于 selectorEngine 相关的改变。图 3 则摘自 Dojo 1.8 的 Release note, 描述了在做 Dojo 的升级操作时,有哪些地方需要特别注意。
图 2.Dojo1.7 中对 selectorEngine 所做的调整
图 3. Dojo 1.8 的 Release    note 中关于 Dojo 迁移与升级的注意事项充分利用互联网搜索服务项目的 Dojo 升级是一个普遍问题,因此可能自己遇到的升级问题别人也曾遇到过并且已有解决方案。所以应善于搜索别人已造好的“车轮”,减少不必要的时间成本。
Stack Overflow 是国外的一个面向程序员的专业 QA 站点,在这里可以找到各种与编程相关的问题以及高质量的答案。您可在解决问题之前先在该网站上进行查找相应问题的答案,该网站免费且不用注册,使用很方便。
图 4. Stack Overflow 网站避免修改 Dojo 源码升级过程会遇到一些复杂问题,在解决这些问题时,尽量不要在 Dojo 源码这一层上进行改动。因为如果修改的代码被放在 Dojo 源码里,那么下次升级时这些修改的代码就会随着 Dojo 源码的替换而被移除。如果为解决问题不得不对 Dojo 源码进行修改,则可在业务代码中使用 Dojo.extend 来对源码中的方法进行修改。
此处以修改 dijit.Dialog 类的样式为例进行说明。假如当前项目需要对 dijt.Diaog 这个通用的对话框类的样式进行改变,为了遵循不修改 Dojo 源码的原则,我们可以有两种做法。第一种是创建子类继承 dijit.Dialog,再对子类进行修改。该做法在 Dojo 控件层之上引入自定义组件层,可能会破坏项目架构。第二种做法便是使用 Dojo.extend 来对 dijit.Dialog 进行修改,将 dijit.Dialog 的 template 换为项目自己定义的即可。如清单 6 所示。
清单 6. 使用 Dojo.extend 间接修改 Dialog 类
1
2
3
4
dojo.extend(dijit.Dialog, {
            templateString: dojo.cache("dojoCustom",
"templates/Dialog.html")
        });




Dojo.extend 与 Java 反射类似,都是在运行时对类的结构进行了修改。之后由此类生成的对象,都会受到之前对类所做修改的影响。因此,Dialog 在被修改 template 后,由其所产生的所有 Dialog 对象,都会使用新的 template 进行展现,从而显示出新的样式。
避免使用 Dojo 源代码中的私有属性和方法众所周知,JavaScript 的属性和方法不像 Java 等语言那样具有访问权限。因此理论上我们可以随意访问一个对象的方法和属性。但由于目前 Dojo 的版本变化较快,其私有属性和方法也时常变化,这里的“私有”指的是变量前面加下划线标识的。项目代码中一旦使用了这些私有属性和方法,则在下一次项目 Dojo 升级后,则很可能出现问题。例如,新版本的 Dojo 直接删除了某个私有方法,而这个私有方法恰好被项目所使用。正确的做法应是直接使用 Dojo 源码中的公有方法和属性(不带下划线标识),因为 Dojo 的公开方法和属性相对稳定,可以避免因 Dojo 升级所引起的问题。
还是以 dijit.Dialog 为例进行说明。Dialog 有一个私有方法_size(),用于调整 dialog 里面的内容而使 Dialog 展现得更完整美观。这个方法在 Dojo 1.6 与 Dojo 1.8 中的定义并不相同。如清单 7、8 所示。我们在对 dialog 进行调整时,不能直接使用这个私有方法,而应该使用 resize()或 show()这些公开方法。公开方法的内部会调用这个私有方法,并在这个私有方法发生改变时,也做适当调整,使该公开方法自身的作用保持不变。
清单 7. Dojo 1.8 中_size()方法的定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
_size: function(){
this._checkIfSingleChild();
if(this._singleChild){
if(typeof this._singleChildOriginalStyle != "undefined"){
this._singleChild.domNode.style.cssText = this._singleChildOriginalStyle;
delete this._singleChildOriginalStyle;
                }
}else{
domStyle.set(this.containerNode, {
                 width:"auto",
                 height:"auto"
                });
            }

var bb = domGeometry.position(this.domNode);
var viewport = winUtils.getBox(this.ownerDocument);
viewport.w *= this.maxRatio;
viewport.h *= this.maxRatio;
if(bb.w >= viewport.w || bb.h >= viewport.h){
       var containerSize = domGeometry.position(this.containerNode),
        w = Math.min(bb.w, viewport.w) - (bb.w - containerSize.w),
        h = Math.min(bb.h, viewport.h) - (bb.h - containerSize.h);

     if(this._singleChild && this._singleChild.resize){
    if(typeof this._singleChildOriginalStyle == "undefined"){
this._singleChildOriginalStyle
                       = this._singleChild.domNode.style.cssText;
                 }
this._singleChild.resize({w: w, h: h});
}else{
domStyle.set(this.containerNode, {
                    width: w + "px",
                    height: h + "px",
                    overflow: "auto",
                    position: "relative"   
                 });
                }
}else{
if(this._singleChild && this._singleChild.resize){
this._singleChild.resize();
                }
            }
        },




清单 8. Dojo 1.6 中_size()方法的定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
_size: function(){
this._checkIfSingleChild();
if(this._singleChild){
if(this._singleChildOriginalStyle){
this._singleChild.domNode.style.cssText =  
                        this._singleChildOriginalStyle;
                }
delete this._singleChildOriginalStyle;
}else{
dojo.style(this.containerNode, {
                 width:"auto",
                 height:"auto"
                });
            }
var mb = dojo._getMarginSize(this.domNode);
var viewport = dojo.window.getBox();
if(mb.w >= viewport.w || mb.h >= viewport.h){
var w = Math.min(mb.w, Math.floor(viewport.w * 0.75)),
                 h = Math.min(mb.h, Math.floor(viewport.h * 0.75));
if(this._singleChild && this._singleChild.resize){
this._singleChildOriginalStyle
                       = this._singleChild.domNode.style.cssText;
this._singleChild.resize({w: w, h: h});
}else{
dojo.style(this.containerNode, {
                    width: w + "px",
                    height: h + "px",
                    overflow: "auto",
                    position: "relative"   
                 });
                }
}else{
if(this._singleChild && this._singleChild.resize){
this._singleChild.resize();
                }
            }
        },




准确定位当前问题是升级导致的还是残留问题解决这两类问题时,调试代码的侧重点是不同的。升级导致的问题更关注 Dojo 底层源码,而系统残留问题一般与业务代码相关。定位问题类型的方法有多种,其中一种比较直观的就是将升级后的系统与升级前的系统做对照。这种对照式调试方式应该贯穿于整个升级过程。
返回列表