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

浅谈如何将项目中的 Dojo 从 1.6 升级至 1.8(3)升级要点分享

浅谈如何将项目中的 Dojo 从 1.6 升级至 1.8(3)升级要点分享

升级要点分享 – 从 Dojo 1.6 升级至 Dojo 1.8虽然不同版本的 Dojo 在升级时需要改动的地方千变万化,但终归存在一些共性问题,在大部分项目的 Dojo 升级中都会出现。这里将向您分享在笔者的项目中,从 Dojo 1.6 升级至 Dojo 1.8(兼容性升级)过程中遇到的典型问题与升级要点。
正确解决升级后打开页面显示空白的问题一般情况下,当项目升级至 Dojo 1.8 以后,原先采用 Dojo 1.6 页面布局类设计的页面便可能出现打开时显示空白的情况。这是因为 Dojo 1.8 下的这些布局类最适于在 AMD 模式下被加载与使用,而当 Dojo 1.8 工作在兼容模式时,这些布局类在初始化时就容易出现问题。按照笔者的项目升级经验来讲,这种页面显示空白的问题出现概率不算低,约占项目全部页面的 7%。
解决这种问题的方法可以是针对空白页面的初始化方法,一层一层地向下跟踪调试,找出发生问题的根源,然后进行修复。但这种修复方法过于复杂,而且开发人员要熟悉 Dojo 底层源码。并且有可能不同页面显示空白的原因也不同,逐一调试并修复的工作量很大。
有一种更快捷直接的方法,便是在页面初始化完成之后,在该页面所对应的布局性 widget 的 postCreate 方法里面,调用相应布局类(_LayoutWidget 的子类)的 resize 方法, 对页面中的 widget 布局进行重新调整。清单 1 给出了_LayoutWidget 这个最底层的布局类的 resize 方法。
清单 1. _LayoutWidget 类的 resize 方法
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
resize: function(changeSize, resultSize){
    var node = this.domNode;
    // 设置边界值,除非它没有被指定
    if(changeSize){
        domGeometry.setMarginBox(node, changeSize);
    }
    // 如果高度和宽度没有被指定,则需要查询出这个节点
    // 但请注意在设置边界值后立即查询它会返回不准确的结果,所以尽量不要这样做
    var mb = resultSize || {};
    lang.mixin(mb, changeSize || {}); // changeSize 覆盖掉 resultSize
    if( !("h" in mb) || !("w" in mb) ){
        mb = lang.mixin(domGeometry.getMarginBox(node), mb);
    }
    var cs = domStyle.getComputedStyle(node);
    var me = domGeometry.getMarginExtents(node, cs);
    var be = domGeometry.getBorderExtents(node, cs);
    var bb = (this._borderBox = {
        w: mb.w - (me.w + be.w),
        h: mb.h - (me.h + be.h)
    });
    var pe = domGeometry.getPadExtents(node, cs);
    this._contentBox = {
        l: domStyle.toPixelValue(node, cs.paddingLeft),
        t: domStyle.toPixelValue(node, cs.paddingTop),
        w: bb.w - pe.w,
        h: bb.h - pe.h
    };
     
    //用于调整它的子控件的大小。
    this.layout();
},




从该方法的内容可以看出,它实际上是递归地对自身以及其所包含的子控件重新进行像素计算与渲染,该过程完成之后这些子控件便会重新显示出来。
这种修改方式利用的原理是无论 Dojo loader 对该页面的初始化与渲染是否正确,都让该页面在初始化完成后,通过自身的重新渲染来进行显示,从而避免由于 Dojo loader 对该页面渲染出错而使页面显示空白的问题。
对 Widget 的调用需要遵循新版本 Dojo 的 APIDojo 1.6 升级至 Dojo 1.8 之后,部分 widget 的 API 也相应发生了变化。因此原先项目代码中对这些 widget 的调用可能会抛出错误,需要将其修正为 Dojo 1.8 API 中正确的用法。
例如,在笔者的项目中,升级完成后,发现页面中的文件上传控件无法使用,经调试发现,这个上传控件的源码(Dojox.form.uploader)在 Dojo 1.8 里发生了一些变化。清单 2 给出的是 Uploader 这个控件在 Dojo 1.6 中的定义。
清单 2. Uploader.js 在 Dojo 1.6 中的部分定义
1
2
3
4
5
6
7
8
9
10
11
12
13
uploadType:"form",
//
_nameIndex:0,
widgetsInTemplate:true,

//模板字符串,定义了一个 Button.
templateString:'<div class="DojoxFileInput">
     <div DojoType="dijit.form.Button" DojoAttachPoint="button">...',
postMixInProperties: function(){
    this._inputs = [];
    this._getButtonStyle(this.srcNodeRef);
    this.inherited(arguments);
},




从清单 2 中可以看到,Uploader 在 Dojo 1.6 里定义了一个 Button 作为自己的子 widget 对象, 因此我们可以像清单 3 中那样去使用 Uploader。
清单 3. Uploader 在 Dojo 1.6 下的用法
1
2
3
4
this.bBrowse.button.set('iconClass',"lookupIcon");
this.bBrowse.button.set('label',"Add Attachments");
this.bBrowse.button.domNode.parentNode.style.width = "150px";
this.bBrowse.button.domNode.style.width = "150px";




清单 3 中的 this.bBrowse 是对 Uploader 的引用,因为 Uploader 中将 Button 定义为自己的一个子 widget    对象,因此可以直接引用这个 button。
然而在 Dojo 1.8 中,Uploader 这个控件在定义时,它的 template 由之前的 templateString 所定义的字符串,变为了一个模板文件。在这个模板文件中,button 不再作为自己的子 widget 对象出现,而是被 Uploader 当作父类进行了继承。如清单 4 中所示。
清单 4. Uploader 在 Dojo 1.8 下的定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
define([
    "Dojo/_base/kernel",
    "Dojo/_base/declare",
    ...
"dijit/form/Button",
    "Dojox/form/uploader/Base",
    "Dojo/i18n!./nls/Uploader",
    "Dojo/text!./resources/Uploader.html"
],function(kernel, declare, ... Button, uploader, res, template){

    kernel.experimental("Dojox.form.Uploader");

//此处 Button 作为 Uploader 的父类直接被继承
declare("Dojox.form.Uploader", [uploader, Button], {
...}
});




因此之前 Dojo 1.6 中对 Uploader 的用法需要做出调整,如清单 5 所示。
清单 5. Uploader 控件在 Dojo 1.8 下的用法改进
1
2
3
4
this.bBrowse.set('iconClass',"lookupIcon");
this.bBrowse.set('label',"Add Attachments");
this.bBrowse.domNode.parentNode.style.width = "150px";
this.bBrowse.domNode.style.width = "150px";




以上代码将 this.bBrowse.button 替换为 this.bBrowse,即把之前对 button 对象的调用,变为了对自身的调用(实际上是对自己的父类 Button.js 的调用)。
升级对 Dojo 的 Build 脚本的影响一般而言,项目中如果使用 Dojo,则在发布产品时会将 Dojo 进行 build 处理,使其在压缩之后而容易被加载。但在从 Dojo 1.6 升级至 Dojo 1.8 之后,原先 Dojo 1.6 下的 build 脚本需要做出一些变化。
首先可确定的是 Dojo 1.6 的 Build 脚本是可以被 Dojo 1.8 的 build 引擎支持的,不必完全重写。脚本需要做出的变化事实上已经在 Dojo1.7 版本的 Release Note 里声明了,即:acme 选择引擎不再会被自动 build 到 Dojo.js 中,而需要显式地在 build 脚本中进行声明,否则 build 结束后,Dojo/selector/acme.js 这个文件就不会被打到包中,进而导致产品运行时的错误。
因此,完成 Dojo 1.6 至 Dojo 1.8 的升级之后,我们应至少在 build 脚本中将入 selectorEngine=acme ,才能保证 build 的正确性。
返回列表