构建一个前端库-做一个富客户端的基类
基类,我们需要一个基类。
数据库访问我们通常有一个基类,用于操作的统一性。
那么,我们现在需要一个富客户端的前端基类。
为什么我们需要它。
1.我们需要一个dom元素与javascript之间的桥梁。
2.我们需要一个可伸缩布局的方案。
3.它是可拖动的。
4.它是可改变大小的。
5.它是可参数化配置的。
6.它是可绑定数据源的。
7.它是可隐藏也可延迟加载的。
我们需要这么一个基类,避免我们重复写很多相似的代码、
我们一个一个来说它们的实现。
1.构建桥梁
通常我们都用document.getElementById来用javascript获取一个dom元素。
但这里,我们富客户端的方案是用javascript生成dom对象,并且用jQuery辅助我们的元素获取。
所以首先我们来动态构建html
if (v.modal == 1) { //允许多个模态对象并存 if (_modal_layer) _modal_layer += 5; else _modal_layer = radf.MODAL_LAYER; v.parent = _root; v.zIndex = _modal_layer + 1; } else if (v.modal == 2) { //只允许同时存在一个非模态对象,后面的非模态对象会替代前面的非模态对象 if (_modeless) { _modeless._param.modal = 0; if (_modeless._loaded) _modeless.sendToTop(); else _modeless._param.zIndex = 1; } v.parent = _root; v.zIndex = radf.MODELESS_LAYER; _modeless = this; } //html定义 if (v.id) this._html= v.tagName + " id=" + v.id + " class='" + v.className + "' _objIndex=" + this._objIndex + " _loadMode=" + v.loadMode; else this._html= v.tagName + " class=" + v.className + " _objIndex=" + this._objIndex + " _loadMode=" + v.loadMode; if (v.tip) this._html += " title='" + v.tip + "' "; //样式属性 this._style = " style='position:absolute;overflow:" + v.scrollBar; if (this._padding.text) this._style+= ";padding:" + this._padding.text; //留白 if (this._borderWidth.text) this._style+= ";border-width:" + this._borderWidth.text;//边框宽度 if (v.borderStyle) this._style+= ";border-style:" + v.borderStyle; //边框样式 if (v.borderColor) this._style+= ";border-color:" + v.borderColor; //边框颜色 if (v.background) this._style+= ";background:" + v.background; //背景 if (v.style) this._style += ";" + v.style; //样式 if (v.minWidth == 0 ) v.minWidth = this._borderWidth.left + this._borderWidth.right + this._padding.left + this._padding.right; if (v.minHeight == 0 ) v.minHeight = this._borderWidth.top + this._borderWidth.bottom + this._padding.top + this._padding.bottom; //位置属性 this._top = v.top; this._left = v.left; this._y0 = this._padding.top + this._borderWidth.top; this._x0 = this._padding.left + this._borderWidth.left; this._oldY0 = this._y0 this._oldX0 = this._x0;
然后,我们把这个html用jQuery包装起来。
Control.prototype.$ = $(this._html);
最后,我们用一个全局的数组来保存所有产生的javascript对象。
var radf._objIndex = []; this._objIndex = radf._obj.length; radf._obj[this._objIndex] = this;
这样,我们在这个对象内部就拥有了它自己的jQuery对象,在全局上也拥有了一个可控的Javascript对象。
我们可以轻易的在全局使用这个javascript也可以方便的在原型中使用jQuery对象。
2.可伸缩布局的方案
浮动和清除浮动是前端永恒的话题。但是我们的方案中,用了一个神奇的东西。
position:absolute
好吧,我们都知道它是一个禁果。
它非常轻易的可以实现元素的随意摆放,但也非常损耗性能。
使用它,我们要注意几件事
1.margin,padding不再可使用。
2.需要一个可承受的性能损耗。
3.z-index变得十分重要。
4.可控的元素嵌套。
5.可实现的算法。
所以我们写了三种情况下的算法。
//1. 重画大小不依赖于父组件的子组件 this._redrawFirst(); //2. 确定自适应方式下的组件大小 this._redrawSecond(); //3. 重画大小依赖于父组件的子组件 this._redrawThird(); //4. 布局子组件 if (this._layout) this._layout();
由于我们在布局的时候,ajax操作会异步执行,
所以经过测试,在数据到来的零点几秒之内,
dom元素的布局是完成了,所以算法的时间消耗是可以接受的。
3.可拖动及可以改变大小
绝对定位的原因,可拖动变得十分简单。
改变大小的问题,在于改变大小后,调用上面的方法,重算父窗口就ok了。
4.可配置的参数
Control.prototype.create = function(v) { //设置缺省参数 //for (var i in this._defaultParam) if (v[i]==null) v[i] = this._defaultParam[i]; radf.Utility.copy(this._defaultParam,v); //保存初始化参数 this._param = v; //设置父对象 if (v.parent == null || v.modal > 0 ) { if (_root) v.parent = _root; else v.parent = root(); } v.parent._addChild(this); //建立对象索引 this._objIndex = radf._obj.length; radf._obj[this._objIndex] = this; //初始化参数 this._iniParam(v); }
我们看一下一个类实例化的时候会做些什么, 将默认参数存起来,将填写的参数加入到实例中,
将父对象保存起来,建立对象的索引号。
5.可绑定数据
我之前提到的MVVM模式的优势在于,数据先到的话,就会将数据存起来,
dom先加载了,就会将外框的div先加载,而里面的数据,例如table中的td,在数据到来的时候再加载。
并且,在dom元素操作的时候,也会通过基类写好的方法,将数据重新绑到数据对象。
或者在操作数据对象,例如重新从数据库取出数据后,就会重新生成dom元素。
这样,一个可绑定的组件基类就ok了。
7.它是可隐藏并且可以延迟加载
我们知道,当一个dom对象需要隐藏,将它的display设成none,就会让这个元素不占位的隐藏。
如果用visible的话,就会占位隐藏。由于富客户端的作法,我们基本上没有外链,所有操作都在一个页面上,
空间非常的局限。所以一个可以伸缩的页面是非常必要的。
那么我们使用display将单个组件变得可以隐藏起来,以用来显示全全部内容。
那么延迟加载就很好理解了,如果元素被设为visible:false,那我们就不做这个元素的数据绑定,也不会这个对象的宽高,
只有一个空的div在那里。当这个元素被要求显示,例如一个折叠框打开时候,我们再去load它。