posts - 10, comments - 14, trackbacks - 0, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

2011年4月20日

同时使用JSON2.js和prototype,会导致json方法对于数组对象处理出现错误。

 

解决方案是:使用json2的json方法,但要增加附加函数来修正。

 

json_data = JSON.stringify(outAcctList_groupInfo, function(key, value) {
 if (typeof this[key] == 'object' && Object.prototype.toString.apply(this[key]) === '[object Array]') {
  return this[key];
 } else {
  return value;
 }
});

posted @ 2011-04-20 18:32 暴风雪 阅读(97) 评论(0) 编辑

2011年4月7日

JS面向对象应用二

----多差异流程的WEB客户端逻辑设计实现

一、问题的提出

        随着公司国际化脚步的加快,系统应用的大面积推广,出现了各个分支机构的业务需求差异的情况,尤其以汇款栏目最为明显。

       每一个海外分支机构因为其所处的当地监管、以及自身的考虑不同,而导致业务需求不同。界面上最大的不同,主要是因为所选清算系统、清算路径不同,而出现的界面输入要素的不同,包括客户端js联动的不同。

       具体来说主要有如下几种情况:

        1) 所有分支机构都需要调用的相同代码部分

        2)  分支机构之间逻辑实现不同

        3)  有些分支机构之间是相同的,而有些分支机构则需要重载

 

        这三条,完全可以套用面向对象的继承、重载、多态的概念。

        第一条就是说的继承,第二、三条就是说的重载与多态。用面向对象的方法来解决绝对是专杀!可是如何实现呢?这里面还是有一定技巧的,下面就是详细的设计情况。

二、设计与实现

    1. 唯有OO能解决

            由于工期原因,加上用JS实现OOP的种种不确定因素,我的第一个方案打算放弃OOP,使用的是下面的简单设计,如图。

 

也就是说,我将js,分为公用部分和非公有部分两个文件,非公有js部分每个分行对应一个。

      可是遇到了强大的难题:
        1:如何界定公用js,后续范围变化了怎么半?代码如何维护?难道要所有分行都要修改嘛,不可能。
        2:如何知道我要调用哪个分行的非公有js?这个倒可以通过后面的方法实现。
        3:如何重写公用js里面的js方法?

      也许还有问题,但到此,这个方案也只得放弃。非常的不现实的,维护代价很高,实现难度也不低,外加实现架构乱!

    2.事已至此,唯有实现客户端OOP框架了

   A. 基类的实现

使用ProtoType原型实现,并且加入了一个简单的伪名称空间。

文件名字remit.0000.js

//创建一个名称空间BEGIN

var sdc;

if (!sdc) sdc = {};

else if (typeof sdc != "object")

    throw new Error("sdc already exists and is not an object, error at remit.0000.js");

if (!sdc.RemitBase) sdc.RemitBase=Class.create();//创建基类!

//创建一个名称空间END

 

//下面就是给基类增加方法了

Object.extend(sdc.RemitBase.prototype, {

    initialize: function() {//此方法必须有

   

    },

    payuseOnChanged: function(form, payuseSel, otherField)

    {

       …………

    },

    getPayuseInfo:function()

    {  

       …………

    },

    feecurrtypeOnChange:function(feeObjName){

       currConstrainOnChange('*' + feeObjName);

       this.showRemitCurType();

    },

    outAcctOnChangeExtraHandler : function () //各分行自定义附加函数 remitFun里重写就行了

    {

    },

    outCurrTypeOnChangeExtraHandler : function () //各分行自定义附加函数 remitFun里重写就行了

    {

    },

    conPageInit : function () //确认页面和OK调用的初始化函数

    {     

    }

    …………//其他公用方法

});

B. 子类的实现

我的文件命名规则是remit.地区号.js

var sdc;

if (!sdc) sdc = {};

else if (typeof sdc != "object")

    throw new Error("sdc already exists and is not an object, error at remit.js");

 

var RemitFun = Class.create();

Object.extend(RemitFun.prototype, sdc.RemitBase.prototype);//继承基类

Object.extend(RemitFun.prototype, {//覆盖基类的方法,增加自己的方法

    initialize: function() {

    },

    // Event Handler for inArea

    inAreaOnChangedHadler : function (source)

    {

       …………

    },

    conPageInit : function () //这里就是覆盖的基类方法。

    {     

    }

});

C. 多态的实现。这里用了一个小技巧。

       当时想了几天也没想出来,因为js的运行时怎么可能支持多态呢-_-! 但是,我想到了一个替代的方法,就是依托服务器来实现多态!其实就是:应用服务器能够知道此时需要的子类(分行特定js文件)是什么,让它给发送到浏览器就行了!

    实际上只需要一句代码就解决了。但确实很关键,没有这个伪多态是不行的。

    这句宝贵的代码就是:

<script type="text/javascript" src="<%=webpath%>js/pages/remit/remit.<icbc:label controlID="jsFilePathInfo" />.js"></script>

    红色的代码实际上就是地区号了。

三、总结

    至此,汇款的逻辑部分通过以上形式的组织,将他们大部分都装入了js文件。应用了面向对象的方法,实际效果真是出人意料,很不错。

        1.    消灭了重复代码,提升了复用性。
        2.    可维护性高。由于继承方法,使得新增代码变少了。
        3.    代码的灵活性高,逻辑清晰。

这些优点提升了开发的进度,间接的也减少了出错的几率

posted @ 2011-04-07 10:44 暴风雪 阅读(22) 评论(0) 编辑

 

JS面向对象应用一

----界面分离JS,多语言及校验组件实现

一、多语言实现

       海外以前的代码由于有多语言方面的阻碍,一直是jspjs语言混合编写在同一页面。这样做,第一不符合逻辑分离原则;第二也对带宽造成浪费,不经济。

       只要解决了多语言就能实现js可分离。

1.1原来的代码形式://通过utb这个javabean来动态获得多语言翻译

if(outAcctNameE.trim().length == 0){

              alert("<%=utb.getJSAlert("VALID00005")%>");             //请输入汇款人英文户名

              document.frmRemitApply.outAcctNameE.focus();     

              return;

       }

代码1

1.2实现方案:

       登录后可以取得当前语言的信息,于是只将需要的翻译写在jsp上,并且使用JSON形式组织,其他代码分离到js文件中

       新代码jsp中:

<% //储所有的js校验提示信息 %>

var myErrMsg = {

    inputManual:'<icbc:label text="remit_remitApplyinputManual" />', //手工输入

    saveSampleConfirmTitle:'<%=utb.getJSAlert("VALID00035")%>', //您是否要保存样本?

    mustAgree:'<%=utb.getJSAlert("VALID00025")%>', //有勾选阅读须知,不能提交。

    selectProvince:'<%=utb.getJSAlert("VALID0132")%>'

};

    在使用的地方直接使用myErrMsg.XXXXXX(例如: myErrMsg.mustAgree)就可以了,通过这个方法,就可以将业务逻辑提取成js文件了。Js文件中的翻译使用myErrMsg对象就可以了。

 

二、校验组件

    对于用户的输入是需要校验内容的,其中有很多是相同的逻辑,如校验是否必输并且提示、校验是否是数字并且提示、校验是否是英文等等。

    其调用形式非常类似于上面的代码1,而我们的业务逻辑经常就是多个这样类似的代码组合而成的校验组合,其最后会返回一个校验结果(True False)

    这个组件基本上不会有继承和重载的情况出现,所以只需封装一下这些数据和方法即可。

    2.1Validation类的设计

2.2Validation类的实现,使用prototype原型继承方式创建类。

    function Validation()

{

        this.res = true; //校验成功标志

}

 

校验方法的封装:

Object.extend(sdc.validation, {

 //弹出错误提示信息并置焦点与控件之上

 displayInfoAndFocus: function(obj,str,focusId){

       obj.res = false;

       alert(str);

       if($(focusId) != null && $(focusId).style.display != "none" && !$(focusId).disabled)

           $(focusId).focus();

    },

 //校验必输项是否输入值了

 requiredValid: function (elemId,str,focusId){

       if(arguments.length == 2)

           focusId = elemId;

       if( this.res && !($(elemId).value.trim().length > 0) )

       {

           sdc.validation.displayInfoAndFocus(this,str,focusId);

       }

       return this.res;

    }

    ………………省略其他校验方法

});

每一步判断this.res这个值是一个关键,也就是组合校验的情况下,必须保证前面校验都已经正确了才能进行下面的校验。

 

    创建类的方法:

Validation.prototype.requiredValid = sdc.validation.requiredValid;

Validation.prototype.hasChinese = sdc.validation.hasChinese;

…………省略

 

2.3使用示例:

function test(){

//new出一个对象

var valid = new Validation();

//请输入收款人户名

valid.requiredValid("inAcctName", myErrMsg.requiredinAcctName);

//收款人名称最大136个字符

valid.maxLengthByteValid("inAcctName", 136 , myErrMsg.maxName);

//这里是结合使用非组件验证的情况  

if(valid.res && $("iAgreeChk") != null && $("iAgreeChk").checked == false)

{

 alert(myErrMsg.mustAgree);

 valid.res = false;

}

return valid.res;

}

三、总结

由此页面逻辑可以分离出jsp页面形成单独的js文件,易于维护节约带宽,这里的关键是多语言。校验控件减少了重复代码,使程序更可读,可靠。

posted @ 2011-04-07 10:40 暴风雪 阅读(81) 评论(0) 编辑

2008年7月1日

Firefox可以使用Firebug来调试js,后来发现使用VS更方便,关键有些只能支持IE的系统。。。恐怕只能:P

无意间想到的,既然VS可以拦截js错误来进行调试,应该也能通过自由设置断点的方式。

首先要将IE的Debug JS选项打开。Internet选项->高级->禁用脚本调试 把它后面的队勾去掉。

接着打开VS,2003或者2005都行,附加(Attach)要调试的IE的进程即可。注意要选择Script类型的调试

然后选择VS中的工具栏-->调试-->窗口-->运行文档。之后就会打开当前HTML页面的所以文档,找到要设置断点的位置即可。

然后运行页面即可,通过Vs可以方便的查看各个对象的值和状态,快速定位问题!

 

posted @ 2008-07-01 22:47 暴风雪 阅读(965) 评论(0) 编辑

2008年6月17日

苦思冥想快2天的SplitContainer的Click事件控制SplitterDistance的问题,终于让我查出是什么问题!哈哈哈!

这个按说可以说是个微软的bug了,或者说是设计的时候没有考虑太多。有些东西他们设计也不是很精致亚,嘿嘿。

看张图可能你就明白了。

当鼠标按下的时候,splitContainer会响应自己的MouseDown事件,在这个事件里,他会生成一个新的层从而盖住了下面真正的Splitter。从而会影响到Click时间的执行情况,具体是啥情况就说不清楚了,我猜是:本来Click能好好的执行,可偏偏半路杀出一个MouseDown,这个MouseDown新产生的阴影层挡住了MouseUp的执行(不能算是一次Click操作)。从而使得界面闪了一下就又恢复原状了。

后来的实验也能证实,分别在MouseDown、MouseUp、MouseClick中实验。只有MouseDown可以完全正常执行。

解决方法:
其中一些思路来自于CollapsibleSplitter from codeproject
在Spliter中间画出一部分,点击这部分的时候进行快速切换操作,而点击其它部分的时候,就是控件默认调整

新建class继承自SplitContainer,然后覆盖OnPaint方法

    protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle r = this.SplitterRectangle;
            g.FillRectangle(new SolidBrush(Color.Aqua), r);
            if (Orientation == Orientation.Vertical)
            {
                rr = new Rectangle(r.X, (int)r.Y + ((r.Height - 115) / 2), 8, 115);
                this.SplitterWidth = 8;
  g.FillRectangle(new SolidBrush(hotColor), new Rectangle(rr.X + 1, rr.Y, 6, 115));                
                g.DrawLine(new Pen(SystemColors.ControlDark, 1), rr.X + 1, rr.Y, rr.X + rr.Width - 2, rr.Y);
                g.DrawLine(new Pen(SystemColors.ControlDark, 1), rr.X + 1, rr.Y + rr.Height, rr.X + rr.Width - 2, rr.Y + rr.Height);

                if (this.Enabled)
                {
                    // draw the arrows for our control image
                    // the ArrowPointArray is a point array that defines an arrow shaped polygon
                    g.FillPolygon(new SolidBrush(SystemColors.ControlDarkDark), ArrowPointArray(rr.X + 2, rr.Y + 3));
                    g.FillPolygon(new SolidBrush(SystemColors.ControlDarkDark), ArrowPointArray(rr.X + 2, rr.Y + rr.Height - 9));
                }

            }

     //do not Dispose,is it Ok???
            //g.Dispose();
        }

 

然后在MouseMove中进行判断当前鼠标是否在所画的区域即可,然后分别调用不同的事件处理。

private void OnMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            // check to see if the mouse cursor position is within the bounds of our control
            System.Console.WriteLine(e.X.ToString() + " " + e.Y.ToString());
            if (e.X >= rr.X && e.X <= rr.X + rr.Width && e.Y >= rr.Y && e.Y <= rr.Y + rr.Height)
            {
                if (!this.hot)
                {
                    this.hot = true;
                    this.Cursor = Cursors.Hand;
                    this.Invalidate();
                }

            }

            else
            {
                if (this.hot)
                {
                    this.hot = false;
                    this.Invalidate(); ;
                }


                this.Cursor = Cursors.Default;

                if (controlToHide != null)
                {
                    if (!controlToHide.Visible)
                        this.Cursor = Cursors.Default;
                    else // Changed in v1.2 to support Horizontal Splitters
                    {
                        if (this.Orientation == Orientation.Vertical)
                        {
                            this.Cursor = Cursors.VSplit;
                        }

                        else
                        {
                            this.Cursor = Cursors.HSplit;
                        }

                    }

                }

            }

        }

 

另外还要覆盖MouseDown事件。如果MouseDown的时候是在所画的区域则不调用base的MouseDown

protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!this.hot)
                base.OnMouseDown(e);
        }

posted @ 2008-06-17 21:39 暴风雪 阅读(248) 评论(0) 编辑

2008年4月29日

现实与理想总是有差距,当初我认为这么一个企业是完全有实力建立自己的工程体系和方法的,实际上还完全处于吹牛阶段(CMMI3)。

而事实上不仅仅要有实力还要有能力。每个项目都做的乱糟糟的!作坊式的生产工艺。也许部门也不想这样,因为上面的更大的领导也许根本不关心,只要能干活儿就行了!所有的人都在强调,很多客观因素是无法改变的。没人有试图改变什么,大家都在改变自己,无论是心态还是方法等等。领导的意思很明了,别哀求什么时间不够用,你们还年轻,很有冲劲,潜力很大,做好主力,当好MT,抗住!

软件开发,是个脑力活儿。有时候重复性工作也比较多,所以程序员也有IT民工的称号。并不是所有的代码都可以重用,coding的同时也留下了思维的痕迹,拷贝-粘贴之余,也要思考一番这个东西怎么做,做成啥?所以人在软件开发当中是非常之重要的因素。我讨厌别人把程序员当成纯粹的code maker来用。人不机器,机器也写不出代码(虽然可以替代一部分吧)。

工程是需要计划、组织、人员、管理等等要素的。

在软件开发当中,其实有一点很重要,就是能够比较准确合理的评估出工程所需要的时间。一个正常的项目,起码要根据工作量和团队的水平,给一个合理的估算。但一个问题是,怎么才能估算准啊?国外好像有人发明了几种数学模型,可以用。但我讨厌用数学。。。呃。不爱计算。如果估算的话,最好是让承担任务的程序员来估算,而且不要给他压力,这样应该能够得到一个比较合理的值。但前提是,要先大概分析下要开发的东西需要修改或者新增的东西,然后和以往的工作进行一下类比。最好的情况是,能够在项目进行中,如果发现了偏差可以进行修正。这个因为有些项目是难以修改DeadLine的,所以可以会有些不切实际。

在建筑领域,交付时间是由甲方来定的,软件也是一样,一般都是甲方定好的。相对于建筑,软件的不确定因素太多,且大多时候甲方都是急功近利,从而导致了很多不爽的事情。建筑方面,由于受限于资金流等因素,所以甲方有可能会把交付时间订的比较长,而施工单位也可以通过简单的增加人员的方式来提交工程速度。而做软件一般需求都比较紧迫,项目中也很难通过简单的增加程序员来提高开发速度。另外对于估算工期,建筑方面也很好估算,主体结果的施工,最快7天左右一层,这个要受限于混凝土的凝固速度。而做软件就没这么早的福气了,更多的团队都是期盼,计划能够偏差不大就ok了,实在不行,只能通过加班来处理。

据说印度的软件公司,很强大,工作量可以细化到比较小的粒度,这样可以相当准确的估算出时间。从而减少了加班的出现。

所以,估算工作量,指定交付时间,怎么也要在需求分析之后。否则,就是胡诌了。

关于加班,除了给自己打工的,恐怕没人愿意加班。没有补偿的加班更会打击团队的士气与信心。出现了加班也就意味着出现了偏差,所有人都想努力挽回,可如果偏差太大,再也无法挽回……

不写了,累了。

p.s.  nnd,每个项目都要靠无休止的加班来完成,哪个X订的计划。

posted @ 2008-04-29 22:52 暴风雪 阅读(32) 评论(0) 编辑

2008年3月20日

posted @ 2008-03-20 22:30 暴风雪 阅读(411) 评论(0) 编辑

2007年12月27日

摘要: 2007年,我走出了朝夕为伴的校园,迈入了社会。阅读全文

posted @ 2007-12-27 23:51 暴风雪 阅读(1673) 评论(13) 编辑

2007年12月22日

摘要: 对于HTML中的Id和Name。阅读全文

posted @ 2007-12-22 09:50 暴风雪 阅读(1773) 评论(1) 编辑

2007年4月26日

posted @ 2007-04-26 22:05 暴风雪 阅读(24) 评论(0) 编辑