许愿墙模块功能分析 一,热点技术 1,实现可拖放DOM技术移动许愿字条可拖放DOM模式(Draggable DOM pattern)的宗旨在于允许浏览者自己定义页面中各元素的位置,并且,只需要用鼠标选中要移动的部分,把它拖到新的位置上,就可以定制页面。
DOM是Document Object Model文档对象模型的缩写,是一种与浏览器、平台、语言无关的接口,使用户可以访问页面其他的标准组件。DOM是以层次结构组织的节点或信息片段的集合。这个层次结构允许开发人员在树中导航寻找特定信息。分析该结构通常需要加载整个文档的构造层次结构,然后才能做任何工作。由于它基于信息层次,因此DOM被认为基于树或基于对象。
具体实现时以下时间会被触发: (1)moveStart (2)Move (3)moveEnd 当按下鼠标左键,开始移动鼠标时,在被拖动的许愿条上就会触发moveStart事件。用户可以使用moveStart事件处理函数在拖动开始时允许javaScript代码。当moveStart事件被触发后,Move时间会一直触发,只要对象还在被拖动,就一直触发。当拖动停止时,则触发moveEnd事件。
echo输出许愿条样式布局,代码如下:
echo "
爱墙编号:".$id." ".$sendtime." ×
".$Picker." $content
".$author."
";
当按下鼠标左键时,应用鼠标时间onmousedown触发Move()函数
var Layer=''; document.onmouseup=moveEnd; document.onmousemove=moveStart; var b; var c; function Move(Object,event){ //移动DIV许愿字条 Layer=Object.id; if(document.all){ document.getElementById(Layer).setCapture(); b=event.x-document.getElementById(Layer).style.pixelLeft; //设置左边框 c=event.y-document.getElementById(Layer).style.pixelTop; //设置右边框 }else if(window.captureEvents){ window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP); b=event.layerX; //返回时间对象相对于本体的横坐标 c=event.layerY; //返回时间对象相对于本体的纵坐标 } /**实现鼠标单击字条时,字条置上**/ document.getElementById(Layer).style.zIndex=iLayerMaxNum; iLayerMaxNum=iLayerMaxNum+1; /********************************/ }
document.all是文档中所有标签组成的一个数组变量,包括了文档对象中的所有元素,这个数组可以访问文档中的所有元素。
语法: document.all[i] document.all[name] document.all.tags[tagname] 说明: all[]是一个多功能的类似数组的对象,它提供了对文档中所有HTML元素的访问。all[]数组源自于IE4并已经被很多其他浏览器采用
all[]已经被Document接口的标准的getElementById()方法和getElementByTagName()方法以及Document对象的getElementByName()方法所取代。
all[]包含的元素保存了最初的顺序,如果你知道他们在数组中的确切数字化位置,可以直接从数组中提取他们。然而,更为常见的是使用all[]数组,根据他们的HTML属性name或id来访问元素。如果元素拥有指定的name,将得到共享同一名称的元素的一个数组。
document.all可以判断浏览器是否是IE
if(document.all){ alert("is IE!"); }
window.captureEvents()
window.captureEvents(event1 | event2 | eventN)
captureEvents()方法捕获所有发生的事件类型,如果有多个事件发生,则用|竖线隔开;captureEvents()方法主要事件如下:
Event.ABORT
Event.BLUR
Event.CHANGE
Event.CLICK
Event.DBLCLICK
Event.DRAGDROP
Event.ERROR
Event.FOCUS
Event.KEYDOWN
Event.KEYPRESS
Event.KEYUP
Event.LOAD
Event.MOUSEDOWN
Event.MOUSEMOVE
Event.MOUSEOUT
Event.MOUSEOVER
Event.MOUSEUP
Event.MOVE
Event.RESET
Event.RESIZE
Event.SELECT
Event.SUBMIT
Event.UNLOAD
示例代码:
Using window.captureEvents
当鼠标移动时,触发moveStart()函数,代码如下:
function moveStart(d){ if(Layer!=''){ //如果图层不为空 if(document.all){ document.getElementById(Layer).style.left=event.x-b; //设置左边距 document.getElementById(Layer).style.top=event.y-c; //设置右边距 }else if(window.captureEvents){ document.getElementById(Layer).style.left=(d.clientX-b)+"px"; document.getElementById(Layer).style.top=(d.clientY-c)+"px"; } } }
应用DOM方法(document对象的getElementById方法)获取包含许愿字条layer层左边距和上边距的距离。b和c分别表示获取Layer层的横纵坐标。
clientX: 检索与窗口客户区域有关的鼠标坐标的x坐标,属性为只读,没有默认值。
clientY: 检索与窗口客户区域有关的鼠标光标的y坐标,属性为只读,没有默认值。
clientX,pageX,offsetX,x,layerX,screenX,offsetLeft 各浏览器通用属性: screenX: 鼠标在显示屏幕上的坐标。
clientX: 鼠标在页面显示区域的坐标。
特有属性:(注:IE和FF的定位有个1px的差别,实际上,IE的定位从0开始,FF的定位从1开始,FF永远会比IE大1px,需要根据实际情况处理。)
pageX:FF特有,鼠标在页面上的位置,从页面左上角开始定位,这个可以很方便在整个页面上进行定位,IE没有直接替换的属性。
layerX: FF特有,鼠标相对于“触发事件的元素的层级关系中离该元素最近的,设置了position的父元素”的边界的位置,从border的左上角开始定位,即如果这个父元素存在border,则坐标原点在border的左上角,而不是内容区域的左上角。
offsetX:IE特有,鼠标相对于“触发事件的元素”的位置,从内容区域左上角开始定位,不是从border左上角开始!这个属性比较好用,用来判断鼠标点在一个元素中的哪个位置很方便,FF没有直接替换的属性。
x:IE特有,跟layerX一个效果,可作为layerX的直接替换属性。
offsetLeft: 这个属性不是事件对象的属性,而是DOM对象所有的,该属性表示的是DOM对象在“该DOM对象的层级关系中离该对象最近的,设置了position的父对象”中的位置,虽然话是这么说的,但是不同的浏览器效果不一样,FF中严格按上述说明执行,但是在IE6/7中,这个属性返回该DOM对象在其直接父对象中的位置,但是IE8改正了这个问题,不过IE8又有了一个新问题,其他的浏览器都是从父对象的内容区域的左上角开始定位,IE8确是从父元素的border的左上角开始定位,由于测试环境为IETester中的IE8,不能排除是IETester的问题。
当鼠标抬起时,触发moveEnd()函数,代码如下:
function moveEnd(d){ if(Layer!=''){ //如果layer图层不为空 if(document.all){ document.getElementById(Layer).releaseCapture(); Layer=''; //将layer图层设为空 }else if(window.captureEvents){ window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP); Layer=''; //将layer图层设为空 } } }
在上面的代码中,setCapture()函数的作用是将后续的mouse事件都发送给这个对象,releaseCapture()函数是将mouse事件返回,由document、window等对象来自行处理,这样就保证了在拖动的过程中,不会由于经过了其他元素而受到干扰。另外,还有一个很重要的因素,在win32上,MOUSEMOVE的时间不是连续的,并不是每次移动一个像素的鼠标指针,就会发生一个MOUSEMOVE事件,Windows会周期性检测鼠标指针的位置变化来产生MOUSEMOVE的事件。所以,如果是一个很小的页面对象,例如一个直径5像素的圆点,如果没有setCapture和releaseCapture,那么在按住鼠标之后,快速地移动鼠标,就有可能鼠标移动走了但小圆点还在原地,就是因为下一次的mousemove事件已经不再发给这个圆点对象了。
2,对QQ号文本框中禁止非数字字符输入 在动态网站中,为了确保用户输入的文本或数值的有效性,必须对用户输入的数据加以验证,确保数据的准确及安全性。本模块禁止用户向QQ文本框中输入汉字或英文字符。
onKeyUp="setQQ();if(/(^0+)/.test(value))value=value.replace(/^0*/, '')" onKeyDown="setQQ();" //键盘按下时触发,比如按着1不放时,该函数生效 onKeyPress="return event.keyCode>=48 && event.keyCode onpaste="var s=clipboardData.getData('text'); if(!/\D/.test(s))value=s.replace(/^0*/,''); return false;" />
上面代码中,分别应用3个事件来控制QQ号输入的值。
onKeyUp事件:事件会在键盘按键被松开时发生。如果是数字则可以添加到QQ号文本框中。
onKeyPress事件:事件会在键盘按键被按下并释放一个键时发生。只允许用户输入0~9之间的数字。
onpaste事件:当用户粘贴数据以便从系统剪切板向文档传送数据时在目标对象上触发。当用户向QQ号文本框中粘贴字符串时,只允许用户粘贴数字串。
另外,应用isNaN()方法来验证输入的QQ号是否是数值型。
isNaN(num Value);
numvalue:是必选项,用来检查是否为NaN的值。
当提交签字许愿字条时,将触发checkForm()函数,应用document.getElementById()函数和表单字段的ID(QQ文本框的ID号为“QQ”)来直接获取这个元素。应用isNaN()方法来验证QQ号是否为数值型。
function checkForm(){ //祝福内容 if(isNaN(document.getElementById('QQ').value)){ alert('您输入的QQ号不是数值型,请重新输入!'); document.getElementById('QQ').focus(); return false; } }
常用文本框限制代码:
代码示例:
onkeyup="value=value.replace(/[^a-zA-Z]/g,'')"
说明: replace(/[^a-zA-Z]/g,'')
其中有^为逻辑词“非”,然后后面跟着a-zA-Z指的是英文字母大小写范围,“/g”表示用后面的''中的字符(当前为空)全局替换。
此句代码的含义为:在文本框中只能输入大写或小写字母,如果不是,则自动删除。
常用输入限制代码:
只能输入英文字母:
只能输入英文和数字:
\W匹配字母或数字或下划线或汉字,\D表示匹配数字
只能输入数字和x(用于身份证号的输入) :
|后面的就是可以排除的非数字,可是一个范围x-z
只能输入数字
\D表示匹配数字,中文输入法输入时,存在后续表格不能输入中文问题 不能输入字母,但能输入/.-等 不能输入数字,不允许粘贴 但可以输入空格,解决中文输入法问题
只能输入字母和汉字(还有一些非数字字符)
小数点后只能有最多两位(数字,中文都可输入),不能输入字母和运算符号
3,限制纸条内容的长度 在签写许愿内容时,通常需要限制用户输入文本的长度。在字符串长度的计算上,汉字是占两个字符(汉字的宽度以及存储所占的位置决定了一个汉字占两个字符),而英文字母和数字都被识别为一个字符。在PHP中获取字符串长度应用strlen()函数实现。但是在本模块中,为了能够实现统计许愿内容所允许输入的剩余字符数,这里就要重新输写计算中英文数字混合字符串长度的函数。在签写许愿内容时,实时限制字符数。
添加一个文本框,用来控制输入祝福纸条内容剩余的字节数。
在上面的代码中,应用“freeLength”来实时输出祝福纸条内容所剩余的字符数。
添加一个编辑框用来输入祝福纸条的内容,添加onkeydown和onkeyup事件来触发javascript脚本自定义的函数textCounter(),用来限制该编辑输入的字符数,最多输入150个字符,如果许愿内容大于150,则自动删除,仅保留最大容量值。
在上面的代码中,textCounter()函数有3个参数值,第一个参数值“this.form.content”是指输入的许愿内容;第二个参数值“this.form.freeLength”是指允许输入的许愿内容字符数;第三个参数“150”是输入许愿内容的最大容量值。
应用javascript脚本自定义一个函数textCounter(),控制祝福内容不能超过150个字符,这里需要注意的是,中英文所占的字节数不同。
DBCS是亚洲的字符集,包含ANSI(ANSI即ASCII码值为0~255之间的字符)。DBCS使用1个或者2个字节来表示一个字符集,超过256个字符则占用两个字节。当字符为ANSI时,存放于文件中只占用1个字节。如果非ANSI(大于256个字符),则占用两个字节。因此,这里就用三目运算符来分别计算英文数字和汉字所占用的字节数。当变量StrValue.charCodeAt(i)小于等于256时,按1个字节计算;大于256时按2个字节计算。
function textCounter(field, countfield, maxlimit) { //祝福内容限制在120个字符内 var StrValue = field.value; var ByteCount = 0; var StrLength = field.value.length; for (i=0;i ByteCount = (StrValue.charCodeAt(i) } if(ByteCount strtemp=StrValue; document.getElementById('ContentSample').innerHTML = StrValue; countfield.value = maxlimit - ByteCount; }else{ document.getElementById('content').innerHTML = strtemp; } }
该函数只能限制显示部分150字节,但是输入框没有现在,而且粘贴超过150字节时,显示为空白。修改代码如下:
function textCounter(field, countfield, maxlimit) { //祝福内容限制在150个字符内 var StrValue = field.value; var ByteCount = 0; var StrLength = field.value.length; var cutstr = ''; for (i=0;i ByteCount = (StrValue.charCodeAt(i) if( ByteCount cutstr = StrValue.substring(0,i+1); //如果输入字符小于限制长度,截取当前输入字符i+1为输入字符个数 strtemp = cutstr; } else { cutstr=strtemp; //否则截取最大输入字符长度 } } if(ByteCount document.getElementById('ContentSample').innerHTML = cutstr; //输出显示内容 countfield.value = maxlimit - ByteCount; }else{ document.getElementById('content').value = cutstr; //限制输入框显示内容 document.getElementById('ContentSample').innerHTML = cutstr; //输出显示内容 countfield.value =0; //剩余字节数 } }
在上面的代码中,“countfield.value”是用来计算输入字符串剩余的字符数,并将该值赋给textCounter()函数的第2个参数值“this.form.freeLength”,以此来实时计算当前许愿内容所允许输入的字符数量。
4,PHP验证码类当前页面校验验证码输入对与错 当前页面验证输入是否正确的方法Ajax,add.js
function codecheck(){ var getVcode = document.getElementById('checkcode').value; //获取验证码输入框的内容 xmlhttp.open("get","codeChk.php?code="+getVcode,true); //将验证码发送到codeChk.php页面检验验证码是否正确 xmlhttp.onreadystatechange=function(){ if(xmlhttp.readyState==4) { if(xmlhttp.status==200) { var msg=xmlhttp.responseText; if(msg==1){ document.getElementById("messageImg").src="images/dui.gif"; //验证码正确,输出显示正确图片 document.getElementById('txt_hyan').value = getVcode; }else{ document.getElementById("messageImg").src="images/cuo.gif"; //验证码错误,输出显示错误图片 document.getElementById('checkcode').focus(); return false; } } } } xmlhttp.send(null); }
codeChk.php验证码检验页面
session_start(); require 'secoder.class.php'; //先把类包含进来,实际路径根据实际情况进行修改。 $vcode = new YL_Security_Secoder(); //实例化一个对象 $code = $_GET['code']; echo $vcode->check($code); //check($code)函数返回的是true或者false,返回true时,codeChk.php页面输出的是1,否则没有输出 ?>
secoder.class.php验证码类中的check($code)函数
public static function check($code) { isset($_SESSION) || session_start(); // 验证码不能为空 if(empty($code) || empty($_SESSION[self::$seKey])) { return false; } // session 过期 if(time() - $_SESSION[self::$seKey]['time'] > self::$expire) { unset($_SESSION[self::$seKey]); return false; } if(strtoupper($code) == $_SESSION[self::$seKey]['code']) { //不区分大小写比较 return true; } return false; }
5,定义生成指定范围的许愿条随机算法 本模块需要生成一个指定范围的随机算法,用来显示许愿字条的显示位置,以使每次展示在读者眼前的都是不同的许愿字条。本模块主要应用rand()函数控制许愿墙纸的显示位置。
rand()函数用于产生一个随机整数
语法:rand(min,max) 参数: min,max可选,规定随机数产生的范围
如果没有提供可选参数 min 和 max,rand() 返回 0 到 RAND_MAX 之间的伪随机整数。在某些平台下(例如 Windows)RAND_MAX 只有 32768。如果需要的范围大于 32768,那么指定 min 和 max 参数就可以生成大于 RAND_MAX 的数了,或者考虑用 mt_rand() 来替代它。
mt_rand() 使用 Mersenne Twister 算法返回随机整数
语法:mt_rand(min,max) 如果没有提供可选参数 min 和 max,mt_rand() 返回 0 到 RAND_MAX 之间的伪随机数。很多老的libc的随机数发生器具有一些不确定和未知的特性而且很慢。php的rand()函数默认使用libc随机数发生器。mt_rand()函数是非正式用来替换它的。该函数用了Mersenne Twister中已知的特性作为随机数发生器,它可以产生随机数值的平均速度比libc提供的rand()快四倍。
随机显示许愿墙纸的关键代码如下:
$T=rand(320,520);
$L=rand(5,790);
$Z=$page_count;
$Z = $Z - 3;
echo "
爱墙编号:".$id." ".$sendtime." ×
".$Picker." $content
".$author."
";
6,解析IP获取用户所在城市 在PHP中,使用PHP预定义变量$_SERVER['REMOTE_ADDR']获取客户端的IP地址。然后将IP按照通用的算法将其解析成一个数字串(每个城市都有一个对应的数字串),通过这个数字串来确定查询用户所在的城市名称。
在数据库中,IP区域的存储时一个数字串,并非实际的IP地址,这时就需要对客户端或服务器端的IP转换成指定数字串的格式,从而进行地域信息的查询。
$ip=getenv('REMOTE_ADDR'); //获取客户端IP地址 /********解释IP区域***********/ $cip=cip($ip); $csql="select * from tb_ip where (ip1'".$cip."') or (ip1=ip2 and ip2='".$cip."')"; //执行查询 $res = $DB->fetch_one_array($csql); $cip1=$res['country']; if($cip1==""){ $cip1="IP不详"; }
二,实现过程 1,双击许愿字条,该字条置顶显示,并屏蔽整个页面 当用户双击许愿字条后,该许愿字条将置顶显示,同时屏蔽整个页面,以达到突出显示的效果。
(1)控制DIV突显效果,首页设置一个隐藏的DIV,ID名称为“shadeDiv”,代码如下
(2)应用Javascript脚本自定义一个Hide()函数,通过设置DIV的显示属性display设置为空,从而隐藏DIV ,代码如下:
function Hide(){ document.getElementById("shadeDiv").style.display = "none"; iLayerMaxNum = iLayerMaxNum+2; }
(3)在CSS样式表中设置隐藏DIV的样式。代码如下: #shadeDiv{filter:alpha(Opacity=55);opacity:0.35;background: #333;position:absolute;} //IE浏览器下滤镜效果,兼容性不好
(4)接下来,双击已经设计好的许愿字条DIV图层,代码如下: ondblclick=Show(".$id.",'shadeDiv')
(5)自定义一个函数show(),用来控制背景的效果。
function Show(n,divName){ document.getElementById(n).style.zIndex = iLayerMaxNum+1; document.getElementById(divName).style.display = "block"; document.getElementById(divName).style.zIndex = iLayerMaxNum; var size = getPageSize(); //设置隐藏区域的面积,这里是获取许愿墙显示区域的面积,即本例中设置滤镜的面积 document.getElementById(divName).style.width = size[0]+"px"; document.getElementById(divName).style.height = size[1]+"px"; }
(6)设置纸条显示的区域,这里得到的仅仅是数字
function getPageSize(){ var w =document.body.clientWidth; var h= document.body.clientHeight; arrayPageSize = new Array(w,h); return arrayPageSize; }
2,应用Jpgraph图形类库实现3D饼形图表按地域统计分析许愿比率,实现过程如下: (1)应用浮动框架技术实现不同类别下的地域统计分析结果,每一个黄颜色的版块分别是一个浮动框架.浮动框架布局的代码如下:
(2)应用3D饼形图动态统计分析全部区域的许愿比率 首先应用Jpgraph类库实现图表分析,需要应用include语句引用jpgraph.php文件。代码如下:
include("global.php"); //链接数据库源文件 include("jpgraph/jpgraph.php"); //引用图表分析类文件 ?>
绘制饼形图需要引用jpgraph_pie.php文件。绘制3D效果的饼形图需要创建PiePlot3D类对象,PiePlot3D类在Jpgraph_pie3d.php中定义,需要应用include语句调用该文件。代码如下:
include("jpgraph/jpgraph_pie.php"); //引用饼形图类文件 include_once("jpgraph/jpgraph_pie3d.php"); //引用3D饼图PiePlot3D对象所在的类文件 ?>
创建graph对象,生成一个990x276像素大小的画布,设置统计图所在画布的位置以及画布的阴影。设置标题的字体以及图例的字体。设置饼形图所在画布的位置以及半径,将绘制的3D饼形图添加到图像中。
$graph = new PieGraph(990,276); //创建画布 $graph->SetShadow(); //设置阴影 $graph->title->Set("应用3D饼形图统计分析全部区域许愿比率"); //设置标题名称 $graph->title->SetFont(FF_SIMSUN,FS_BOLD); //设置标题的字体加粗 $graph->legend->SetFont(FF_SIMSUN,FS_NORMAL); //设置饼形图文字的字体 $size=0.5; //设置饼形图的半径 /***********************统计全部许愿比率*************************/ //创建饼形图对象 $p0= new PiePlot3D($arraynum0); //创建饼形图对象 $p0->SetLegends($arraycip0); $p0->SetSize($size); //设置饼形图的大小 $p0->SetCenter(0.45,0.48); //设置饼形图的坐标位置 $p0->SetLegends($arraycip0); //设置城市名称 $p0->value->SetFont(FF_FONT0); //设置字体 $p0->title->SetFont(FF_SIMSUN,FS_BOLD); //设置标题字体加粗 /*************************************************************/ $graph->Add($p0); //添加3D饼形图到图像中 $graph->Stroke(); //输出图像 ?>
(3)应用3D饼形图动态统计分析”亲情类“的许愿比率。 其实现方法与获取全部的许愿比率的方法基本类似,不同的是这里在检索亲情类许愿人数时设置了where查询条件。另外在设置饼形图的半径和位置上稍微有变化。
include("global.php"); //链接数据库文件 include ("jpgraph/jpgraph.php"); //引用图表分析类文件 include ("jpgraph/jpgraph_pie.php"); //引用饼形图类文件 include_once ("jpgraph/jpgraph_pie3d.php"); //引用3D饼图PiePlot3D对象所在的类文件 /***********************统计亲情类别*************************/ $sql2="select distinct(count(cip)) as num,cip from tb_wishes where wishsort='亲情' group by cip "; $DB->query($sql2); //动态统计亲情类许愿 $res2=$DB->get_rows_array($sql2); //生成二维数组 $rows_count2=count($res2); //统计二维数组的数量 $arraynum2=array(); //声明城市”亲情类“许愿总数数组 $arraycip2=array(); //声明”亲情类“城市名称数组 //解析数组 for($k=0;$k array_push($arraynum2,$res2[$k][num]); //输出城市的许愿数量 array_push($arraycip2,$res2[$k][cip]); //输出城市名称 } /*************************************************************/ //创建画布 $graph = new PieGraph(320,246); //创建画布 $graph->SetShadow(); //设置阴影 $graph->title->Set("统计分析全部区域的[ 亲情类 ] 许愿比率"); //设置标题名称 $graph->title->SetFont(FF_SIMSUN,FS_BOLD); //设置标题的字体加粗 $graph->legend->SetFont(FF_SIMSUN,FS_NORMAL); //设置饼形图文字的字体 $size=0.3; //设置饼形图的半径 /***********************统计亲情许愿比率*************************/ $p= new PiePlot3D($arraynum2); //创建饼形图对象 $p->SetLegends($arraycip2); //设置城市名称 $p->SetSize($size); //设置饼形图的大小 $p->SetCenter(0.45,0.55); //设置饼形图的坐标位置 $p->value->SetFont(FF_FONT0); //设置字体 $p->title->SetFont(FF_SIMSUN,FS_BOLD); //设置标题字体加粗 /*************************************************************/ $graph->Add($p); //添加3D饼形图到图像中 $graph->Stroke(); //输出图像 ?>
3,许愿墙列表,许愿墙字条高级搜索功能的实现 为了便于访客能更清晰地查看各种不同类别的许愿字条,本模块设计了爱墙列表和许愿字条高级搜索功能。其中,爱墙列表时在默认状态下检索全部的许愿字条,而高级搜索功能是按照访客设置的一定的查询条件来检索与之匹配的许愿字条。
设计爱墙列表及许愿字条高级搜索的表单元素如下:
4,许愿墙显示效果如图: