一起来将变量存储到DOM节点里
时间:2010-06-04
来源:互联网
记得某大大曾今形容全局变量是魔鬼,全局变量的缺点显而易见。避免使用全局变量的方法之一是将变量写进对象里,其实说白了,就是给变量附加一个命名空间,这样做绝大多数情况下都能工作的很好。很多时候我们还希望这个变量能保留值,比如记录该对象的方法总共被调用了多少次(当然这貌似没什么意义
),通过字面量方式定义对象,这个问题就不是问题了:定义一个方法,每次调用对象方法累加该变量即可。但是如果你的对象需要通过构造器模式(new)调用可能就会有问题,new出来的对象是对象原型的实例,new n次就是n个副本,累加函数就没意义了。这时候定义一个全局看起来很有必要,但是本人超级不喜欢全局变量,前段时间做的一个程序中的动画函数遇到了上述类似的问题,最初版本是用了全局变量,最近拿出来看,发现这个全局变量特别碍眼,所以琢磨出来一个偏方,程序现在运行的很漂亮,丑陋的全局也剔除了,但是说了是偏方,对这个方法还是没什么把握,拿出来和各位探讨:
下面是这个独立出来的动画函数:
不过将一个对象存储到节点上这样操作看起来有些奇怪,我的分析是,DOM节点本身其实也是对象(使用typeof获取一个节点的值,为object),所以自然可以有他的属性,我们甚至可以为他定义方法,如下:
[ 本帖最后由 kevinx 于 2010-6-4 17:56 编辑 ]

下面是这个独立出来的动画函数:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <style type="text/css"> * { padding:0; margin:0; } img { display:block; float:left } #outer { width:610px; overflow:hidden } #inner { width:1850px; } </style> </head> <body> <div id="ddd"></div> <div id="bb" style="background:gray; border:solid 0px blue"></div> <div style="background:gray; width:500px; height:10px; border:solid 0px black" id="test"></div> <script type="text/javascript"> function $$(ele){ if(typeof ele == 'string') return document.getElementById(ele); else return ele; } function getCssStyle(ele,attr){ var value = null; if($$(ele).currentStyle){ value = $$(ele).currentStyle[attr]; } else if(window.getComputedStyle){ value = window.getComputedStyle($$(ele),null)[attr]; } return value; } var css = { get:function(ele,attr){ var value = null; if($$(ele).style) value = $$(ele).style[attr]; if(!value) value = getCssStyle(ele,attr); if(!value||value == 'auto'){ if(attr == 'height') value = $$(ele).offsetHeight; else if(attr == 'width') value = $$(ele).offsetWidth; else if(attr == 'left') value = $$(ele).offsetLeft; else if(attr == 'top') value = $$(ele).offsetTop; } if(!value) value = 0 + 'target:'+$$(ele).tagName+'<br />attribute:'+attr+'<br />no available value!'; return value; }, set:function(ele,attrObj){ if(typeof attrObj == 'string') $$(ele).className = attrObj; else{ for(var one in attrObj){ if(!attrObj[one]) continue; if(one == 'opacity'){ var a = parseFloat(attrObj[one]); var value = a>1?a/100:a; if($$(ele).filters) $$(ele).style.filter = 'alpha(opacity='+ attrObj[one]*100 +')'; else $$(ele).style.opacity = attrObj[one]; continue; } $$(ele).style[one] = attrObj[one]; } } } }; var T = 5; function counter(){ $$('ddd').innerHTML = T++; } var animate = function(obj,attr,addition){ if(!window.TAS) window.TAS = {}; return new anit(obj,attr,addition); } function anit(obj,attr,addition){ var THIS = this, add = addition?addition:{}; for(var one in attr){ ( function(one){ if($$(obj)['anit'+one]){ clearInterval($$(obj)['anit'+one]); $$(obj)[one+'even_step'] = $$(obj)[one+'even_value'] = null; } $$(obj)['anit'+one] = setInterval( function(){ counter(); var ae = add.effect?add.effect:null, t = add.times?add.times:null, ck = add.callback?add.callback:null; switch(ae){ case 'even': THIS.even(obj,one,attr[one],t,ck); break; case 'speedDown': THIS.speedDown(obj,one,attr[one],ck); break; default: THIS.speedDown(obj,one,attr[one],ck); } },20); } )(one); } } anit.prototype = { speedDown:function(obj,attr,value,callback){ var o = parseFloat(css.get(obj,attr)), a = parseFloat(value); var step = (a - o)/10; if(step > -1 && step < 0) step = -1; if(o != a) $$(obj).style[attr] = o + Math.ceil(step) + 'px'; else{ clearInterval($$(obj)['anit'+attr]); $$(obj)['anit'+attr] = null; } }, even:function(obj,attr,value,t,callback){ var o = parseFloat(css.get(obj,attr)), a = parseFloat(value); if(!$$(obj)[attr+'even_step']){ var t = t?parseInt(t):20; $$(obj)[attr+'even_step'] = (a - o)/t; } if(!$$(obj)[attr+'even_value']){ $$(obj)[attr+'even_value'] = o; } if($$(obj)[attr+'even_value'] > a && o > a) $$(obj).style[attr] = o + $$(obj)[attr+'even_step'] + 'px'; else if($$(obj)[attr+'even_value'] <= a && o < a) $$(obj).style[attr] = o + $$(obj)[attr+'even_step'] + 'px'; else{ clearInterval($$(obj)['anit'+attr]); $$(obj).style[attr] = a + 'px'; $$(obj)['anit'+attr] = null; $$(obj)[attr+'even_step'] = $$(obj)[attr+'even_value'] = null; } }, speedUp:function(){ } } animate($$('test'),{ 'width':'323px', 'height':'500px' }); animate($$('bb'),{ 'width':'323px', 'height':'500px' },{ 'callback':function(){} }); setTimeout( function(){ animate($$('bb'),{ 'width':'533px', 'height':'100px', 'marginLeft':'300px', 'borderWidth':'50px' },{ 'callback':function(){} }); },500); </script> </body> </html>
提示:您可以先修改部分代码再运行
例子主要看animate,该函数允许你任何时间通过多次调用来操作同一个对象的同一个或者多个属性,处理方式为:如果上次对该属性的动画未完成则终止,执行本次操作(类似于jquery调用了animate然后调用stop方法)。为了实现这个功能就需要记录上一次动画的处理过程(即setInterval的引用),同时可以看到animate调用的时候其实接收了anit对象new的一个实例,也就遇到了开头我描述的问题,最先使用了全局变量,后来考虑将animate写成一个字面量形式的对象,然后将该全局变量写成该animate对象的一个属性,这样貌似可以解决全局变量的问题(其实这样做在实际操作时还有一个问题即如何记录每次setInterval的引用使得该引用唯一而且不会与其他次数的操作发生冲突),后来想到将该引用存储到本次操作的DOM节点本身上,这样一来只要节点存在该存储的值就存在,且很容易确保其唯一性,问题解决。提示:您可以先修改部分代码再运行
不过将一个对象存储到节点上这样操作看起来有些奇怪,我的分析是,DOM节点本身其实也是对象(使用typeof获取一个节点的值,为object),所以自然可以有他的属性,我们甚至可以为他定义方法,如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>Untitled Document</title> </head> <body> <div id="test">hello world</div> <script type="text/javascript"> document.getElementById('test').a = function(){ alert('yikes!'); }; document.getElementById('test').a(); </script> </body> </html>
提示:您可以先修改部分代码再运行
再考虑节点本身拥有的标准属性(如width、height等)这些属性同样可以通过我们操作一般js定义对象属性的方法来获取值(想想为什么叫它html的属性?这不正是对象里的叫法吗!(非标准解释:D)),而节点常用的style属性其类型同样为object,如下例子:提示:您可以先修改部分代码再运行
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>Untitled Document</title> </head> <body> <img width="100" id="image" /> <div style="width:100px" id="div"></div> <script type="text/javascript"> var a = document.getElementById('image')['width']; var b = document.getElementById('image').width; alert('yo:D 我是通过["sbscript"]下标形式获取的width: ' + a); alert('而我是通过点表达式获取的width: ' + b); var c = document.getElementById('div').style; alert('我是div的style属性,我的类型是: ' + typeof c); </script> </body> </html>
提示:您可以先修改部分代码再运行
这样分析貌似合情合理,没有问题,而且测试也没有任何浏览器兼容问题,甚至恶心的ie6也表现的很好,但是一想到为html节点添加不存在的标准属性很多人可能和我一样想到当初的lightbox,lightbox当初的做法是为在html节点上手动添加不存在的属性用于标示哪些图片用于幻灯,而这个做法现在在标准浏览器下已经不可用(ie很宽容),如下:提示:您可以先修改部分代码再运行
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>Untitled Document</title> </head> <body> <div id="a" temattr='biteme'>.</div> <script type="text/javascript"> var a = document.getElementById('a').temattr; alert(a); </script> </body> </html>
提示:您可以先修改部分代码再运行
上面两种方式区别在于,一个是通过js添加,另一个是直接在html结构中添加,我觉得,因为页面在加载时候浏览器会生成一个dom,所以js添加的方式其实是对该dom的操作,所以是可行的,而html中硬添加的方式则是通过html的语法,这能解释为什么在标准浏览器中不可行,另一个可以解释该问题的现象:在ie下尝试直接在html中定义一个非字符串类型的属性是不可行的,如下:提示:您可以先修改部分代码再运行
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>Untitled Document</title> </head> <body> <div id="a" temattr=new Object()>.</div> <script type="text/javascript"> var a = document.getElementById('a').temattr; alert(a); </script> </body> </html>
提示:您可以先修改部分代码再运行
当然目前有些达达嚷嚷html现今的定义已经落伍,即html不只应该作为文档结构来使用,而是应该作为应用程序的基础,html5貌似就是这样一个转型,然而目前html5依然不支持直接在html添加非标准属性的方法:提示:您可以先修改部分代码再运行
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>Untitled Document</title> </head> <body> <div id="a" temattr='biteme'></div> <script type="text/javascript"> var a = document.getElementById('a').temattr; alert(a); </script> </body> </html>
提示:您可以先修改部分代码再运行
这样分析下来貌似通过节点存储变量的方法很不错,个人感觉可能的问题在于这样做使得程序和html结构又从某种意义上被掺和在一起了,同时这些变量没有在程序程序中声明,看起来有些不可控制,提示:您可以先修改部分代码再运行
[ 本帖最后由 kevinx 于 2010-6-4 17:56 编辑 ]
作者: kevinx 发布时间: 2010-06-04
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28