Archive for 二月, 2011

点菜页面实现的思考(javascript复杂页面实现)

悠点网(http://www.okto.cn,又进行了一次改进,页面内容变的更丰富,更有层次感了,用户体验有了不错的进步。 改版的前端工作量很大部分集中在点菜页面的功能实现。 DEMO地址:http://okto.cn/b2c.do?mod=rest&ac=order&restid=27 点菜页面实现目标: 1、整个点菜过程无刷新,提高用户体验。 2、提供菜肴列表。 3、用户点击菜肴,菜肴进入左方菜单处。可以自由增减,并实时计算菜的个数和总价。 4、支持多人点菜,并能同步菜单。 5、有聊天窗口,可以边点菜,边聊天。且聊天窗口可拖动。 6、支持小工具,例如锁定菜单,超支提醒等等。 现在实现这些功能的思路是这样的(感谢张三东童鞋:O)。 首先,抽离数据层,用来和服务器进行交互。 function DataProvider(){} ,首先给DataProvider扩充必要的本地数据,用户名,用户id,用户头像等等。 DataProvider.prototype.post=function(data,callback){}  ,扩充post方法,想服务器提交数据。 在post的基础上,扩充各种细化的数据方法,满足数据交互的需要。 然后是表现层。 表现层主要由很多的面板组成。聊天面板,点菜单面板,导航TAB面板,导入菜单列表面板,导入菜单详细面板,菜肴列表面板。 所有的面板继承自Pannel, Pannel具有以下几个属性或方法。 close(关闭),open(打开),dataprovider(数据源,指向dataProvider) containerBox(指向面板容器的DOM对象),parentComponent ,指向父级的对象。 当面板打开时,执行初始化函数,来出初始化面板的各种参数及必要的DOM表现。 ————————————————————————————————————————————— 接着昨天的说。 今天又改进了一下结构。 所有的面板都有自己的对象,对象都首先继承了基类Pannel,首先构造一个大面板,包括所有的小面板,这个大面板没有自己的表现层,而是充当所有小面板之间的调度和联系的作用。 起初只是让大面板起一个桥梁的作用。比如在菜肴面板中点击菜肴,需要菜单面板同时添加一个这个菜肴的信息。起初是这样做的,self.parentComponet.cartPannel.addFood..  ,也就是说,通过大面板找到对应的响应面板的方法。 这本来没有什么问题,但是发现在实际的程序运行中,有很多东西都是相互关联的,也就是说,某个操作,是更新两个面板,而另外一个操作,也是更新两个面板,但是产生事件的位置,却不一致。 今天就解决下这个问题,就是让外部的这个大面板,添加一些方法,来同时更新小面板。然后大面板中也集成了定时刷新服务器等服务。 今天也增加了一个数据缓存,以前判断一个菜是否已经被选用,是查找左边的菜单中是否存在包含菜ID的DOM元素存在,效率比较差,现在增加了一个数据缓存,把这些数据缓存在一个对象中,保存在dataProvider.dataCache中。 其他的操作,都比较分散,大多数就是事件处理函数的派发,和把数据格式化为HTML,都集成在各自的面板中。 总之,就是如果有协同操作的,也就是同时更新两个以上面板的操作,都由大面板的对应方法派发,单独的,都控制在对应小面板内。 感觉还有很多地方可以优化,明天继续改。 今天和三东童鞋讨论了一个问题,现在的web前端程序,与服务器后端进行交互,有这样一个老大难问题。就是,如果后端返回的数据改了,例如本来的菜ID叫foid,前端程序取值用data.foid,如果有一天,菜ID叫foodid了,前端程序就要大改,因为可能很多地方都是用foid这个键名,代价太大了。 有什么好的解决方法呢? ——————————————————————————————————————————————————- 好吧。终于结束了。 内存泄露问题还有很多,不知道什么时候能够完全解决。

前端为什么难搞? 看我任务栏中的窗口数有感

今天和一朋友聊起来,他截了个图给我,他的桌面上,遨游,IEtester,Firefox,Chrome,Safari,IE.. 各种浏览器都有,甚至还有一个ie7.bat 。 我看了一下我桌面的软件,发现我也安装了不少软件。 现在列一下我安装的软件(和前端开发有关的)。 图像处理软件:Photoshop,Fireworks  ; 写HTML+CSS的: Dreamweaver ; 写Javascript的: Aptana, Webstorm ; 做动画的: Flash ,Swishmax ; 写Actionscript的: Flashdevelop,Flex builder; 浏览器: IE8,Firefox,Chrome,Safari,Opera,IEtester; 写php的: Zend ; 画线框图的:Axure 突然觉得做前端的真悲剧,需要懂的东西真多。 你需要懂点美工,需要会HTML,css,要会写JS,AS,还要懂点后端的程序,这还不算完,用户体验也要顾得上,于是,还要会画画线框图。 要求真是令人发指。高投入,低回报,真是泪流满面。。。。 如果你也是做web的,你都安装了些什么程序?

常用JS函数(3)

function toJSONString(o) { var r = []; if(typeof o ==”string”) return “\””+o.replace(/([\'\"\\])/g,”\\$1″).replace(/(\n)/g,”\\n”).replace(/(\r)/g,”\\r”).replace(/(\t)/g,”\\t”)+”\””; if(typeof o ==”undefined”) return “undefined”; if(typeof o == “object”){ if(o===null) return “null”; else if(!o.push){ for(var i in o) r.push(“\””+i+”\””+”:”+toJSONString(o[i])) r=”{“+r.join()+”}” }else{ for(var i =0;i<o.length;i++) r.push(toJSONString(o[i])) r=”["+r.join()+"]“ } return r; } return o.toString(); } function toJSONString(o) { var r = [];    if(typeof o ==”string”) ...Read More

对JS内存泄露的一些思考

昨天在群里和西门,天天讨论js的内存泄露问题。 JS的内存泄露,无怪乎就是从DOM中remove了元素,但是依然有变量或者对象引用了该DOM对象。然后内存中无法删除。使得浏览器的内存占用居高不下。这种内存占用,随着浏览器的刷新,会自动释放。 而另外一种情况,就是循环引用,一个DOM对象和JS对象之间互相引用,这样造成的情况更严重一些,即使刷新,内存也不会减少。这就是严格意义上说的内存泄露了。 感谢天天,提供了IE6给我们的脚本进行测试,然后我们发现IE6的内存泄露问题确实特别严重,而我的IE8下不会出现的问题,在IE6下反而很容易出现。 首先,我写了一个制造一个大DOM对象的函数。很简单,就是给DOM对象增加了一个很大很大的属性。恩。几MB function MemoryLeak(){ var p=document.createElement(“p”); p.bigAttribute=new Array(1000).join(new Array(1000).join(“xxxx”)); } 一百万个XXXX,几个MB,恩 首先,一个明显的循环引用。 function MemoryLeak(){ var o={}; o.p=document.createElement(“p”); o.p.bigAttribute=new Array(1000).join(new Array(1000).join(“xxxx”)); o.p.e=o; } 这个肯定没问题,js对象o和DOM对象p之间形成了相互引用。 在IE6下,内存溢出了,即使刷新,内存占用也不会下降。在我的IE8下,内存不会增加。IE8改进了不少问题嘛。窃喜中。。。 西门提供了一个函数,也是会造成IE6的内存溢出。 function leak_ximen(){ var fn = function(){}; var obj = document.createElement(“div”); obj.bigAttribute=new Array(1000).join(new Array(1000).join(“xxx”)); obj.onclick = fn; } 这个函数的内存溢出问题很隐蔽。事实上,DOM元素通过onclick引用了一个function,而function的active object引用了变量obj,而变量obj又引用了DOM元素。于是形成了一个环形引用。IE6又一次出现了问题。。。 西门又提供了另外一个方法。避免了这个问题。 function leak_ximen3(){ var fn = function(){}; (function() ...Read More

常用JS函数(2)

function DOMReady(fn){ if(document.addEventListener){ document.addEvent(“DOMContentLoaded”,fn,false); } else{ setTimeout(fn,0); } } function Each(obj,fn,args){ var isObj=false; if(typeof obj==”object” || typeof obj==”function”){ isObj=true;} if(args){ if(isObj){ for(var i in obj){ fn.apply(obj[i],args); } } else{ for(var i=0;i<obj.length;i++){ fn.apply(obj[i],args); } } } else{ if(isObj){ for(var i in obj){ fn.apply(obj[i],i,obj[i]); } } else{ for(var i=0;i<obj.length;i++){ fn.apply(obj[i],i,obj[i]); } } } }

Chrome浏览器在function内部delete参数时的一个特例

function c(x){ alert(delete arguments[0]); alert(Array.prototype.slice.call(arguments, 0)); alert(x); } 执行c(1) 最后一行的输出结果,除了ch是undefined之外,包括safari,都是1。或许可以说,在chrome中,可以删除形参。但是又非常微妙的是,第一行结果统统为true,第二行的结果又统统为空。 相同的是,直接delete x和delete arguments.callee.arguments都不会成功。 你甚至可以delete arguments.callee。

获取js函数的名称

例如function a(){…} 那么a就是这个func的名称 如果var f = function a(){} 那么这个func依然是a,而f是一个引用。 如果var f = function(){} 这是个匿名函数,函数名为”。 除了IE之外,ff,sa,ch,op的函数都有name属性,比如a.name。 而IE下,我们只能调用函数的toString()属性,通过正则来获取。 我们污染一下原型 Function.prototype.getSelfName = function(){ return typeof this.name === ‘string’ ? this.name : /function\s+([^\{\(\s]+)/.test(this.toString()) ? RegExp['$1'] : ‘[Unknown]‘; }

常用JS函数(一)

绑定事件 function addEvent(o,l,f){ if(o.addEventListener){ o.addEventListener(“on”+l,f,false); } else{ o.attachEvent(l,function(){f.call(o,window.event);}); } } 用法: var link=document.getElementById(“a”); addEvent(link,”click”,function(e){alert(e)}); 获取指定ID的元素 function $(o){ return typeof o==”string”?document.getElementById(o):o; } 用法: var a=$(“links”); 创建DOM元素 function Element(tag,obj){ var ele=document.createElement(tag); for(var i in obj){ if(i==”listeners”){ for(var k in obj[i]){ addEvent(ele,k,obj[i][k]); } else{ ele[i]=obj[i]; } } } return ele; } 用法: var span=new Element(“span”,{“className”:”abc”,”listeners”:{“click”,function(){alert(1)}}}); 当然用不用new都一样,只是用new更有感觉不是吗?  :) 判断元素是否属于包含关系 ...Read More

flash中的htmlText

flash开发中,经常会读取后台的html数据源,在很多情况下,是HTMLEditor生成的html字符串。 但是flash对html标签支持实在是太差了。。好吧,反正adobe不是搞浏览器的,它才不管洪水滔天呢。 <a>标签:支持href和target属性 <b>标签:加粗显示 <br>标签:换行 <font>标签:支持color和face属性。 <p>标签:支持align和class属性 <u>标签:加下划线 <img>标签:支持src,width,height,align,hspace,vspace,id属性 还有一个特殊的标签<textformat>:支持blockindent , indent  , leftmargin,rightmargin , tabstops属性 可以看出,flash支持的html标签及其有限,而且在图文混排上,显示的也和html不同。

写一个js文件的loader

我印象中,js脚本文件的loader似乎有,但是完美的,完美到像php的include或者cSharp的using的,貌似没有。有些团队据说有,但是没有一个公认的好的方式,或者说没有一个团队愿意拿出来共享,我觉得这说明,他们的方法都存在问题:或者代码冗余,或者存在n多不确定性,或者只适用于他们自己的环境。 注意我说的是一个文件的loader,是通过script标记的src属性调用,而不是将js代码通过innerHTML写到一个div或者什么标签里。 为什么要写loader呢? 比如jq的冗长是我们经常诟病的一个问题。我在冒死写我自己的类库的一开始,我就确定了一个事情:分文件写。也就是,一个核心的、公共的类库是必需的,然后根据页面需要挂所需的js文件。我觉得这个出发点还是不错的。但是后来我意识到,比如在ui部分,tab标签、无缝滚动、图片轮显、ajax等等诸多部分分在不同的文件中,而往往首页里这些都要用得到,那么,script标记在页头最多时有10个上下。当然,如果你不在意还行。我觉得有点蠢。 jq的冗长是我不要的,script标记过多也不是我要的,所以,我需要一个loader。 但是我还没想好。 这里只做一个简单的实现,实现通过js添加一个script标记,并且确保这个标记引入的文件会被执行。 想到的方式有两种:通过dom添加和通过document.write直接写。 通过dom方式是最方便、简单,并且标准的方式。只要通过document.createElement创建一个script标记,并且按照html标准添加type和src属性,然后把这个标记添加到页面当中去就可以了。但是如我们所知,如果我们不把具体的js代码放到window.onload当中去的时候,js标记的位置是个很重要的问题。也就是说,你的类库文件必须在前,实例应用必须在其后,不但js是逐行的,ie中html也tmd的是逐行的。在添加js标记时,我选择将标记放到head中。并且,head是一个默认标记,就像document,无论你的html中是否有head代码,head标记都是存在的。所以无需判断head标记是否存在,直接用head.appendChild即可。需要注意的问题有二:1、head的获取,在ie下是需要使用getElementsByTagName(‘head’)[0]来获得,其他浏览器直接document.head即可得到。2、执行顺序ie有所不同。我的感觉:在ie下,ie会重新理解标记位置,按script标记在head中的顺序逐行执行引入的文件;而其他浏览器,是按照引入的时间来执行的,比较复合人类的思路。 通过document.write方式,更直接。我先说一下我最终没有采用dom方式的原因:文件加载完成的时间不确定。我幻想过,当我添加了一个新的script标记后,window.onload事件会再次触发一次。当然事实并不是这样。换句话说,我不知道js文件什么时候能够加载完。而当你document.write的时候,所写入的代码会成为html解析的一部分,所以浏览器会等待js文件加载完成以后再执行下面的解析。需要注意的问题:如果在script标记A中使用document.write写了一个script标记B,那么,标记B会紧跟在标记A之后,也就是说是在标记A的外部。所以,在标记A中不能使用动态写入的标记B中的代码,需要在标记A之外重新写script标记来执行标记B中的代码。 最后附上muselite库里暂时新加的window.using代码,这段代码还没有想好怎么用,仅仅完成了文章开头所说的,动态添加的功能而已。 window.MUSELITE_DEFAULT_FOLDER = ‘Scripts’; (function(w, arr){ w._using = function(app){ if(!app || typeof app != ‘string’) return; var i = 0, len = arr.length; for(; i < len; i++) arr[i] === null ? document.write(app) : document.write(arr[i]); } w.using = function(){ if(arguments.length < 1) return; var i ...Read More