dojo怎样extjs 动态创建div和删除div

dojo/dom-construct.toDom方法学习笔记-爱编程
dojo/dom-construct.toDom方法学习笔记
  toDom方法用来将html标签字符串转化成DOM节点。1.7之后toDom方法被分配到了dom-construct模块。
require(["dojo/dom-construct"], function(domConstruct){
// Take a string and turn it into a DOM node
var node = domConstruct.toDom("&div&I'm a Node&/div&");
  dom操作是每位想要有所建树的前端开发者必须要跨过的槛,类库虽好常用有依赖,对于类库里常用的函数,我们要做到知其然知其所以然。toDOM将html转换为dom节点,我能想到的是两种方法:
利用正则表达式,依次匹配出所有标签;首先需要一个正确的正则,其次需要保证正确的节点关系
利用dom的api来做,这个我们可以创建一个元素使用innerHTML来自动转换
  很明显,第二种方法简单,全部交给浏览器去做,我们只需拿到元素的子节点即可;但是innerHTML标签又有它的特殊性:
innerHTML取值时会把所有的子元素作为文本输出;
设值时,会先将字符串转化为dom节点,然后用dom节点替换元素中的子元素;此时如果字符串中有特殊标签开头,比如tbody、thead、tfoot、tr、td、th、caption、colgroup、col等;对于必须存在包装元素的标签,浏览器不会为这些标签补全包装元素,或者统一作为文本处理,或者忽略这些标签
那我们就有必要对html标签进行一些修正,主要是针对必须存在于包装元素的标签;这些标签作为innerHTML赋值会被浏览器忽略,但是如果作为dom节点直接挂载到dom树中,浏览器会为他们自动创建隐含的包装元素。所以在遇到这些标签开头的html片段时,我们需要手动补全缺失的包装元素。
  下面我们来看一下dom-construct模块是怎么处理的。
  找出所有待补全的元素:tbody、thead、tfoot、tr、td、th、caption、colgroup、col、legend、li;dojo中使用如下结构将某些缺失的标签管理起来:
var tagWrap = {
option: ["select"],
tbody: ["table"],
thead: ["table"],
tfoot: ["table"],
tr: ["table", "tbody"],
td: ["table", "tbody", "tr"],
th: ["table", "thead", "tr"],
legend: ["fieldset"],
caption: ["table"],
colgroup: ["table"],
col: ["table", "colgroup"],
li: ["ul"]
  经过下面这一步处理后,tagWrap中的每一项中多了两个属性, eg:tagWrap.tr.pre = "&table&&tbody&"和tagWrap.tr.post = "&/tbody&&/table&";
for(var param in tagWrap){
if(tagWrap.hasOwnProperty(param)){
var tw = tagWrap[param];
tw.pre = param == "option" ? '&select multiple="multiple"&' : "&" + tw.join("&&") + "&";
tw.post = "&/" + tw.reverse().join("&&/") + "&";
  1、innerHTML方式需要一个额外的元素,作为临时的容器,所以利用一下变量来管理这个额外的元素:
var reTag = /&\s*([\w\:]+)/,//用来判断字符串参数中是否含有html标签
masterNode = {},//作为仓库来管理临时容器
masterNum = 0,//z这两个变量用来标识临时容器
masterName = "__" + dojo._scopeName + "ToDomId";
  2、toDom方法中,首先创建一个临时容器,是一个div元素:
doc = doc || win.
var masterId = doc[masterName];
if(!masterId){
doc[masterName] = masterId = ++masterNum + "";
masterNode[masterId] = doc.createElement("div");
  &3、然后判断frag中是否含有html标签,如果含有html标签而且需要我们补全包装元素,则利用上面生成的pre和post补全标签后传递给master这个容器的innerHTML,这一步完成后找到我们传入的html标签对应的dom树,赋值给master;如果不需要包装,直接赋值给master.innerHTML
var match = frag.match(reTag),
tag = match ? match[1].toLowerCase() : "",
master = masterNode[masterId],
wrap, i, fc,
if(match && tagWrap[tag]){
wrap = tagWrap[tag];
master.innerHTML = wrap.pre + frag + wrap.
for(i = wrap. --i){
master = master.firstC
master.innerHTML =
  这里仅是简单的认为如果正则匹配则进行包装处理,按照我的理解,正则的写法应该为:/^&\s*([\w\:]+)/,原因看下面例子:
  第一个表达式子所以报错,就是因为&adffd&这部分在dom中被作为文本节点,文本节点并没有子节点。更改了正则之后,如果不是html标签做开头则统一作为文本节点添加到dom中去。
  4、将html标签转化成dom后,如果仅有一个元素则返回这个元素,否则将转化后的元素,放入到文档片段中。
if(master.childNodes.length == 1){
return master.removeChild(master.firstChild); // DOMNode
df = doc.createDocumentFragment();
while((fc = master.firstChild)){ // intentional assignment
df.appendChild(fc);
return // DocumentFragment
  参考标准的描述,DocumentFragment是一个轻量级的文档对象,能够提取部分文档的树或创建一个新的文档片段。可以通过appendChild()或insertBefore()将文档片段中内容添加到文档中。在将文档片段作为参数传递给这两个方法时,实际上只会将文档片段的所有子节点添加到相应的位置上;文档片段本身永远不会称为文档树的一部分
利用innerHTML标签创建dom元素,并自动补齐缺失的标签,这就是dom-construct模块针对toDOM方法的实现思路。
1 exports.toDom = function toDom(frag, doc){
// summary:
instantiates an HTML fragment returning the corresponding DOM.
// frag: String
the HTML fragment
// doc: DocumentNode?
optional document to use when creating DOM nodes, defaults to
dojo/_base/window.doc if not specified.
// returns:
Document fragment, unless it's a single node in which case it returns the node itself
// example:
Create a table row:
require(["dojo/dom-construct"], function(domConstruct){
var tr = domConstruct.toDom("&tr&&td&First!&/td&&/tr&");
doc = doc || win.
var masterId = doc[masterName];
if(!masterId){
doc[masterName] = masterId = ++masterNum + "";
masterNode[masterId] = doc.createElement("div");
if(has("ie") &= 8){
if(!doc.__dojo_html5_tested && doc.body){
html5domfix(doc);
// make sure the frag is a string.
frag += "";
// find the starting tag, and get node wrapper
var match = frag.match(reTag),
tag = match ? match[1].toLowerCase() : "",
master = masterNode[masterId],
wrap, i, fc,
if(match && tagWrap[tag]){
wrap = tagWrap[tag];
master.innerHTML = wrap.pre + frag + wrap.
for(i = wrap. --i){
master = master.firstC
master.innerHTML =
// one node shortcut =& return the node itself
if(master.childNodes.length == 1){
return master.removeChild(master.firstChild); // DOMNode
// return multiple nodes as a document fragment
df = doc.createDocumentFragment();
while((fc = master.firstChild)){ // intentional assignment
df.appendChild(fc);
return // DocumentFragment
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。javascript table 动态创建 tr ,删除tr 等相关操作 - mojianpo 莫建坡 - ITeye技术网站
博客分类:
使用框架或者才采用 clonse 方式也可以实现。
直接javascript操作:
&!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&
&html&
&meta http-equiv="Content-Type" content="text/ charset=UTF-8"&
&title&Insert title here&/title&
&head&
&title&UPLOAD HTML&/title&
&link href="dojo-release-1.5.0/dijit/themes/dijit.css" rel="stylesheet" /&
&link href="dojo-release-1.5.0/dijit/themes/tundra/form/Button.css"
rel="stylesheet" /&
&link href="dojo-release-1.5.0/dijit/themes/tundra/ProgressBar.css"
rel="stylesheet" /&
&script&
&&&&&&& djConfig = {
&&&&&&&&&&& isDebug: false,
popup:true,
&&&&&&&&&&& parseOnLoad: true
&&&&&&& }
&&& &/script&
&script src="dojo-release-1.5.0/dojo/dojo.js"&&/script&
&script&
&&&&&&& dojo.require("dojox.form.FileUploader");
&&&&&&& dojo.require("dijit.form.Button");
&&&&&&&
&&&&&&& dojo.addOnLoad(function(){
var props = {
uploadUrl:"test/uploadFile.action",
fileMask:[
["All Images",
"*.*.*.*.png"]
deferredUploading:false,
degradable:true,
&&&&&&&&&&&&&&& uploadOnChange:false,
&&&&&&&&&&&&&&& selectMultipleFiles:true,
&&&&&&&&&&&&&&& devMode:true,
&&&&&&&&&&&&&&& isDebug:false,
&&&&&&&&&&&&&&& showProgress:false
if(dojo.byId("btnF")){
var f = new dojox.form.FileUploader(props, "btnF");
dojo.connect(dijit.byId("fSubmit"), "onClick", function(){
alert('click');
var param = {author:dojo.byId('author').value};
f.upload(param);
dojo.connect(f, "onChange", function(dataArray){
alert("onChange");
&&&&&&&&&&&&&&&&&&&& dojo.forEach(dataArray, function(d){
&&&&&&&&&&&&&&&&&&&&&&&& alert(d);
&&&&&&&&&&&&&&&&&&&
addTr(d);
&&&&&&&&&&&&&&&&&&&& });
dojo.connect(f, "onComplete", function(dataArray){
alert("onComplete:" + dataArray);
dojo.forEach(dataArray, function(d){
function addTr(objFile){
alert("add");
var table = document.getElementById("tableBody");&&
var tr = document.createElement('tr');&&
table.appendChild(tr);&&
var td1 = document.createElement('td');&&
tr.appendChild(td1);&&
td1.innerHTML = objFile.
var td2 = document.createElement('td');&&
tr.appendChild(td2);&
if(objFile.size){
td2.innerHTML = Math.ceil(objFile.size*.001)+"KB";
td2.innerHTML = "&";
var td3 = document.createElement('td');&&
tr.appendChild(td3);&&
var delHref = "&a href='javascript:void(0);' onclick=\"delTR(this);\"&删除&/a&";&&
td3.innerHTML = delH
function delTR(obj){
alert("del");
var table = document.getElementById("tableBody");&&
var selectedTr = obj.parentElement.parentE&&
table.removeChild(obj.parentElement.parentElement);&
&&& &/script&
&/head&
&body class="tundra"&
&table class="tbl"&
&form id="formF" class="form"&&label&作者:&/label& &input
class="field" type="text" value="" id="author" name='author' /&&br /&
&div tabIndex="5" id="btnF" class="btn"&浏览&/div&
&button tabIndex="6" id="fSubmit" class="btn"
dojoType="dijit.form.Button"&提交&/button&
&/tr&
&/table&
&p&上传文件列表&/p&
&table border="1" bordercolor='#000000' align="center"
style="border-collapse: width: 500px"&
&th&文件名&/th&
&th&大小&/th&
&th&操作&/th&
&tbody id="tableBody"&
&/tbody&
&/table&
&/body&
&/html&
浏览: 412703 次
来自: 北京
你好,请问html = nvl(html); 这句中的nvl( ...DOJO动态生成树删除子节点后不刷新问题! - ITeye问答
在a.JSP文件中有一个下拉框和一个DOJO树,其中DOJO树的内容(JSONObject)要根据下拉框的数据决定(就是把下拉框的选项值赋值给dojo tree的objectId)
&select name="groupCode"onChange="return switchCode(this.options[this.selectedIndex].value);"&
&option value=""&--Select--&/option&
&option value="_APP"&_APP&/option&
&option value="_APPSDF"&_APPSDF&/option&
&option value="app1"&app1&/option&
&dojo:TreeSelector widgetId="selector" eventNames="select:nodeSelected"&&/dojo:TreeSelector&
&div dojoType="TreeSelector" widgetId="selector"&&/div&
&div id="treeDialog" class="popupContainer"&
dojoType="TreeRPCController" RPCUrl="doExpandNode.do?mode=doExpand" widgetId="asiTreeController" DNDController="create"&&/div&
&div dojoType="Tree" selector="selector" toggler="fade" widgetId="asiTree" controller="asiTreeController" expandLevel="3"&
&div dojoType='TreeNode' widgetId='ATreeRoot' title='xxx'
isFolder='true' objectId='///' &&/div&
下拉框对应的JS如下:
function switchCode(slkValue)
//Assign drop-down value to objectId of dojo Tree
var slkObj=dojo.widget.byId('ATreeRoot')
if(slkObj)
slkObj.objectId=slkV
//Remove all tree child node when switch drop-down options
var sCont=dojo.widget.byId('asiTree');
removetreeNode((sCont.children)[0]);
function removetreeNode(treeNode) {
var children=treeNode.
while(children.length&0){
treeNode.removeChild(children[0]);
treeNode.collapse();
现在,当切换下拉框时我可以删除掉树子节点,但是,当我再次点击根节点的“+”符号时,它不执行RPCUrl中所对应的URL,也就是它不重新去生成树,而下拉了一个我移去了子节点的空树。这是为啥?怎样才能让它刷新树的内容?
目前还没有答案
已解决问题
未解决问题developerWorks 社区
随着 Ajax 应用的飞速发展,浏览器端 JavaScript 代码应用的规模和复杂度和传统 Web 应用相比已不可同日而语。各种功能强大的小部件窗口 (widget),各种眩目的特效,在浏览器端都需要消耗越来越多的内存资源。而如何正确的创建和释放这些资源,保证用户在长时间的使用过程中不会因内存泄漏导致浏览器应用的性能、体验降低,也日渐凸现重要。
, 高级软件工程师, IBM
胡旷,现在 IBM 中国软件开发中心工作,目前从事 IBM Connections 的开发。主要技术研究方向包括 Web2.0 应用,社交软件,人机交互。在移动计算,人机交互,节能技术,智能应用等方面拥有多项专利。
, 高级软件工程师,
刘万荣任职于 IBM 中国软件开发中心 Lotus 产品部门,目前从事 IBM Connections 的开发。他感兴趣的技术领域包括:Web 2.0、Web Services、Java 和其他基于 JVM 语言的企业级应用。
, 高级软件工程师,
李春玲,现在 IBM 中国软件开发实验室 Lotus 开发中心工作,目前从事 IBM Connections 的开发。
对于浏览器端,尤其是 Internet Explorer 的内存泄漏问题及解决方法,已经有很深入和广泛的讨论。而本文将更多的讲解作为一个 Dojo 开发人员,如何正确使用 Dojo 的相关技术,遵循 Dojo 的编程模式来避免浏览器的内存泄露问题。Ajax 应用新的挑战Ajax 技术已经被广泛的应用,其给 Web 用户带来全新的使用体验同时,也给 Web 开发人员带来了各种各样新的挑战。Ajax 应用中浏览器端内存泄露问题便是其中之一。作为一名 Web 前端开发人员,如果某天系统测试人员给您开了一个名为“浏览器端内存泄露问题”的 Bug, 千万别感到意外,因为您正处在 web2.0 时代。Internet Explorer 和 Mozilla Firefox 是使用人数最多的两个网页浏览器,因而我们主要讨论 JavaScript 在这两个浏览器中的内存泄露问题。在这两个浏览器中,用来管理 DOM 对象的组件对象模型(component object model)是导致 JavaScript 内存泄露的罪魁祸首。不管是原生的 Windows COM,还是 Mozilla 的 XPCOM 都使用引用计数(reference-counting)垃圾回收机制来分配和回收内存。然而用来管理 DOM 对象内存的引用计数机制并不总是和应用于 JavaScript 的标志和清除(mark-and-sweep)垃圾回收机制相兼容。问题便由此而来。关于 JavaScript 内存泄露模式以及如何避免内存泄露,已经有很多经典参考资料(参见本文后面的参考资源)。但是由于 Dojo 工具集对于 JavaScript 所做的封装,使得这些资料对于 Dojo 开发人员,却并不很实用。而本文将关注于如何正确使用 Dojo 的相关技术,遵循 Dojo 的编程模式来避免浏览器的内存泄露问题,主要涉及到:
如何正确使用 Dojo 事件机制来避免内存泄露
如何正确使用 Dojo API 来销毁 DOM 节点
如何正确析构 Dojo 小部件(Widget)来避免内存泄露
如何正确使用 dojo.create API 来避免内存泄露
如何更好地设计 UI 代码来避免内存泄露文中将辅以我们在软件开发中遇到的真实案例,来讲解如何使用这些编程模式来避免内存泄露问题。在阅读下面章节前,请务必先阅读参考资料中提到的一文。Dojo 事件机制与避免内存泄漏在 JavaScript 编程中,我们经常会用一个 JavaScript 函数来响应并处理某个 DOM 节点的特定事件。而这恰恰也是最容易引入循环引用(circular references)而最终导致内存泄露的地方。在 Dojo 中,其实我们只要按照一定的编程模式,便能很好地避免循环引用带来的问题。Dojo 事件机制提供的 dojo.connect API 能够让我们方便地把一个 JavaScript 函数关联上某个 DOM 节点事件。Dojo 事件机制对这一操作过程的包装,让我们能够非常容易地处理这种关联所带来的循环引用。清单 1. 使用 dojo.connect API // 关联一个 JavaScript 函数与一个 DOM 节点事件
var myConnection = dojo.connect(domNode, "onclick", scope, "onClickHandler");在清单 1 中通过使用 dojo.connect API ,我们用 onClickHandler 函数来响应并处理 domNode 节点抛出的 onclick 事件。在 dojo.connect 执行完之后,它将返回一个值,代表刚关联的 JavaScript 函数与 DOM 节点事件之间的联系,我们称之为“连接”(connection)。而该“连接”正是消除循环引用的关键!方法很简单,当该“连接”不需要的时候,比如被关联的 DOM 节点被销毁的时候,通过使用 dojo.disconnect API 来断开该“连接”。这样,被关联的 JavaScript 对象与 DOM 节点之间的循环引用就被断开了。也就避免一个潜在的内存泄露问题。dojo.disconnect API 使用方法见清单 2。清单 2. 使用 dojo.disconnect API // 在必要的时候断开“连接”
dojo.disconnect(myConnection);在开发 Dojo 小部件的时候,我们也需要消除 DOM 节点与 JavaScript 函数关联带来的循环引用问题,只是方法稍有不同。在小部件开发中,可以使用小部件基类 dijit._Widget 提供的 connect 方法来关联 JavaScript 方法和 DOM 节点事件。相比使用 dojo.connect, 使用基类 dijit._Widget 提供的 connect 方法会让我们的代码更简洁。我们并不需要关心用 connect 之后生成的“连接”(connections)以及何时断开它们。基类 dijit._Widget 提供的 connect 方法会把生成的“连接”自动存储起来。当小部件被销毁时,这些存储的“连接”也会连同一起被自动销毁(参考“Dojo 小部件析构与避免内存泄漏”小节图 1 中小部件销毁过程中的 disconnect 阶段)。很明显,这样的使用方式,让我们的代码显得更加简洁与容易维护。清单 3.使用 dijit._Widget 基类的 connect 方法 // 在小部件开发中关联 JavaScript 函数与 DOM 事件
this.connect(domNode, "onclick", "onClickHandler");熟悉 Dojo 小部件开发的读者可能会想到小部件开发中另外一种通过模板技术关联 JavaScript 函数与 DOM 节点事件的方式,使用小部件模板中的 dojoAttachEvent 属性。那么,使用该技术的话,我们是否需要手工处理“连接”呢?和使用 dijit._Widget 基类的 connect 方法一样,答案是不需要!对于在小部件模板中使用 dojoAttachEvent 属性的方式,Dojo 也会帮我们自动处理产生的“连接”,不需要我们再写任何额外的代码。清单 4. 使用小部件模板技术中的 dojoAttachEvent 属性 // 小部件模板文件片段
&div class="close" dojoAttachEvent="onclick:closeHelpBox"&X
// 小部件 JavaScript 定义文件片段
closeHelpBox: function(event)
this.destroy();
…对于非小部件开发的情况,我们必须使用 dojo.connect API,并手动地使用 dojo.disconnect API 处理“连接”。一种比较好的模式是定义一个帮助方法用来注册特定上下文内生成的所有“连接”,当该上下文结束时一并切断注册的所有“连接”。参考清单 5 中代码。清单 5. 非小部件开发情况,使用 dojo.connect API 的编程模式 // 定义帮助方法
connectionHelper = {
scopes:{},
connect : function(/*string*/ scope,
/*Object|null*/ obj,
/*String*/ event,
/*Object|null*/ context,
/*String|Function*/ method){
var conn = dojo.connect(obj, event, context, method);
if(!this.scopes[scope]){
this.scopes[scope] = [];
this.scopes[scope].push(conn);
clear: function(/*string*/ scope){
if(this.scopes[scope]){
dojo.forEach(this.scopes[scope], dojo.disconnect)
}Dojo.destroy , dojo.empty 与 DOM 销毁当 DOM 节点不需要时,明确地销毁它也是一个很好的习惯。这会减少内存的占用,提升程序的性能。我们可以使用 Dojo 提供的 dojo.destroy API 和 dojo.empty API。这两个 API 的差别在于 dojo.destroy 会销毁包括参数指定的 DOM 节点本身及所有子节点,而 dojo.empty 只会销毁子节点。Dojo 小部件 (Widget) 析构与避免内存泄漏所有的内存泄露问题都是由于程序中已不使用,却未能释放的资源引起。在 Dojo 中,Dojo 小部件可以被认为聚合了多种资源,例如 DOM 对象,JavaScript 对象,事件连接(使用 dojo.connect 生成的 connections)等。所以在使用 Dojo 小部件时,要避免内存泄露,首先需要掌握的便是在正确的时候,使用正确的方法销毁 Dojo 小部件。当发生页面跳转或页面部分内容刷新时,其中的小部件就不再需要了。此时,我们需要调用 Dojo 小部件基类 dijit._Widget 的 destroyRecursive API 来销毁小部件。图 1 列举出了 Dojo 小部件销毁过程中的几个主要阶段:
destroyRecursive:小部件销毁过程入口
destroyeDscendants:销毁小部件中嵌套的子小部件
destroy:释放小部件本身的资源
uninitialize:扩展点,用以释放自定义的资源
disconnect:切断小部件中生成的“连接”(connections)
destroyRendering:销毁小部件中的 DOM 节点当 destroyRecursive 被调用时 , 图 1 中的各阶段按照从左至右深度遍历的顺序依次执行。这里需要注意的是,在销毁小部件时,开发人员需要调用的只是 destroyRecursive API,而非 destroy API。DestroyRecursive API 会在调用 destroy API 之前先调用 destroyeDscendants API 销毁嵌套的子孙小部件。另外,开发人员可以通过覆写 uninitialize API ,在小部件销毁过程中来释放自己定义的一些资源。图 1.Dojo 小部件销毁过程清单 6.使用 dijit._Widget 的 destroyRecursive API 销毁小部件 var myWidget = dijit.byId("widgetId");
if (myWidget && myWidget.destroyRecursive)
// 销毁 myWidget 小部件
myWidget.destroyRecursive();从以上小部件销毁过程我们可以看出对于嵌套的小部件,我们只需要确保最顶层的小部件的 destroyRecursive API 被调用就可以了。其销毁过程会保证嵌套的子孙小部件也能被正确地销毁。然而,某些使用 Dojo 小部件的应用场景我们需要特别注意。我们知道大多数 Dojo 小部件在使用时需要明确指定一个 DOM 节点,用于挂载该小部件。但是某些 Dojo 小部件的使用却并不需要明确指定要依附的 DOM 节点,比如 dijit Menu, dijit Dialog 等。以 dijit.Menu 小部件为例,在使用编程的方式来创建 dijit.Menu 小部件时,通常并不需要指定一个 DOM 节点作为附着点。默认情况,该小部件将依附于 body 标签的最底部。如果这种情况下您忘记了销毁它,内存泄露便悄然发生了。图 2 所示是我们在开发中曾碰到的一个真实案例,红色框中的下拉菜单是通过编程的方式使用 dijit.Menu 小部件生成。从视图上看,它依附于一个下拉菜单按钮上,但我们并没有给它指定一个依附的 DOM 节点。当这个视图需要销毁时,我们只明确销毁了按钮小部件,却忘记了销毁菜单小部件。最后导致每次视图切换都会带来 2M 的内存泄露。图 3 是我们使用 sIEve 工具检测该视图切换时生成的浏览器内存使用情况图,右侧陡升的曲线便说明了问题的严重性。图 2.dijit.Menu 小部件引起的内存泄露图 3.dijit.Menu 小部件内存泄露导致的内存使用曲线为了解决这个问题,一般有两种方式:在生成该类小部件时,明确的把该小部件依附于另一个小部件的 DOM 节点上,这样当上层的小部件被销毁时,按照 Dojo 小部件销毁流程,底部的子小部件也会被依次销毁;另外一种方式便是在生成该小部件时记住该小部件的 id, 在需要销毁该小部件时,明确地调用 destroyRecursive API 来销毁该小部件。Dojo.create 与避免 DOM 插入顺序内存泄漏IE 中有一类典型的内存泄漏模式称之为 DOM 插入顺序内存泄漏。当创建动态的 DOM 节点时,我们必须确保上层元素首先被附着,然后是底层的。如果把顺序反过来,便有可能导致内存泄露。很多人可能都习惯先创建一个很大的 DOM 树,然后再把它附着到一个父节点上。而这在 IE 上却会带来问题。我们需要改变创建 DOM 树的方式。Dojo 中的 dojo.create API 提供了动态创建 DOM 节点的功能,正确的使用该 API 能帮助我们避免 DOM 插入顺序内存泄露问题。该 API 很简单,它提供了一个参数用来指定创建的 DOM 节点要附着的父节点。所以,只要在使用 dojo.create API 时,我们始终都指定该参数,我们便能避免 IE 中的 DOM 插入顺序内存泄露问题。清单 7. 使用 dojo.create API 创建 DOM 节点 // btnNode 节点在创建时被附着在 this.containerNode 节点上
var btnNode = dojo.create("span", null, this.containerNode);可能碰到的问题当要创建的 DOM 树很大时,这种从上而下的创建 DOM 节点的方式可能会造成浏览器视图的闪烁。一个好的办法是在 DOM 树渲染期间通过样式”display:none”把最顶层父节点隐藏起来,直到整个 DOM 树都创建好之后,再把顶层父节点展现出来。参考清单 8 中的代码。清单 8. 避免 DOM 节点创建过程中的闪屏问题 var frameNode = dojo.create(“div”,{
"style“: {
display: "none"
},dojo.body());
// 创建 frameNode 节点下的子节点树
// 当子节点树创建好之后,显示整个 frameNode 节点树
dojo.attr(frameNode, "style", {
display: "block"
});UI 代码设计与避免内存泄露内存泄露问题似乎多半在代码后期才会得到关注,其实有时候内存泄露与 UI 代码的前期设计紧密相连。越是在代码开发早期考虑内存泄露的问题,越是能帮我们设计出更好的 UI 代码结构。我们有个真实的案例是需要实现一个定制的 table 小部件。该 table 小部件由 table header 和 table cells 组成(如图 4 所示)。当刷新表格数据时,组成表格单元的 DOM 节点以及关联这些 DOM 节点与事件处理函数的“连接”都需要被及时销毁。在我们的早期设计中,我们把 table header 和 table cells 一起设计成一个整体的小部件。但是之后我们发现在表格数据刷新时,这样的设计处理起来并不是很方便。我们无法像前面推荐的编程模式那样方便地使用 dijit._Widget 中的 connect 方法来管理“连接”,而不得不添加额外的代码来手工地处理“连接”。这种情况下该怎么办呢?经过研究,我们发现其实更好的设计应该是把 table cells 与 table header 划分成两个不同的子小部件,而这两个子小部件组成了 table 小部件(如图 5 所示)。这样,在表格被刷新时,“连接”的处理就能由 table cells 子小部件自己来决定了。我们也就不再需要额外的代码。很明显,后一种设计更加的简洁、优雅!图 4.table 小部件原始设计方案图 5.table 小部件改进的设计方案由此可见,越是能在开发早期把浏览器端的内存泄露问题考虑进来,越是能节省我们后期为提高我们的 AJAX 应用性能所需要的努力。小结本文简要介绍了造成浏览器内存泄露的本质原因。并详细介绍了在使用 Dojo 开发 AJAX 应用时避免浏览器内存泄露的编程模式。首先介绍了 Dojo 中的事件机制以及如何使用它来避免循环引用带来的问题,介绍了如何使用 Dojo 提供的 API 来销毁 DOM 节点。之后着重介绍了 Dojo 小部件的析构机制以及如何正确使用其 API 来避免内存泄漏。还介绍了 DOM 插入顺序内存泄漏模式,以及避免该类内存泄漏模式的最佳实践。最后探讨了小部件设计与内存泄漏的关系,并结合项目中的具体实例来讲解什么样的设计是最好的,以及其如何来避免内存泄漏。
参考 相关文档,了解更多 Dojo 的内容。
Dojo.connect 官方文档 , 。
Dijit._Widget 官方文档 , 。
Memory leak patterns in JavaScript, , developerWorks 上介绍 JavaScript 内存泄露模式的经典之作。
Understanding and Solving Internet Explorer Leak Patterns, , 详细介绍了 IE 中内存泄露的模式。
:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。:这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。,这是有关 Web 2.0 相关信息的一站式中心,包括大量 Web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过
栏目,迅速了解 Web 2.0 的相关概念。查看 ,了解更多和 HTML5 相关的知识和动向。加入 。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
免费下载、试用软件产品,构建应用并提升技能。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Web developmentArticleID=818529ArticleTitle=Dojo 最佳实践 - 如何防止浏览器内存泄漏
publish-date=

我要回帖

更多关于 jq动态创建div 的文章

 

随机推荐