??xml version="1.0" encoding="utf-8" standalone="yes"?>
闭包是通过在对一个函数调用的执行环境中返回一个函数对象构成的。比如,在对函数调用的过E中Q将一个对内部函数对象的引用指定给另一个对象的属性。或者,直接这样一个(内部Q函数对象的引用指定l一个全局变量、或者一个全局性对象的属性,或者一个作为参C引用方式传递给外部函数的对象。例如:-
function exampleClosureForm(arg1, arg2){
var localVar = 8;
function exampleReturned(innerArg){
return ((arg1 + arg2)/(innerArg + localVar));
}
/* q回一个定义ؓ exampleReturned 的内部函数的引用 -:- */ return exampleReturned;
}
var globalVar = exampleClosureForm(2, 4);
q种情况下,在调用外部函?exampleClosureForm 的执行环境中所创徏的函数对象就不会被当作垃圾收集,因ؓ该函数对象被一个全局变量所引用Q而且仍然是可以访问的Q甚臛_以通过 globalVar(n) 来执行?
的确Q情冉|正常的时候要复杂一些。因为现在这个被变量 globalVar 引用的内部函数对象的 [[scope]] 属性所引用的作用域链中Q包含着属于创徏该内部函数对象的执行环境的活动对象(和全局对象Q。由于在执行?globalVar 引用的函数对象时Q每ơ都要把该函数对象的 [[scope]] 属性所引用的整个作用域链添加到创徏的(内部函数的)执行环境的作用域中(x时的作用域中包括Q内部执行环境的zd对象、外部执行环境的zd对象、全局对象。译者注Q, 所以这个(外部执行环境的)zd对象不会被当作垃圾收集?
闭包因此而构成。此Ӟ内部函数对象拥有自由的变量,而位于该函数作用域链中的zdQ可变)对象则成Z变量l定的环境?
׃zdQ可变)对象受限于内部函数对象(现在?globalVar 变量引用Q的 [[scope]] 属性中作用域链的引用,所以活动对象连同它的变量声明-Q即属性的|都会被保留。而在对内部函数调用的执行环境中进行作用域解析Ӟ会把与zdQ可变)对象的命名属性一致的标识W作对象的属性来解析。活动对象的q些属性值即使是在创建它的执行环境退出后Q仍然可以被d和设|?
在上面的例子中,当外部函数返回(退出它的执行环境)Ӟ其活动(可变Q对象的变量声明中记录了形式参数、内部函数定义以及局部变量的倹{arg1 属性的gؓ 2Q?arg2 属性的gؓ 4QlocalVar 的值是 8Q还有一?exampleReturned 属性,它引用由外部函数q回的内部函数对象。(为方便v见,我们在后面的讨ZQ称q个zd<可变>对象?"ActOuter1"Q?
如果再次调用 exampleClosureForm 函数Q如Q?
var secondGlobalVar = exampleClosureForm(12, 3);
- 则会创徏一个新的执行环境和一个新的活动对象。而且Q会q回一个新的函数对象,该函数对象的 [[scope]] 属性引用的作用域链与前一ơ不同,因ؓq一ơ的作用域链中包含着W二个执行环境的zd对象Q而这个活动对象的属?arg1 gؓ 12 而属?arg2 gؓ 3。(为方便v见,我们在后面的讨ZQ称q个zd<可变>对象?"ActOuter2"Q?
通过W二ơ执?exampleClosureForm 函数Q第二个、也是截然不同的闭包诞生了?
通过执行 exampleClosureForm 创徏的两个函数对象分别被指定l了全局变量 globalVar ?secondGlobalVarQƈq回了表辑ּ ((arg1 + arg2)/(innerArg + localVar))。该表达式对其中的四个标识符应用了不同的操作W。如何确定这些标识符的值是体现闭包价值的关键所在?
我们来看一看,在执行由 globalVar 引用的函数对象-Q如 globalVar(2)Q-时的情Ş。此Ӟ会创Z个新的执行环境和相应的活动对象(我们称之ؓ“ActInner1”Q,q把该活动对象添加到执行的函数对象的 [[scope]] 属性所引用的作用域铄前端。ActInner1 会带有一个属?innerArgQ根据传递的形式参数Q其D指定?2。这个新执行环境的作用域铑֏成: ActInner1->ActOuter1->全局对象.
Zq回表达?((arg1 + arg2)/(innerArg + localVar)) 的|要沿着作用域链q行标识W解析。表辑ּ中标识符的值将通过依次查找作用域链中每个对象(与标识符名称一_的属性来定?
作用域链中的W一个对象是 ActInner1Q它有一个名?innerArg 的属性,值是 2。所有其他三个标识符?ActOuter1 中都有对应的属性:arg1 ?2Qarg2 ?4 ?localVar ?8。最后,函数调用q回 ((2 + 2)/(2 + 8))?
现在再来看一看由 secondGlobalVar 引用的同一个函数对象的执行情况Q比?secondGlobalVar(5)。我们把q次创徏的新执行环境的活动对象称?“ActInner2”Q相应的作用域链变成了QActInner2->ActOuter2->全局对象。ActInner2 q回 innerArg 的?5Q?ActOuter2 分别q回 arg1、arg2 ?localVar 的?12? ?8。函数调用返回的值就?((12 + 3)/(5 + 8))?
如果再执行一?secondGlobalVarQ则又会有一个新zd对象被添加到作用域链的前端,?ActOuter2 仍然是链中的W二个对象,而他的命名属性会再次用于完成标识W?arg1、arg2 ?localVar 的解析?
q就?ECMAScript 的内部函数获取、维持和讉K创徏他们的执行环境的形式参数、声明的内部函数以及局部变量的q程。这个过E说明了构成闭包以后Q内部的函数对象在其存箋q程中,如何l持对这些值的引用、如何对q些D行读取的机制。即Q创建内部函数对象的执行环境的活动(可变Q对象,会保留在该函数对象的 [[scope]] 属性所引用的作用域链中。直到所有对q个内部函数的引用被释放Q这个函数对象才会成为垃圾收集的目标Q连同它的作用域链中M不再需要的对象Q?
内部函数自n也可能有内部函数。在通过函数执行q回内部函数构成闭包以后Q相应的闭包自n也可能会q回内部函数从而构成它们自q闭包。每ơ作用域铑ֵ套,都会增加由创建内部函数对象的执行环境引发的新zd对象。ECMAScript 规范要求作用域链是时性的Q但对作用域铄长度却没有加以限制。在具体实现中,可能会存在实际的限制Q但q没有发现有具体限制数量的报告。目前来看,嵌套的内部函数所拥有的潜能,仍然出了用它们的人的惛_能力?
UID50579 帖子297 _֍0 下蝲?14 ?金币236 ?阅读权限200 在线旉131 时 注册旉2008-10-2 最后登?008-12-22 查看个h|站
查看详细资料
引用 使用道具 报告 回复 TOP
事g分发时添?eventListener
不会立即触发 eventListenerQ可能会在下一个事件流Q比如冒泡阶D)中触发?/p>
多个相同?eventListener
如下Q三个参数完全相同,q且W二个参C是匿名函数?/p>
会抛弃多余的Q只保留一个,对应?removeEventListener 也只用一ơ就可以了(removeEventListener 用法?addEventListener 完全相同Q?/p>
但如果是W二个参数是匿名函数Q比如:
则三个均有效Qƈ且无法用 removeEventListener 除去?/p>
this
事g处理E序中,this 变成了触发事件的控gQ但我们仍推荐用 event.target ?event.currentTarget?/p>
早期的事件监?/span>
?DOM0 中,我们?obj.onclick = FuncNameQ由于兼Ҏ好Q应用非常广泛,只是功能不如 addEventListener 强大?/p>
内存问题
前面提到了许多用域名函数的地方Q有时这是没办法的,请参?a target="_blank">在各览器中动态添加事Ӟ参数?/a>Q但q会D内存问题?/p>
一旦事件绑定之后,该绑定代?a target="_blank">作用?/a>的变量就都保留下来,不会?JavaScript 引擎回收Q这可能会引起占用大量内存的问题Q由?removeEventListener 无法删除匿名函数的事件处理程序,只有在物Ӟ比如按钮Q去除之后,该内存才可能得到回收?/p>
事gcd
DOM 事gcd是分?UIEvent、UIEvent:KeyEvent、UIEvent:MouseEventQ不同的事g有不同的属性和ҎQ但常用的来说我们都不会用错Q比如我们不会在鼠标事g中去取键盘|Ctrl、Alt、Shift 除外Q,所以我们没有必要深I?/p>
该对象的属性和Ҏ有:
view 只读Q对象,发生事g?Window 对象?/p>
type 只读Q字W串。比如鼠标点M件的cdQclick?/p>
eventPhase 只读Q数字,事g正l历的阶Dc?Q捕P2Q目标,3Q冒泡?/p>
target 只读Q对象,z֏事g的目标对象。比如鼠标是点击在哪个按钮上的?/p>
currentTarget 只读Q对象,当前正在调用监听器的对象Q也是当前 addEventListener 是绑定在哪个对象上的?/p>
timeStamp 只读Q数字,用毫U表CZ件发生时距计机开机的旉?/p>
cancelable 只读Q布,处理事g的默认行为是否可以停止。主要针对一些系l事Ӟ如果gؓ trueQ则 event ?preventDefault Ҏ可以使用Q否则不可用?/p>
preventDefault() L览器的默认行ؓQ比如在文本框中打字触发 keydownQ如?keydown 事g处理E序中调用了 preventDefault()Q所打的字就不会跑到文本框中去,注意Q此时不要弹?alert 对话框,否则可能不v作用。IE 中在事g处理E序中用 return false 实现cM功能?/p>
bubbles 只读Q布,事g是否开启冒泡功能?/p>
stopImmediatePropagation q个东西?JavaScript 中是个属性,而不是方法,布尔Q但具体试q未发现其用途,不知是不?bug?/p>
stopPropagation() 停止当前的事件流传播Q但不会停止当前正在处理的对象。IE 中用 event.cancelBubble = true 实现cM功能?/p>
cancelBubble 布尔Q是否取消冒泡,不徏议?/span>Q用 stopPropagation() 代替?/p>
preventBubble() L冒Q?span class="caution">不徏议?/span>Q用 stopPropagation() 代替?/p>
preventCapture() L捕获Q?span class="caution">不徏议?/span>Q用 stopPropagation() 代替?/p>
detail 只读Q数字,提供旉的额外信息,对于 click 事g、mousedown 事g?mouseup 事gQ这个字D代表点ȝơ数?/p>
isChar 只读Q布,按下的按键值是否是字符Q比如按?Ctrl 键时Q就q回 false。不q您?Firefox 中测试时Q该值L falseQFirefox 官方已经说明q是一?bug?/p>
altKey 只读Q布,是否按下?Alt 键?/p>
ctrlKey 只读Q布,是否按下?Ctrl 键?/p>
shiftKey 只读Q布,是否按下?Shift 键?/p>
metaKey 只读Q布,是否按下?Meta 键?/p>
下面一些属性很有意思,请仔l区别?/span> charCode 只读Q数字,字符Q英文、数字、符P?Unicode 倹{?/p>
keyCode 只读Q数字,键盘按键倹{?/p>
button 只读Q数字,鼠标按键倹{?/p>
which 只读Q数字,键盘按键值或鼠标按键倹{?/p>
可以看出Qwhich 只有一Ҏ有包括:那就?keypress Ӟ不如 keyCode 那么全,但实际上Qkeypress 事g中用于非字符键的情况较少Q所以一般还是用 which 代替全部?/span>
]]>
上述是我们测试的代码Q根?info 的显C来定触发的顺序,有三?addEventListenerQ?useCapture 可选gؓ true ?falseQ所?2*2*2Q可以得?8 D不同的E序?/p>
最l得出如下结论:
下面提供全部代码Q您可以更改其中?true、false |来进行测试。注意,不适用?IE?br />
当一个事件发生时Q分Z个阶D:
捕获阶段 从根节点开始顺序而下Q检每个节Ҏ否注册了事g处理E序。如果注册了事g处理E序Qƈ?useCapture ?trueQ则调用该事件处理程序。(IE 中无此阶Dc)
目标阶段 触发在目标对象本w注册的事g处理E序Q也U?span class="itemTitle">正常事gz֏阶段?/p>
冒阶段 从目标节点到根节点,每个节Ҏ否注册了事g处理E序Q如果注册了事g处理E序Qƈ?useCapture ?falseQ则调用该事件处理程序?
举例
如果?d3 上点击鼠标,事g是q样的:
捕获阶段 ?div1 处检是否有 useCapture ?true 的事件处理程序,若有Q则执行该程序,然后再同样地处理 div2?/p>
目标阶段 ?div3 处,发现 div3 是鼠标点击的节点,所以这里ؓ目标阶段Q若有事件处理程序,则执行该E序Q这里不?useCapture ?true q是 false?/p>
冒阶段 ?div2 处检是否有 useCapture ?false 的事件处理程序,若有Q则执行该程序,然后再同样地处理 div1?/p>
注意Q上q捕获阶D和冒阶段中,实际?div1 之上q应该有l点Q比如有 bodyQ但q里不讨论?/p>
addEventListener 用于注册事g处理E序QIE 中ؓ attachEventQ我们ؓ什么讲 addEventListener 而不?attachEvent 呢?一?attachEvent 比较单,二来 addEventListener 才是 DOM 中的标准内容?/p>
?/span>
addEventListener 为文档节炏Vdocument、window ?XMLHttpRequest 注册事g处理E序Q在以前我们一般是 <input type="button" onclick="..."Q或 document.getElementById("testButton").onclick = FuncNameQ?nbsp;而在 DOM 中,我们?addEventListenerQIE 中用 attachEventQ?/p>
语法
CZ
或?listener 直接是函数
JavaScript(js)静态页面传gCookie加入时_2007-12-25 9:17:28 来源Q?nbsp; ~辑Q 利用Cookieq行静态页面g递:Cookie是浏览器存储量命名数据.它与某个特定的网||站兌在一赗?br />
Cookie用来l浏览器提供内存,以便脚本和服务器E序可以在一个页面中使用另一个页面的输入数据?br />
Post.htm
以下是引用片D:
function setCookie(name,value)
{
/*
*--------------- setCookie(name,value) -----------------
* setCookie(name,value)
* 功能:讄得变量name的?br />
* 参数:name,字符?value,字符?
* 实例:setCookie('username','baobao')
*--------------- setCookie(name,value) -----------------
*/
var Days = 30; //?cookie 被保存 30 ?br />
var exp = new Date();
exp.setTime(exp.getTime() + Days*24*60*60*1000);
document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
location.href = "Read.htm"; //接收面.
}
Read.htm
以下是引用片D:
function getCookie(name)
{
/*
*--------------- getCookie(name) -----------------
* getCookie(name)
* 功能:取得变量name的?br />
* 参数:name,字符?
* 实例:alert(getCookie("baobao"));
*--------------- getCookie(name) -----------------
*/
var arr = document.cookie.match(new RegExp("(^| )"+name+"=([^;]*)(;|$)"));
if(arr !=null) return unescape(arr[2]); return null;
}
alert(getCookie("baobao"));
优点:可以在同源内的Q意网内讉K.生命期可以设|?
~点:值长度有限制.
本文转自州IT信息|?http://www.fzic.net)
本文转自可可在线(http://www.rcinn.cn),详细出处参考:http://www.xqke.cn/news.asp?id=475
function LTrim(str){
var i; for(i=0; i<str.length; i++){ if(str.charAt(i)!=" ") break; str=str.substring(i,str.length) ; return str; } } var i ; for(i=str.length-1; i>=0; i++){ if(charAt(i)!=" ") break; } str = str.substring(0, i+1) ; } return LTrim(RTrim(str)) ; } if(Trim(document.form1.title.value == "")){ alert("Sorry ! title is Empty !") ; document.form1.title.focus() ; return false ; } if(Trim(document.form1.cont.value == "")){ alert("Sorry ! cont is Empty !") ; document.form1.cont.focus() ; return false; } return true ; |
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>无标题页</title>
<script type="text/javascript">
var leftTime = 10;
window.onload = initAll;
function initAll()
{
show();
}
function show()
{
document.getElementById("btntest").value=leftTime;
leftTime--;
if(leftTime>0)
{
setTimeout("show()",1000);
}
else
{
document.getElementById("btntest").value="OK !";
document.form1.btntest.disabled=false;
}
}
</script>
</head>
<body>
<form action="" name="form1">
<input size="30" type="button" name="btntest" id="btntest" value="" disabled="true" />
</form>
</body>
</html>
昄Q如果用动态的脚本来初始化菜单数组Qasp,jsp均可Q,那就可以很方便的实现动态的树型菜单了?/span>
2。jsp动态实?br /> 分以下步骤实现动态的树型菜单Q?br /> 1Q在数据库徏tree_info表,有nodeIdQparentNodeIdQnodeNameQnodeUrl四个字段Q来存储节点信息?br /> 2Q编写javac,用于从数据库扑և节点信息Qƈ且生成javascript脚本?br /> 3Q编写tagcR用于封装逻辑Q简化jsp的开发?br /> 4Q徏一个webE序q行试?/span>
3。详l过E?br />
1Q在数据库徏表,脚本如下Q?br />
CREATE TABLE `test`.`tree_info` (
`node_id` INTEGER UNSIGNED NOT NULL DEFAULT -1,
`parent_id` INTEGER UNSIGNED NOT NULL DEFAULT -1,
`node_name` VARCHAR(45) NOT NULL,
`ref_url` VARCHAR(45) NOT NULL,
PRIMARY KEY(`node_id`)
)
我用mysql数据库,如果脚本l节有出入,误行修?br />
按照上面的dTreeCZ插入数据
2Q编写TreeInfo.javaQ这个类用于装节点信息
package com.diegoyun.web.tree;
/**
* @author Diegoyun
* @version 1.0
*/
public class TreeInfo {
private int nodeId = -1;//node id
private int parentId = -1;//parentId
private String nodeName = null;//node name
private String url = null;//url references
public int getNodeId() {
return nodeId;
}
public void setNodeId(int nodeId) {
this.nodeId = nodeId;
}
public int getParentId() {
return parentId;
}
public void setParentId(int parentId) {
this.parentId = parentId;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
~写TreeUtil.javaQ用于从数据库得到节点信息,装到TreeInfo对象Qƈ生成javascript脚本
TreeUtil.java
package com.diegoyun.web.tree;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Connection;
import java.sql.DriverManager;
/**
* @author Diegoyun
* @version 1.0
*/
public class TreeUtil {
public static List retrieveNodeInfos(){
List coll = new ArrayList();
String driverName = "com.mysql.jdbc.Driver";
String host = "localhost";
String port = ":3306";
String serverID = "test";
String userName = "root";
String userPwd = "root";
String url = "jdbc:mysql://" + host + port + "/" + serverID ;
Connection conn = null ;
PreparedStatement ps = null;
ResultSet rs = null;
try{
Class.forName(driverName).newInstance();
conn = DriverManager.getConnection(url , userName , userPwd);
String sql = "select * from tree_info";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
TreeInfo info = null;
while(rs!=null && rs.next()){
info = new TreeInfo();
info.setNodeId(rs.getInt(1));
info.setParentId(rs.getInt(2));
info.setNodeName(rs.getString(3));
info.setUrl(rs.getString(4));
coll.add(info);
}
// if(rs!=null){
// rs.close();
// rs=null;
// }
// if(ps!=null){
// ps.close();
// ps=null;
// }
}catch(Exception e){
System.out.println(e);
}
return coll;
}
public static String createTreeInfo(List alist){
StringBuffer contents = new StringBuffer();
contents.append("<!--\n");
contents.append("var Tree = new Array;");//create a array in javascript
TreeInfo info =null;
for(int max = alist.size(),i=0;i<max;i++){
info = (TreeInfo)alist.get(i);
//define elements of array
contents.append("Tree[");
contents.append(i);
contents.append("]=\"");
contents.append(info.getNodeId());
contents.append("|");
contents.append(info.getParentId());
contents.append("|");
contents.append(info.getNodeName());
contents.append("|");
contents.append(info.getUrl());
contents.append("\";");
}
contents.append("docment.writer(Tree);");
contents.append("http://-->");
return contents.toString();
}
public static void main(String[]args){
List alist = TreeUtil.retrieveNodeInfos();
// TreeInfo info = null;
// for(Iterator i = c.iterator();i.hasNext();){
// info = (TreeInfo)i.next();
// System.out.println("*****" + info.getNodeName());
// }
System.out.println(TreeUtil.createTreeInfo(alist));
}
}
3)~写标签c?br />
InitTreeTag.java
package com.diegoyun.web.taglibs;
import com.diegoyun.web.tree.TreeUtil;
import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.jsp.JspException;
import java.io.IOException;
/**
* @author Diegoyun
* @version 1.0
*/
public class InitTreeTag extends TagSupport{
public int doEndTag() throws JspException {
StringBuffer tree = new StringBuffer();
tree.append("<script type=\"text/javascript\">\n");
tree.append(TreeUtil.createTreeInfo(TreeUtil.retrieveNodeInfos()));
tree.append("</script>\n");
try{
pageContext.getOut().println(tree.toString());
}catch(IOException ioe){
ioe.printStackTrace();
}
return super.doEndTag();
}
}
ShowTreeTag.java :
package com.diegoyun.web.taglibs;
import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.jsp.JspException;
import java.io.IOException;
/**
* @author Diegoyun
* @version 1.0
*/
public class ShowTreeTag extends TagSupport{
public int doEndTag() throws JspException {
StringBuffer buffer = showTree();
try {
pageContext.getOut().println(buffer.toString());
}
catch (IOException ioe) {
ioe.printStackTrace();
}
return super.doEndTag();
}
private StringBuffer showTree(){
StringBuffer sb = new StringBuffer();
sb.append("<div class=\"tree\">\n");
sb.append("<script type=\"text/javascript\">\n");
sb.append("<!--\n");
sb.append("createTree(Tree);\n");
sb.append("http://-->\n");
sb.append("</script>\n");
sb.append("</div>\n");
return sb;
}
}
标签的tld如下Q?br />
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>tree</short-name>
<!--initTreeTag-->
<tag>
<name>init</name>
<tag-class>com.diegoyun.web.taglibs.InitTreeTag</tag-class>
<body-content>empty</body-content>
</tag>
<!--ShowTreeTag-->
<tag>
<name>show</name>
<tag-class>com.diegoyun.web.taglibs.ShowTreeTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
4Q徏立webq程Q编写jspq行试?/span>
index.jsp如下Q?br />
<%@ page language="java"%>
<%@ taglib uri="/WEB-INF/tlds/tree.tld" prefix="tree"%>
<html>
<head>
<title>Tree example</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="StyleSheet" href="tree.css" type="text/css">
<script type="text/javascript" src="tree.js"></script>
<tree:init/>
</head>
<body>
<b>Tree example :</b><br /><br />
<tree:show/>
<br /><br />
</body>
</html>
试Qenjoy yourselfQ?/span>
4。待解决问题
dTree有点bugQ如果把cssQimgQjs的\径改变,树就有可能不会正显C?nbsp;
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
window.onload=initAll ;
function initAll(){
document.getElementById("test01").onclick=test ;
}
function test(evt){
var src = evt ? evt.target : window.event.srcElement ;
alert(src) ;
return false ;
}
</script>
</head>
<body>
<center>
<a id="test01">test01</a>
</center>
</body>
</html>