Posts Tagged ‘javascript’

如何写出更好的JS树状菜单

catge Posted in Life,Tags: ,
4

差不多是两年前的这个时候,我当时在华中科技大学注册中心HUB团队负责WEB标准化和规范化的工作。当时我花了两天两夜,重写了注册中心的HTML模板,并通过了W3C的CSS、XHTML校验。我拿着这套模板,告诉办公室主任王士贤老师,学校的信息系统应该做个大手术,全部换成我的新模板。当时王老师笑了笑,说这个改动太大,委婉的拒绝了我的提议,他说了让我刻骨铭心的一句话:

“网页技术发展很快,也许几年后,你再来看你写的这些模板,会有更好的想法。”

两年前我看到“不会用JS写树状菜单,就不算真正懂JS”,于是我通宵写了这个树状菜单。之后陆陆续续有不少人加我QQ,交流树状菜单的问题,甚至还有网友给我个绰号“树状菜单弟” -_-! 这两年来随着个人前端技术水平的不断提升,尤其是支付宝个人版项目对我的锻炼,我开始逐渐明白“技术没有最好的,只有最适合的”这句话的含义。在今年第四届D2会议上,豆瓣的张克军分享了《从YUI2到YUI3看前端的演变》,前端的“库”时代已经来临。

我一直想重写这个树状菜单,修复原来的两个BUG,采用基于YUI的组件封装模式来写,独立出样式表现层和脚本行为层,提供丰富的扩展接口,同时考虑到禁用JS时的可用性。在我开始写这个组件的时候,我忽然想起D2上一名观众问克军的一个问题“您做为一个前辈,请给我们这些菜鸟一些指导,是应该学YUI还是JQuery?”克军的回答是,从最基础的原生的JS获取对象绑定事件等知识学起,学什么框架不重要,选择一个合适的,会用即可。其实任何一门编程语言都是如此。如果我在这里用YUI写出一个树状菜单组件,那唯一的用途就是被一些垃圾源码站转载,而且不大可能被应用,还不如看看YUI里的menu组件。懒懒交流会上,淘宝的玉伯说过,如果想让自己的JS代码“流芳百世”就得用原生的写法,因为不依赖任何框架的JS代码复制粘贴起来最方便。

然而为了方便组件编写和减少BUG,为了一个事件绑定,我不得不在自己的代码里加上addEvent的方法。还得加hasClass、addClass、get等DOM操作方法,大大增加代码的长度。于是我放弃了重写的这个念头,只是略讲下编写思路好了。

function addEvent(obj, type, fn) {
    if(obj.addEventListener){
        obj.addEventListener(type, fn, false);
    }else if(obj.attachEvent){
        obj["e"+type+fn] = fn;
        obj.attachEvent( "on"+type, function() { obj["e"+type+fn](); } );
    }
}

首先初始化绑定导航的DOM,然后分别为每一级的UL和LI绑定上hover和click事件,分别加上”hover”和”select”的样式名。然后通过CSS来展现样式,显示隐藏对应节点。Over

再过两年后,我再回过头看现在的代码思路,可能会有更好的想法。代码需要熟能生巧,需要时刻跟上技术的发展,才能保持优雅的姿态。多看看前辈的文章,多与人交流,拜一个好的师傅,是学习的最佳途径。

其实做人又何尝不是如此。自以为是的自己,总会被以后看似成熟的自己所否定。以前catge同学常被人说幼稚儿童,心有不甘。现在则习惯了,被人说幼稚不要紧,关键要学会改变自己,改掉不足的地方,学习他人的长处。倒是有个88年的幼齿,说不带我这个老年人一起玩的时候,我心碎了。

PS:这个雪人是我自己堆的,还是很有童心的吧,请90后的小弟弟小妹妹不要拒绝我^o^

《JavaScript入门经典》studyNote

catge Posted in Share,Tags: ,
1

    对于javascript初学者,或者是和我一样不是很精通的人,我极力推荐这本书。你可以把它当作一本教材,或者是参考手册,也可以只是随手翻翻。该书详细的介绍了关于javascript的一切,从起源到未来,从语法到脚本,从内置对象到第三方库,从编码习惯到测试工具,从DHTML到AJAX,作者甚至还饶有兴趣的介绍了FF下的Greasemonkey插件。果然在计算机图书这块,国内与国外不单单只是一个技术差距的问题,可能还有知识传授方式的差异。

本书用到的示例代码可以从这里下载:
http://www.samspublishing.com/bookstore/product.asp?isbn=0672328798&rl=1#info3

摘录本书可能对我有用的部分内容:

————Document对象————
document.URL 获取文档的URL地址,只读,若要指定不同地址,可使用window.location对象。
document.title 列出由HTML中的<title>定义的页面标题,可写。
document.referrer 用户来到此页的来源页。注:该值需要http://访问才能获得,且区分字母大小写。
document.lastModified 返回文档最后修改日期时间。
document.links.length 返回页面中链接的数量
document.anchors.length 返回页面中锚点数量

————Location对象————–
window.location.href 改变该属性值可以改变当前窗口URL。
location.reload() 刷新当前文档,传入参数true将忽略缓存强制刷新当前文档。
location.replace() 替换当前页到指定地址,且替换当前页在浏览器历史中的记录。

————String对象—————–
toUpperCase() 将所有字符转化为大写
toLowerCase() 将所有字符转化为小写
substring(a,b) 该方法返回的是从a(a,b为字符串索引,包括a)到b(不包括b)间的字符串
charAt(a) 该方法返回字符串的第a个字符
indexOf("this",2) 从第2个字符处开始搜索该字符串中是否包含"this",返回的是找到的索引值,没有则返回-1
lastIndexOf() 方法同上,从字符串尾向前搜索。
split(" ") 将该字符串在每个空格处分开,返回数组
join(" ") 与split相反
replace("a","b") 将字符串中的a替换成b

————-Math对象—————–
Math.ceil() 将一个数字向上舍入到上一个整数
Math.floor() 向下舍入
Math.round() 将一个数字舍入到最接近的整数
Math.random() 返回0至1之间的随机小数

————-Date对象—————–
setDate(),getDate(),getUTCDate(),setUTCDate()
setMonth(),0-11表示月份
setFullYear()
setTime(),从1970年1月1日起算的毫秒数值
setHours、setMinutes()、setSeconds()、getMilliseconds()
setDay()
getTimezoneOffset(),方法返回一个整数值,表示当前计算机时间和 UTC 时间相差的分钟数,负值表示早于UTC时间
toUTCString(),使用UTC把date对象时间值转换成文本
toLocalString(),使用本地时间把date对象时间值转换成文本
Date.parse()把日期字符串转换成一个Date对象(从1970年1月1日起算的毫秒数值)
Date.UTC()把Date对象值转换成UTC(GMT)时间

————-自定义对象—————-
function CallName() {
 alert(this.name);
}
function Card(name,address) {
 this.name = name;
 this.address = address;
 this.CallName = CallName;
}
myCard = new Card("catge","HUST");
myCard.address = "Wuhan";
myCard.CallName();

————-扩展内置对象—————
function saidBy(name) {
 alert(name +":"+ this);
}
String.prototype.saidBy = saidBy;
"hehe".saidBy("catge");

————-with关键字—————–
with关键字指定一个对象,后面大括号中的语句块中没有指定对象的属性都将被假定为该对象属性。例如对字符串lastname而言:
with(lastname) {
 window.alert("length:"+ length);
 capname = toUpperCase();
}

————-for—in循环—————-
for(i in navigator){
 alert(navigator[i]);
}
用来执行对一个对象的每个属性进行运算

————-第三方程序库—————–
Prototype http://prototype.conio.net
Script.aculo.us
SAJAX http://www.modernmethod.com/sajax
Dojo http://www.dojotoolkit.org
Yahoo! UI Library http://developer.yahoo.net/yui
MochiKit http://mochikit.com

————–IE与FF的event属性————
event.button 鼠标左键值为1,右键值为2(event.button左键为0,右键为2)
event.clientX 事件发生位置的x轴坐标(event.pageX元素左上角为基点,而非鼠标实际地点)
event.clientY 事件发生位置的y轴坐标(event.pageY)
event.altkey 表示是否按下了Alt键(event.modifiers表示事件发生时按下了哪个修饰键,返回值为不同键的二进制的组合)
event.ctrlkey 表示是否按下了Ctrl键
event.shiftkey 表示是否按下了Shift键
event.keyCode 所按键的键码(event.which用Unicode表示,可使用String方法转换它)
 Key = String.fromCharCode(event.which)
event.srcElement 元素出现的对象(event.target)

function hover(e) {
if(!e) var e = window.event;
whichlink = (e.target)?e.target.id:e.srcElement.id;

}

————————————————–
1、不能在onload事件处理程序中使用document.write(或document.open)语句,否则会覆盖当前文档
2、添加noscript标签内容,或者为支持javascript的用户添加某些可以继续操作的事件。
3、推荐两款不错的软件:
javascript调试工具
Web Developer(用于Firefox)
http://chrispederick.com/work/web-developer/

IE的Turnabout插件,允许用户对特定网站进行JS脚本订制
http://www.reifysoft.com/turnabout.php

化成天下网首页新增图片随机切换效果

catge Posted in Design,Tags: ,
5

    请先到《化成天下网》首页,观看图片随机切换效果http://hctx.hust.edu.cn/ 。

    实现方法,在你的页面上留出一个id="pic"的容器(div,span,td都行),然后在外加上 这句,以下是该JS源码:

——————–slideimg.js———————–

var imgsrc = new Array();
var imglink = new Array();
var imgalt = new Array();
imgsrc[0] = "http://202.112.28.132/hust/hctx/slideimg/1329.jpg"; //图片地址链接
imgsrc[1] = "http://202.112.28.132/hust/hctx/slideimg/1319.jpg";
imgsrc[2] = "http://202.112.28.132/hust/hctx/slideimg/1309.jpg"; //添加更多图片只需按格式继续增加数组元素

imgalt[0] = "第1329期 郑功成:民生问题与和谐社会"; //对该图片的描述
imgalt[1] = "第1319期 左大培:中国的宏观经济与中美关系(下)";
imgalt[2] = "第1309期 Ray Hiebert:互联网和大众,媒体的未来";

imglink[0] = "http://www.univs.cn/newweb/univs/hust/2007-12-10/805079.html"; //图片点击后的跳转链接地址
imglink[1] = "http://www.univs.cn/newweb/univs/hust/2007-11-19/800535.html";
imglink[2] = "http://www.univs.cn/newweb/univs/hust/2007-10-29/796264.html";

var index = 0; //初始播放图片序号
var duration = 5000; //图片切换时间(毫秒)

var pic = document.getElementById("pic"); //此ID是与页面唯一关联处

function preImg(){
pic.innerHTML = ""; //除掉原来内容
var a = document.createElement("a");
a.setAttribute("href",imglink[index]);
a.setAttribute("title",imgalt[index]);
pic.appendChild(a);
var slideimg = document.createElement("img");
slideimg.setAttribute("src",imgsrc[index]);
a.appendChild(slideimg);
slideimg.style.filter = "revealTrans(duration=1,transition=23)";
setTimeout("nextImg()",duration);
}

function nextImg(){
var img = pic.firstChild.firstChild;
if(img.filters){
img.filters.revealTrans.transition=Math.floor(Math.random()*23);
img.filters.revealTrans.apply();
}
index = (indexpic.firstChild.setAttribute("href",imglink[index]);
pic.firstChild.setAttribute("title",imgalt[index]);
img.setAttribute("src",imgsrc[index]);
if(img.filters) img.filters.revealTrans.play()
setTimeout("nextImg()",duration);
}

preImg();

//代码由catge原创,可随便引用,注明blog:catge.blogbus.com即可 

———————————————————

    考虑到浏览器兼容问题,所以采用了标准的DOM来写这段函数,图像的切换效果是随机生成的。基本思路就是:

1.先去掉id="pic"的容器的原有内容

2.用DOM生成一个子节点a和a的子节点img

3.给a,img设置属性,同时如果支持浏览器滤镜的话会套上filter效果

4.通过setTimeout改变a、img的src、href等属性,同时给支持滤镜的浏览器加上filter效果

这段代码比其他类似代码的优势是:标准化和兼容性

不足的地方有:

1.如何通过后台自动调用前面的几个数组的数据,条件许可的化,后台做比前台JS实现更好。想实现这种功能,至少要让后台多输出几个img到前台来;

2.扩展图片选择功能,比如加几个浮动的小标签在图片上,点“1”就到第一张图片,点“5”就到第五张图片。主要考虑到这样做可能比较依赖页面的样式定义,所以也就暂时没加上这种功能。

3.给非IE浏览器添加更酷的功能。其实这段效果只有IE能显示出来,FIREFOX等浏览器下只是单纯的切换图片而已。考虑到这些浏览器有更强的CSS特性,应该可以做类似的酷炫效果给他们。

————————————————–

12月27日补记:昨天配合后台加上了自动加载图片功能,以后就无需手动修改了。实现方法为:页面上新建一个id为imgurl的隐藏div,从后台输出最近五期人文讲座的数据(图片链接地址,文章标题,链接地址),然后通过本JS进行实现。JS地址已改,上半部分代码改动为:

var index = 0; //初始播放图片序号
var duration = 5000; //图片切换时间(毫秒)
var pic = document.getElementById("pic"); //获取展示图片容器
var imgurl = document.getElementById("imgurl"); //获取包含图片链接信息的容器
var imgsrc = new Array();
var imglink = new Array();
var imgalt = new Array();

function preImg(){
var i = 0;
imgurl = imgurl.innerHTML.split("*");
for(var j=0;j<imgurl.length-1;j=j+3){
imglink[i] = imgurl[j];
imgsrc[i] = imgurl[j+1];
imgalt[i] = imgurl[j+2];
i++;
}
pic.innerHTML = ""; //除掉
var a = document.createElement("a");
a.setAttribute("href",imglink[index]);
a.setAttribute("title",imgalt[index]);
pic.appendChild(a);
var slideimg = document.createElement("img");
slideimg.setAttribute("src",imgsrc[index]);
a.appendChild(slideimg);
slideimg.style.filter = "revealTrans(duration=1,transition=23)";
setTimeout("nextImg()",duration);
}