浏览 3404 次
精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-03-31
最后修改:2010-04-01
目录 (一)有关框架 (二)文件组织与代码组织 (三)JS与FLASH交互 (四)ajax局部刷新与RPC (五)获取设置元素样式与监听元素事件 (六)页面元素的创建调整与关联 (七)浏览器兼容性问题 (八)WEB软件的前端架构实践 文章中的代码只为表达文章意义,非真正能执行的代码。 动态创建、调整element 一、你考虑清楚要直接操作element吗? 用这个疑问来表示对这种行为的慎重,操作element有哪些地方你可能需要考虑呢:
即使有以上考虑,有以下情形我还是选择直接操作element
另外,刷新整个部分与只更新变化的地方,用户体验会更好,不会闪的那么厉害,而且要做动画表示这个变化也方便。 二、应用模板进行局部更新 应用整体模板 应用模板编程的优势及示例,我就不再重复。再次请大家参见金大为的雏凤清音 -- 面向数据的前端编程方法 应用局部模板 var groupManagerCmp = { body: "#userGroup", viewTemplete: new Template( "<tr><td>${name}</td><input type='button' value='编辑' /><td></td><td><input type='button' value='删除' /></td></tr>"), editTemplate: new Template( "<tr><td><input type='text' value='${name}'></td><td><input type='button' value='提交' /></td><td><input type='button' value='取消' /></td></tr>"), renderViewRow: function(id, name){ var tr = this.viewTemplete.bind(id,name); $("input[0]",tr).click(function(){ //编辑 groupManagerCmp.edit(tr, id, name); }) $("input[1]",tr).click(function(){ //删除 action.do("delete", {id: id}, function(){ groupManagerCmp.remove(tr); }) }) return tr; }, renderEditRow: function(id, name){ var tr = this.editTemplate.bind(id,name); $("input[0]",tr).click(function(){ //提交 action.do("put", {id: id, name: name}, function(group){ groupManagerCmp.update(tr, group.id, group.name); }) }); $("input[1]",tr).click(function(){ //取消 groupManagerCmp.update(tr, id, name); }) return tr; }, append: function(id, name){ $(this.body).appendChild(this.renderViewRow(id, name)); }, remove: function(trNode){ $(this.body).removeChild(trNode); }, edit: function(trNode, id, name){ $(this.body).replaceNode(trNode, this.renderEditRow(id, name)); }, update: function(trNode, id, name){ $(this.body).replaceNode(trNode, this.renderViewRow(id,name)); } } var action = { url: { post: "group/new", put: "group/update", delete: "group/destroy" } do: function(action, params, callback){ ajax(this.url[action], params, function(data){ callback(decode(data)) }); } } 三、应用状态模式应对复杂的界面变化 项目中有一个随机聊天的东西,系统从到达此页面的人中随机两两配对,进行聊天。 业务过程: 用户点击开始配对-----》系统开始找人与你聊天 <------------------------------- | | ---------------------------- | | | | 找到人,开始聊天 没找到,提示可重新配对 | | | | 聊天中 点击重新配对----------------------------- | | | | 对方退出或中断,提示可重新配对 | | | --------------------------- | | | | 关闭页面 点击重新配对-------------------------------- //某种状态变化后,都调用updateView更新界面 function updateView(state, args){ if(state == "connectSuccess"){//连接成功 chatWin.show(args); jQuery("connectWin").hide(); }else{ chatWin.hide(); if(state == "ready"){ //未连接,等待用户点击连接 //code }else if(state == "connecting"){ //正在连接 //code }else if(state == "connectFail"){ //连接失败 jQuery("#status").text("连接失败"); jQuery("#btnConnect").show(); }else if(state == "strangerLeft"){ //对方离开 //code }else if(state == "connectInterrupt"){ //连接中断 //code }else if(state == "timeout"){//连接超时 //code } } } function connect(currentUser){ chatProxy.connect(currentUser.userId, function(state, data){ if(state == "success"){ updateView("connectSuccess", data.stranger); }else{ updateView("connectFail"); } }) } 三、应用观察者模式应对多处界面变化 示例:当用户变更它的个人信息时,更新见面中显示用户个人信息的地方。用户的个人信息可能在多个页面的不同位置显示。 //用户类 User = function(uinfo){ for(var p in uinfo){ this[p]=uinfo[p]; } this._observers = []; }; User.prototype = { //更新属性 update: function(property, value){ if(this.hasOwnProperty(property)){ if(this[property] != value){ this[property] = value; this.notice(property); } } }, //增加属性变更监听者(函数) addListener: function(property, observer){ if(!this._observers[property])this._observers[property] = []; this._observers[property].push(observer); }, //通知变更 notice: function(property){ var observers = this._observers[property]; if(observers && observers.length){ var value = this[property]; $.each(observers, function(i, fn){ fn && fn(value); }) } } } //在页面初始化代码中添加监听函数 jQuery(document).ready(function(){ currentUser.addListener("name", function(name){ jQuery("#userName").text(name); }) currentUser.addLIstener("icon", function(icon){ jQuery("#userIcon").attr("src",icon); }) }) //在业务代码中,当用户更新个人信息,用户对象自动调用监听函数更新页面。 currentUser.update("name","lucy"); currentUser.update("icon","url"); 三、给元素操作取一个名字 给逻辑相关的元素操作封装在一个方法里面,并取一个与业务相关的名字是一个好的做法。特别是当这个操作的代码重复出现在多个地方的时候,更有这个必要。 function updateUserHometown(province, city){ jQuery("#homeTown").html(provinece + "," + city); } 在JS对象中关联element 一、直接关联还是通过查找引用 var testDiv = document.createElement("div"); testDiv.id = "testDiv"; document.body.appendChild(testDiv); document.body.removeChild(testDiv); alert(testDiv.nodeName); //DIV alert(testDiv.paretNode); //undefined delete testDiv; 此时testDiv才被清除 通过以上代码可以看出,当你直接关联到元素时,就有可能造成元素被移除后,其对映DOM对象还在。基于这个原因,要小心因此可能造成内存泄露。 而通过ID或者其他选择器则不会有这个问题。但每次取不是很麻烦费时吗?其实你只要保证关联到元素的变量会被释放,还是应该直接引用的 function updateView(){ var con = document.getElementById("container"); //code ... } 因为con是一个局部变量,所以它在函数调用后被释放了。 (function(){ var con = document.getElementById("container"); updateView = function(){ alert(con); } })() document.getElementById("container").parentNode.removeChild(document.getElementById("container")); updateView(); //con还是存在。 二、避免引用散布到代码中 将元素CSS选择表达式散布的代码中,维护起来确实很麻烦,也使得我们的代码和页面结合得更加紧密,这是我们不希望看到的,考虑以下办法避免: //方法一:通过参数传递元素选择表达式 function submitForm(){ document.getElementById("userInfoForm").submit(); } function submitForm(formId){ document.getElementById(formId).submit(); } //<a href="javascript:submitForm("userInfoForm")" >提交</a> //方法二:通过get方法把变化集中到一处 function getMainGrid(){ return document.getElementById("mainGrid"); } //方法三:尽量把引用放到一处,然后通过传递参数引用元素。 function initSidebar(){ var s1 = document.getElementById("s1"); var s2 = document.getElementById("s2"); new Sidebar(s1,"news") new SIdebar(s2, "videos"); } 三、考虑关联element被其他业务逻辑删除的情况 在实际项目中,我做了一个文字滚动,做好之后,我发现滚动部分在多种情况下会被替换掉,而文字滚动我是通过setInterval来做的,虽然滚动动画的类里有停止滚动的接口,但由于刷新页面的逻辑不是集中于一个函数内,并且局部刷新页面的动作很大可能还会在未来的代码里面出现,因此我考虑还是由滚动类自己监测容器元素是否存在,由此来决定是否停止滚动,并释放自己。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |