文章分类 » 课程Online

FireBug和YSlow介绍

注:本文中的所有操作可以随意打开一个网页进行,因为操作都很简单,建议每看一步就实际操作一下,这样还可以发现一些文中没提到的功能。

Firebug是Firefox浏览器最好的插件之一,对于网页开发人员来说是一个利器,能够极大地提升工作效率。当你在浏览网页时,它能使你实时的在任何一个页面上编辑,测试css,DOM,Html,javascript。 Yslow也是Firefox的一个扩展,可以对网站的页面进行分析,并告诉你为了提高网站性能,如何基于某些规则而进行优化。

Firebug窗口预览

firebug-1

运行Firefox浏览器后,按F12键就可启动Firebug。

  • Console标签: 主要使用javascript命令行操作,显示javascript错误信息。
  • HTML标签: 显示HTML源码 CSS标签: 浏览所有已经装入的样式表。
  • Script标签: 显示javascript文件及其所在页面。
  • DOM标签: 显示所有的页面对象和window物体的属性。
  • Net标签: 显示本页面涉及的所有下载,以及它们各自花费的时间,各自的HTTP请求头信 息和服务器响应的头信息。
  • Yslow标签: Yslow工具,安装后就会嵌套在Firebug工具当中随时编辑页面

随时编辑页面

firebug-2

点击窗口上方的“inspect”命令(如图),然后滑动鼠标选择页面中的文本节点,下面的html也会瞬时定位到你选择的节点。你也可以对其进行修改,修改结果会马上反应在页面中。反之亦然,若鼠标停留在下方代码中的某个节点上,页面上也会瞬时显示出该节点的width,border和margin等信息。

firebug-3

Firebug同时是源码浏览器和编辑器。所有HTML、CSS和Javascript文件中的对象,都可以用单击或双击进行编辑。当你输入完毕,浏览器中的页面立刻会发生相应变化,你可以得到瞬时反馈。

用Firebug处理CSS

在CSS标签中,Firebug会自动补全你的输入。在DOM标签中,当你按Tab键时,Firebug会自动补全属性名。

firebug-4

此外,我们还可以利用Firebug来查看某元素的盒模型和其所有的CSS样式。在CSS窗口上方,有一个“布局”按钮,点击后会展示与该元素相关的方块模型,包括padding、margin和border的值。还有一个“计算出的样式”按钮,点击后可以查看该节点的所有CSS样式,在这里我们可以看到我们并没有进行设置而是有浏览器自己默认出来的属性。如下图:

firebug-5

评估下载速度

Net标签中图形化了页面中所有http请求所用的时间。你可以用这项功能评估javascript文件下载,占用整个页面显示的时间。并且可以查看AJAX信息。

firebug-6

Javascript调试

在script标签中,可以查看整个页面的所有javascript代码,并在代码中设置断点进行debug,左上角有下一步和继续等按钮,窗口右侧是代码中变量和一些DOM的值,他们会随着javascript代码的运行而变化,同时debug时如果代码对页面内容或效果作出改变,页面也会作出即使的响应。这个debug过程和codeblock和netbeans等IDE都非常相似而且操作要简单的多。

firebug-7

Firebug控制台使用

控制台(console)非常强大,也是firebug里最重要的面板,主要作用是显示网页加载过程中产生各类信息。

它能列出javascript调用的所有函数,及其所花的时间。对javascript调试非常有用。而且它还提供了一个console对象,我们可以利用这个对象的各种函数来对javascript代码进行测试。给前端开发带来了极大的方便。下面简单介绍下console对象的使用,在javascript代码中加入下列代码。

var dog = {};//声明一个对象
dog.name = "大黄";//为dog对象设定一些属性
dog.color = "黄色";
dog.bark = function(){alert("wa kakaka");};

//分组开始——group console.group("group"); console.log("%o",dog); console.log("%d年%d月%d日",2011,9,17); console.info("this is a %s","info"); console.debug("a debug"); console.error("this is a error"); console.warn("this is a warn"); console.dir(dog); console.groupEnd(); //分组结束

//判断表达式——assert var result = 0; console.assert(result == 1);

//计时功能——time console.time("firsttime"); for(var i = 0;i < 1000;i++) { for(var j = 0;j < 1000;j++){} } console.timeEnd("firsttime");

//创建两个函数foo和foo2 function foo(){ for(var i = 0;i < 1000;i++){ for(var j = 0;j < 30;j++){ foo2();} } } function foo2(){ for(var k = 0;k < 1000;k++){} }

//性能分析器——profile console.profile("性能分析器"); foo(); foo2(); console.profileEnd();

运行之后在firebug控制台可看到下面的效果

firebug-8

试想一下在调试代码的时候,为了方便我们可能想让程序在运行过程中就返回给我们一些变量,好让我们查错。以前很多人都喜欢用alert函数弹出个窗口,现在可以完全用console对象来完成这个功能。

不同的函数用来显示不同类型的信息。如log,info,debug,error,warn分别显示的信息类型都不同;这些函数使用起来没什么区别,都和C语言的printf()函数差不多,但只支持字符(%s)、整数(%d或%i)、浮点数(%f)和对象(%o)这四种占位符。唯一的区别就是在控制台当中显示的样式不一样。

下面看下其他的一些函数,如:

  • console.dir()是用来显示一个对象里所有元素的函数。
  • console.assert(),判断某表达式是否正确,如例子中0==1就是一个错误的表达式,所以会产生一个错误信息,如果表达式是对的就什么也不显示。
  • console.group()和console.groupEnd();这两个函数是一对,分组的意思,如果你在调试代码时想要输出看的东西比较多,就可以用这两个函数来进行分组,其group可带上参数,表示该组的名称。
  • console.time()和console.timeEnd();该函数使用来计算时间的,它会为开发者显示出在这两个函数中间的代码所运行的时间。
  • console.profile()和console.profileEnd();该函数被叫做性能分析器,看运行出来的效果就可知道,它能对夹在两函数中间的函数进行测试,包括被调用次数和运行时间等等。该功能和控制台界面中的概况(profile)按钮的功能是一样的。

控制台和console对象的使用比较复杂,还有用来显示xml代码的dirxml()函数和跟踪函数trace()等等。可参考下面的链接进行详细的学习。 链接:http://www.ruanyifeng.com/blog/2011/03/firebugconsoletutorial.html 上面的代码在文章尾部有相关下载,可下载下来实践一下。

Yslow分析网页性能

Yslow的功能在文章的开始处已经说明。它有四个视图,每个视图都是对整个页面在不同方面的信息显示。

组件视图

该视图中列出了整个页面所加载的所有文件,包括html,css和javascript等。并列出每个文件的详细信息和加载每个文件时的http请求信息等。

yslow-1

统计信息视图

该视图会显示整个页面加载的所有文件的个数和各类文件的大小比例。

yslow-2

等级视图

这个视图是YSlow最让人关注的了,它会根据不同中规则对该页面进行评测并给出相应的分数和等级划分,对做的不好的地方还会给出优化的建议。关于每个规则的说明和优化方法可参考本站的另一篇文章《读书分享:高性能网站建设指南》

yslow-3

工具视图

该视图里提供了一些工具,例如对代码进行压缩等等。

示例代码:下载

读书分享:《高性能网站建设指南》

high-performance-web-sites

同样的网络环境,看着别人的网站“唰”的一下就展现出来,你是否和我一样,心急如焚,盼望着早一点攒出一笔钱,给服务器加点内存?或者你已经挽起袖子,开始研究数据库优化?又或者你在暗自思量着可以把哪些设计模式或编码技巧运用在自己的后台代码里,盼望以此带来性能上的巨幅提升? 哦,别激动,很多时候事情并没有你想象的这么严重。

这是High Performance Web Sites(以下称HPWS)的译者在序中说到的前两段。对于网站的响应速度的优化,后台的优化和硬件的升级往往伴随着很多困难,诸如成本,工作量等。但实际上前台的优化更为重要也更为高效,为什么呢?HPWS中引入了一条性能黄金法则:

只有10%~20%的最终用户响应时间花在了下载HTML上,其余的80%~90%时间花在了下载页面中的所有组件上。

这就是为什么我们要把精力集中到对于前台的优化上。

HPWS中引入了14条可以实施的方案用于优化前台性能,我将逐条说明。

减少HTTP请求

减少HTTP请求的有效方法,HPWS中提供了以下几个方法:

图片地图

对于一个和图片关联在一起的超链接,使用图片地图能够有效减少请求数,因为这样在不改变显示效果的前提下,将很多张图片改为了一张。

CSS Sprites

这种方法类似于图片地图,也是用于合并图片,而且更为灵活

内联图片

这种方法是将小块的图片内联为“立即数”,图片的全部数据就在其URL自身之中

合并脚本和样式表

虽然软件工程师会推荐将代码按照模块化原则分开放在多个小文件中,但这样做会降低性能,因为每个文件都会导致一个额外的HTTP请求,所以合并脚本和样式表也可带来性能的提升。

使用内容发布网络

需要这样做的原因是,当你的用户在地理上分布很广时,你就有必要在多个地理位置不同的服务器上部署内容。所以使用内容发布网络(CDN)能够使HTTP请求响应的时间缩短。CDN是一组分布在多个不同地理位置的Web服务器,用于更有效地向用户发布内容。

添加Expires头

Expiers头用于控制浏览器对于缓存的保存时间。因此这一条规则的含义是为你的页面添加长久的Expires头,这样可以有效地将大部分组件保存在缓存中,这样当用户再次访问页面时,浏览器将使用缓存的图片从而减少了HTTP请求的数量,从而节省了时间。

Expires头在服务器端配置,如Apache中有mod_expires模块。使用与不使用Expires头的HTTP响应将如下所示

不使用Expires头

使用Expires头

两者在YSlow中对Expires的评价中分别得到了F和A(注:YSlow是FireFox下的一款插件,用于对一个网站速度进行多个方面的评价)。可以看到合适的Expires头对于网站速度的重要性。

压缩组件

减少HTTP响应的大小来减少响应时间这一点很容易理解,只传输很少的数据,肯定相应有很少的响应时间。减小响应包大小的方法之一是使用gzip编码来压缩HTTP响应包。当然也有一些其他的方法,但都不如压缩组件来得效果好。

压缩组件的配置同样在服务器端,如Apache的modgzip及moddeflate

组件压缩后将在响应头中有显示:

对于压缩的内容,压缩所有内容在YSlow中得分最高A,不进行压缩将得到D,只压缩HTML将得到C

将样式表放在顶部

CSS样式表对于用户而言并不是最重要的,因此若将CSS样式表放在顶部将会延迟页面中其他重要组件的下载,但实际情况与此相反(请到文章末尾给出的链接中体会)将CSS放在顶部的加载速度快于将CSS放在底部。这是因为放在底部的CSS将会阻塞浏览器对于页面的渲染,因为假如没有得到准确的CSS信息,那么对于页面的呈现就显得是一种浪费,所以为了避免这点,浏览器会等到CSS下载完毕后再呈现页面,这样就导致用户界面很长时间会出现“白屏”的现象。显然这种用户体验是不好的,因此将CSS放在底部,将有助于浏览器逐步呈现页面,而不是给用户一个浏览器假死的现象。

将CSS放在底部

将CSS放在顶部

两种做法在YSlow中分别得到B和A

将脚本放在底部

与CSS样式表类似,脚本也会阻碍页面的逐步呈现,但解决的方法与CSS样式表正相反:将脚本放在底部将加快浏览器的呈现速度。这涉及到浏览器的行为。浏览器在下载组件时,往往采取并行下载多个组件的策略,并行下载数与浏览器相关,但脚本将阻塞并行下载,其中一个原因是,脚本可能使用document.write来修改页面内容,因此浏览器会等待,以确保页面能够恰当地布局,而另一个原因是为了保证脚本能够按照正确的顺序执行。如果并行下载多个脚本,就无法保证响应是按照特定顺序到达浏览器的,这使得脚本的执行顺序不可预知,假如脚本之间有关联,就有可能产生错误。文章后面的链接中有一个例子,从里面可以很明显地看到js脚本是如何阻塞呈现的。

但是对于阻塞并行下载,不同浏览器的行为并不相同,经我们的观察和讨论得出,有些浏览器阻塞的并非是并行下载,而是页面的渲染,但不论如何,这都影响了页面的呈现,所以将脚本放在页面的底部能够加速页面的呈现。

在firefox中js脚本和其他组件也是并行下载的(使用firebug查看)

避免CSS表达式

CSS属性设置中可以接受js表达式,在某些情况下(譬如动态改变样式)非常有用,例如在IE中不支持min-width属性,这样就需要使用CSS表达式来设置使得页面拥有最小宽度。但是浏览器对于CSS表达式的频繁求值会导致CSS表达式的低下性能。在文章末尾提供的链接中的例子可以看到,CSS表达式的求值比想象中要频繁。

需要使用CSS表达式又怕降低性能,解决的方法有两个:一个是使用一次性表达式,在一次执行中重写它自身,这样可以将属性设定为一个确定的值,而避免了表达式的重复求值。

一次性表达式

另一种方法是使用事件处理器,这样已经脱离了CSS表达式的范畴,但使用这种方法也能达到同样的效果,而且不需要频繁求值,即将对表达式的求值与一个事件关联。

事件处理器

将事件与函数相关联

使用外部JavaScript和CSS

使用内联还是外部的js和CSS是一个很基本的问题,在HPWS中的说法是“纯粹而言,使用内联js和CSS更快一些”但是我个人实际的实验却表示使用外部的js和CSS更快,我想着其中很大一部分原因是并行下载,因为内联或者外部,组件的总大小是固定的,而内联将使得并行下载不能,所以反而会降低速度,虽然这样减少了HTTP请求。但实际上当然还是使用外部js和CSS较好,因为这涉及到缓存的问题,外部js和CSS可以保存在缓存中,这样用户下次就不必下载了,内联的文件则不然。

在内联比外部快的前提下,HPWS提出了两全其美的方法:加载后下载,即使用户下载内联文件,但是在页面中加入脚本,使得在用户加载页面结束后开始下载外部的js和CSS,同时还可以再服务器端添加动态内联,判断用户是否有当前组件的缓存,这可以通过cookie实现。

下载后加载的代码:

精简JavaScript

减小HTTP相应包的方法,除了压缩组件之外,精简js也是一个有效的方法,精简的含义是从代码中移除不必要的字符以减小其大小,进而改善加载时间的实践。在代码被精简后,所有的注释以及不必要的空白字符都将被移除。这样可以减小需要下载的js脚本。混淆是可以应用在源代码上的另外一种方式。和精简一样,它也会移除注释和空白,同时它还会改写代码。作为改写的一部分,函数和变量的名字将被转换为更短的字符串,这是的代码更加精炼,也更难阅读。但混淆有可能引入错误,混淆会改变js符号,这些都是混淆带来的风险,所以精简是最常用的方式。

精简后的脚本

混淆后的脚本

并且不要忘记精简CSS脚本

移除重复脚本

重复脚本经常发生,因为不同的团队都会向项目贡献代码,但是他们相互之间可能不知道对方已经包含了自己想要的脚本,这样重复包含就发生了,重复的脚本会增加不必要的HTTP请求,从而损伤性能。解决的方法可以在后台添加一个脚本管理的模块,将已经包含的脚本假如一个列表,每次添加前加以检测,对于已经添加的脚本则不再添加。

配置ETag

ETag的作用于Expires头类似,都是标识了一个组件的缓存时间。不同的是Expires头是通过设置保存时间来设置缓存,而ETag是对一个特定版本的组件产生一个特定字符串,然后在以后的请求中通过比对此字符串来决定是否更新此组件。那么为什么要配置ETag呢,因为ETag通常由组件的某些属性来构造,这些属性相对于特定的、寄宿了网站的服务器来说是唯一的。当浏览器从一台服务器上获取了原始组件之后,又向另外一台不同的服务器发起条件GET请求时,ETag是不会匹配的。因此需要配置ETag的构造方法,使得ETag在不同的服务器上相一致。

ETag举例

使Ajax可缓存

由于Ajax是几种已有技术的组合,因而其优化方法大体可以依照前面的优化方法,如配置缓存,压缩组件,精简脚本,等等。

这就是前台优化的一些策略,每一个都很细节,但就是这些细节决定了页面的呈现速度。在阅读HPWS的过程中,我也不止一次感慨:只有对一种技术了解到细节层面才能称为是专家,大面上的东西很容易就了解了,但关键是能不能深入原理和细节。

相关链接

HPWS一书中各条规则实例

使用Gravatar – 普通用户&开发者

Gravatar是什么

Gravatar是www.gravatar.com 推出的一项服务,意为“全球通用头像”。如果在gravatar上注册了账号并在gravatar服务器上放置了头像,那么当在支持gravatar的blog或留言本上发言时,只要提供email地址,就能够显示与email相关联的头像。这样就为大家提供了一个统一管理多个头像的平台,只要站点支持gravatar,就不必特意为每个站点单独上传头像,省去了麻烦。

普通用户

作为一名普通的用户,如何使用Gravatar呢?

首先到gravatar上注册账号,很简单,只要填写一个常用的email地址,填写好密码,然后到邮箱里确认,就注册好了一个gravatar账号。随后用账号登陆gravatar,就可以开始为账号添加头像了,每个email可以和一个头像关联,上传头像的方式有很多种。

选择一种,并选好准备制作成头像的图片。随后进入编辑界面。

简单编辑后,就截取好了gravatar头像,接下来为头像选择等级,不同的等级会决定你的头像是否在站点中显示,假如你的头像过于限制级,则在不支持此等级的站点中不会显示,而只会显示一个缺省头像。

在这几个步骤之后,就添加好了gravatar头像,接下来进入管理界面。

在此界面下,可以对自己的多个头像和相关联的多个email进行管理。

以上是作为普通用户的gravatar使用方法,对于开发者,gravatar同样提供了一些便利的使用方式来丰富你的站点。

开发者

gravatar不但为普通用户提供了头像解决方案,还为开发者们提供了一些接口,方便开发者调用gravatar头像以及在用户gravatar头像中包含的简单profile。在gravatar首页中可以找到开发者文档的入口,里面有关于如何使用gravatar接口的文档。

最常用的调用方式是通过URL调用头像和用户profile。通过URL调用要经过以下几个步骤Creating the Hash将欲调用的用户的email字符串去掉空格,并将所有字母转换为小写,最后将其转换为md5码,以php语言为例:

接下来便可利用得到的字符串构造URL来调用gravatar中的头像了。简单调用,将得到的hash后的字符加在http://www.gravatar.com/avatar/之后,再将其写到<img>标签的src属性中,便可以调用了。如hash后得到的字符串为205e460b479e2e5b48aec07710c08d51,便可按以上方法调用为:

文件格式:如果需要文件的格式,也可以在后面加上后缀,如’.jpg’。在调用的时候,也可以进行一些简单的参数设置,如大小,缺省等。

图像大小:在URL后添加 ?s=(或?size=) 一个整数,便会返回一个指定大小(长宽一样)的图像。

缺省头像:当由于头像分级或未设置头像而无法显示时,可以设置一个缺省头像.设置缺省头像使用的是 ?d= 参数,既可以使用gravatar提供的几种参数,也可以链接到其他URL指向的图片,但要经过urlencode()函数的编码。如:echo urlencode( ‘http://example.com/images/avatar.jpg’ )这样便可将缺省头像指向一个URL。

还有一些其他的参数设置,如强制缺省,制定分级,详细内容请参考官方文档。注册gravatar时还会填写一些个人信息(邮箱,个人主页等)这些信息也可以通过gravatar URL来调用。方法也是先将email hash一下,然后加在http://www.gravatar.com/之后,注意,和调用头像不同,向这一URL发送请求,返回信息就包含着profile中的信息。

这样就得到了全部的profile信息,profile中包含若干键值对,其中键为信息的标题(姓名,电话等),值为信息的内容。 除此之外,gravatar还有远程调用的接口,用于在用户认证的基础上,修改用户gravatar账户中的信息,由于并不常用,所以不再赘述,有兴趣可以参考官方文档。

总之,gravatar的出现对于普通用户来说,提供了一个管理头像平台,能够为用户节省精力,对于开发者来说,在自己的站点中引入gravatar也能够为自己的网站增色不少。

参考资料

Ajax简介 – 异步交互

主讲人朱玺
题目Ajax简介 – 异步交互
时间2011-5-8
 相关下载

简单介绍

Ajax——“Asynchronous JavaScript and XML”(异步JavaScript和XML)…看上去很抽象吧。 还是再介绍介绍JavaScript和XML吧。

  • JavaScript:是一种脚本语言,结构简单,使用方便,其代码可以直接放入HTML文档中,可以直接在支持JavaScript的浏览器中运行.——总而言之就是一种在客户端运行的语言。
  • XML:可扩展标记语言,Xml是Internet环境中跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有力工具。——原来是处理信息用的。

Ajax是干什么的?

通过 AJAX,您的 JavaScript 可使用 JavaScript 的 XMLHttpRequest 对象来直接与服务器进行通信。通过这个对象,您的 JavaScript 可在不重载页面的情况与 Web 服务器交换数据。即实现网页与服务器的异步通信功能。

而传统网页同步处理请求的方法是用户触发一个HTTP请求到服务器,服务器对其进行处理后再返回一个新的HTHL页到客户端——用户每次都要浪费时间和带宽去重新读取整个页面。造成的结果是在网速较低或需要传输的页面较大的情况下原页面会锁死。大大降低用户的浏览体验。

对比传统网页交换数据的方法使Ajax技术拥有两大优点:

  • 可以像桌面应用程序只同服务器进行数据层面的交换,减轻服务器负担,缩短了用户等候时间。
  • 加快了页面的相应速度,大大提高了页面的交互性。使因特网应用程序更小、更快,更友好。

原理图解

传统网页交互方式

页面直接与服务器交换数据,两次user activity之间的世界就是用户页面锁死的时间。

Sync Request

通过Ajax技术的交互方式

Ajax技术在用户页面和服务器之间加入了一个中间层(Ajax engine),用户提出的请求先提交到中间层,中间层再分析用户提交的请求后确定向服务器提交的请求。最后根据服务器返回的数据通过JavaScript实时将结果显示到用户页面上。——以上的数据交换都是在中间层上完成的,所以不会造成整个页面的锁死。加强了用户体验。

Async Request

Ajax小应用

Ajax Demo Show

具体实现

  • 文件组成:有3个文件index.htm ajax.js 和 telltimeXML.php 组成。
  • 核心部件:其中的关键就在于ajax.js文件里的XMLHttpRequest 对象。

XMLHttpRequest对象的属性和方法见文末的附录

我们来重点分析一下ajax.js文件中 getServerTime() 和 useHttpResponse()两个函数。

最前面的getXMLHTTPRequest()函数是针对不同浏览器来建立 XMLHttpRequest 对象,有兴趣的童鞋可以自行google其中的奥妙。

先来看 getServerTime()

var myurl = “telltimeXML.php”; var myRand = parseInt(Math.random() * 999999999); var modurl = myurl + “?rand=” + myRand;

这里构造了一个open函数里的url参数,即Ajax需要发出的服务器请求。这里使用了一Math.random()具体作用后面会再做介绍。

http.open(“GET”, modurl, true);

设定对服务器请求的一些参数:请求类型GET, url:为前面生成,true:异步传输数据。

http.onreadystatechange = useHttpResponse;

设定当readyState 属性改变时,就调用 useHttpResponse() 函数。这里作一下说明,readyState 属性是根据XMLHttpRequest 对服务器请求的不同状态而自动发生变化。具体可参见对readyState 属性的介绍。

http.send(null);

最后发送请求就可以了。

然后来看 useHttpResponse() 函数对readyState 属性改变时所做出的相应。

我的代码是对readyState == 4 和 status == 200 同时成立时(即一般情况下Ajax对服务器请求完成,且服务器返回相应已就绪)对服务器返回的responseXML(包含服务器时间信息)进行处理,并利用javascript对网页进行修改,做到无刷新的数据交换。

在其他情况下就显示一个Loading…表示网页正在后台与服务器交换信息。

Ajax的几个缺陷

缓存

由于 XMLHttpRequest 对象是通过url来对服务器进行请求的,这就不可避免的与浏览器的缓存机制产生了冲突。简单的说,由于服务器端的信息可能是时刻改变的,浏览器缓存则是以url为标准记录缓存。当通过同一url访问服务器时,可能服务器端的数据已经改变,而浏览器却只是读取了本地缓存,而使在网页上显示的信息和在服务器上的信息不一致。造成问题。所以在getServerTime() 函数中我使用了一个Math.random()函数来使每次请求的url不一致,来欺骗浏览器,使其不读取缓存。在讨论中段哥也提到了这个问题,并指出这个方法并不科学,因为random()函数也有小概率产生同样的url同样可能造成问题。现在正确的做法是先读取服务器端返回的状态,若为304则表明服务器端数据未修改,则可以直接读取缓存,否则需从服务器端重新读取信息。

历史

由于Ajax对网页进行的是实时改变,并不改变网页的url,所以会导致浏览器没有办法记录访问地址,并且无法与好友分享网页上的信息。

谢谢大家耐心阅读。

相关下载

附录

参考文章:Ajax初步

在此摘录XMLHttpRequest对象的一些属性和方法。

如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:

open(method,url,async)   method:请求的类型;GET 或 POST
                    url:文件在服务器上的位置
                    async:true(异步)或 false(同步)
send(string)            string:post请求中所要传输的数据。
onreadystatechange      存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState          存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
                    0: 请求未初始化
                    1: 服务器连接已建立
                    2: 请求已接收
                    3: 请求处理中
                    4: 请求已完成,且响应已就绪
status              返回的服务器状态,一般正常的话为200。
responseText            获得字符串形式的响应数据。
responseXML         获得 XML 形式的响应数据。

使用不定个数的参数构造查询字符串

寒假开始制作Cyber-Reader写CDB类库的时候,就有一个查询是要求写出一个,具有可变参数个数的函数,类似于sprintf,fsql定义了数据格式,v1, v2等变量定义了要替换的值,然后将替换后的字符串作为数据库查询进行执行.

这个东西我纠结了好久,也想了不少方法,最后因为开学了没有写完,里面不少东西都是老段完成的.现在说说关于这个查询时遇到的问题和解决的方案.

先举一个实现后的例子:

这其实就是一个select语句,其中不同的地方就是第一个参数中的name的值%s用后面的’glove’来替换,site的值%s用后面的’glovely.info’来替换,这些可以替换的参数是不限定个数的. 也就是说这个函数像我们用的sprintf一样,是带有不定个数的参数的.

最初我的想法是得到用户的输入,将其传递给sprintf,这样变将要赋值的参数通过sprintf完成,然后最后得到的结果便是我们要执行的mysql命令.下面是实现的方法.

实例1:

mysql命令 return $result; if(is_bool($result)) return $result; else return mysql_fetch_array($result); //根据所得值是bool还是array来确定不同的返回值类型. } ?>

虽然有部分命令可以执行,但这显然不是一个很好的办法,毕竟这里要求的功能不是和sprintf一模一样的.

下面便是我们现在的CDB类库中使用的queryf. 它的思路:

得到输入的命令,通过判断其中%的位置和数量,来找到要传入的数据类型和数据个数,并进行相应的错误判断. 实例2:

<?php const NUM = ‘d’; const STR = ‘s’; const RAW = ‘r’; const ESC = ‘%’;

function queryf() { $args = funcgetargs(); //获得输入的命令 if( ($argCount = count($args)) == 0 ) //检查命令长度是否为0 return false; $format = $args[0]; //命令的第一部分 $argpos = 1; $escpos = false; $vpos = 0; $sql = ”; while(true) { $escpos = strpos($format, CDB::ESC, $vpos); //查找符号”%”在字符串$format中出现的位置,偏移量为$vpost,初始为0. if($escpos === false) //第一次查找%位置时$escpos的值应该是false { $sql .= substr($format, $vpos); //找到字符串$format中初始位置到$vpost字符并存入$sql中 break; } $sql .= substr($format, $vpos, $escpos – $vpos); //将%之间的字符串存入 $escpos++; //用来保存匹配到%的位置,这里加一用于下面的比较操作 $vpos = $escpos + 1; //$vpos的位置在$escpos的后一位 if($escpos == strlen($format)) //如果esc的位置等于$format的长度,则返回false,及%后无类型字符 {// % 后面没有类型字符 return false; } $vchar = $format{$escpos}; //$format中的第esc个字符 if($vchar != CDB::ESC) { if($argCount <= $argpos) {// 参数个数不够 return false; } $arg = $args[$argpos++]; } switch($vchar){ //判断%后的字符是什么,即我们要替换什么类型的数据 case CDB::NUM: $sql .= intval($arg); break; case CDB::STR: $sql .= $this->escape($arg); break; case CDB::RAW: $sql .= $arg; break; case CDB::ESC: $sql .= CDB::ESC; break; default: //非法的符号 return false; } } $rs = $this->query($sql); if(isbool($rs)) //判断最后结果的类型 { return $rs; } else { $r = array(); while( ($row = mysqlfetcharray($rs)) ) $r[] = $row; return $r; } } ?>

WordPress插件制作简介

第二次分享会详情

主讲人田大龙
题目WordPress插件开发
时间2011-4-24
 下载课件

————-华丽的分割线————-

这里并没有手把手教你制作一个插件出来,本篇文章意在向大家介绍WordPress插件制作的基本步骤以及需要了解的必要知识,详细的WP插件制作教程网上有很多,本文最后也推荐了一些比较好的教程网站。

OK,言归正传.

1:介绍

简单定义: WordPress插件是一个能够扩展WordPress博客功能的PHP脚本程序或函数集。 目的是为了使WordPress变得扩展性强,易修改和个性化。而且不需要修改WordPress的核心代码。

2:新建一个插件

2.1 名字,文件,位置

2.1.1 插件名 因为一个网站上可能会装很多个WordPress插件,所以要确保插件名字的唯一性。

2.1.2 插件文件 新建一个文件夹,将你插件的文件放入/wp-content/plugins/中,当然这个目录的名字也要唯一。

2.1.3 Readme 文件 无论是插件还是其他什么应用程序,README都是必不可少的。

2.1.4 主页

如果想制作一个较好的插件,最好为它设置一个主页,介绍关于插件的版本信息,使用说明等内容。

2.2 头信息

2.2.1 标准插件信息

需要在PHP头部插入标准的插件信息,WordPress才能识别你的插件。

形式如下:

[coolcode lang=”php”] /* Plugin Name: Name Of The Plugin Plugin URI: http://URIOfPageDescribingPluginandUpdates Description: A brief description of the Plugin. Version: The Plugin’s Version Number, e.g.: 1.0 Author: Name Of The Plugin Author Author URI: http://URIOfThePluginAuthor */ [/coolcode]

最主要的是Plugin Name,WordPress主要是识别它来显示出一个插件。

2.2.2 授权信息

通常大家就直接用标准的授权信息当作自己的授权信息。很多的插件用得就是GPL。加入下面的文字,

可以简要的说明GPL:

[coolcode lang=”php”]/* Copyright Glove glovenone@gmail.com */[/coolcode]

2.3 开始编程

2.3.1 WordPress插件钩子

API:Application Programming Interface 应用编程接口。

wordpress插件主要使用一种叫hook的接口:

A.动作 (Action): 动作是 WordPress 运行到某些环节,或者在某些事件发生时,就会被执行的一种钩子。比如说发表一篇文章、更换主题或者访问后台的某个管理界面,这些都是一件事件的例子。而插件则可以指定某些 PHP 函数来响应这些事件

使用动作来挂载插件的基本步骤如下:

在插件代码中定义当某个事件发生时,需要执行的 PHP 函数用add_action() 把这个函数注册到动作执行挂勾上把插件源码放到 WordPress 指定的地方,然后启用它

添加一个filter的格式为:

[coolcode lang=”php”]addaction ( ‘hookname’, ‘yourfunctionname’, [priority], [accepted_args] );[/coolcode]

例子:

当访客访问站点后,执行的是index.php,即WordPress的入口程序。index.php先后载入一些基本参数(如数据库信息、默认语言),进行一些必要的检查(如WordPress是否已经安装),然后载入我们的插件,当然,前提是这个插件已经启用。在插件中,我们输入以下代码:

[coolcode lang=”php”] function printmyfeed(){ //do something echo ‘Hello, boy!’; } addaction(‘wphead’,’printmyfeed’); [/coolcode]

如代码所示,wphead就是一个Action名,当WordPress执行到wphead这个Action时,它将执行我们插入的printmyfeed函数。这里的函数既可以做某些后台的操作,如update_option,也可以用于前台的输出,如echo,做一些适合在该Action发生的动作。

B.过滤器 (filter):是WordPress加载的,当文本被存入数据库或发送到浏览器之前,filter可用来对其进行多种类型的处理。使用filter,你的插件可以使用定义在其中的PHP函数来对文本进行多种处理。

添加一个filter的格式为:

[coolcode lang=”php”]addfilter(‘hookname’,’yourfilter’,[priority],[acceptedargs]);[/coolcode]

例子:

[coolcode lang=”php”] function addContent($content = “”) { //the content we modified $data = ‘the data we added’; $content .= $data; //add the data to the content originally return $content; } addfilter(“thecontent”, addContent); [/coolcode]

调用add_filter函数时,必须在数据显示、保存等操作之前进行.

2.3.2 保存插件数据到数据库

WordPress有多种方法将插件数据保存到数据表,我们既可以创建新的数据表,也可以用post_meta对单独文章、页面、附件等相关数据进行处理,也可以用“option”,这会是一个很常用的东西。

2.3.3 WordPress的option机制

WordPress有一套在数据库中保存、更改、读取独立的、有名字的数据(”options”)的机制,安装WP后,如果访问数据库,会发现里面有一个叫wp_option的数据表,它保存的内容就是有关我们博客的一些信息:地址,站点名称,文章属性等内容。我们可以通过调用option函数对数据库进行相关的添加、获取、更新等功能。

2.4  i18n你的插件
一个很有意思的词:i18n—internationalization,国际化的缩写,之所以如此缩写是因为从i到n有18个字母,它意指让我们的插件能够在世界上使用,即可以被翻译成各国语言。我们需要在定义字符串和输出字符串时做一些操作。

3:插件开发建议

  • 要遵循标准,统一标准可以给自己和他人同时带来方便,“WordPress Coding Stardards”。
  • 函数不要重名,否则可能会造成混乱,通常加一个不会重复的前缀就好了。
  • 代码中不要把WordPress前缀写成“wp_”,要写成$wpdb->prefix,虽然它们的意思相同。
  • 为了提高你插件的效率和可用性,尽量减少向数据写东西的次数,并且只“Select”你需要的字段。不要用“Select *”这样的语句,这种插件会让你WP的速度变慢很多。

4:相关资源

  1. wordpress官方API
  2. WordPress插件制作入门教程
  3. 自己动手写 WordPress 插件
  4. WordPress教程网 – WordPress插件的各种信息,也有关于wordpress其他的信息
  5. WordPress插件介绍
  6. 帕兰映像 – 不仅有WP的东西,是一个一个关于web的很不错的网站

浅谈jQuery

jQuery Icon

第一次分享会开始,第一次分享的是表面上的东西。这里所说的表面上的东西并不是指十分浅显的东西,而是直接与用户交互的那一部分。我们重点来说一说JavaScript的一个比较流行的库——jQuery。

JavaScript和HTML还有CSS一样,都是下载到用户本地,由用户的浏览器进行解释和执行的。

1、jQuery是什么

刚才已经说过了,它是一个JavaScript的库。这些库被用来简化JavaScript的开发,利用这些库,可以降低开发人员JavaScript的技术门槛,使用一些简单的方法实现高兼容性,高移植性的功能。比如对于初学者来说,难以写出同时兼容IE,Firefox,Chrome,Opera的JavaScript代码来,因为需要考虑的方面比较多。但是利用第三方库,这些兼容性问题就可以忽略掉了。说着说着感觉有点像Java的样子。

第三方库是怎么个作用呢?打个比方吧。比如说你想吃饺子,就得活面,做饺子馅,然后包饺子,再煮饺子。经过了这么多过程才终于可以吃了。库呢,就是把活面,做馅,包饺子这些过程全都交给一个包饺子机去做。你只要把原料放到里面,一按按钮,饺子就出来了。生活一下子就简单了!

除了jQuery,还有其他一些比较优秀的JavaScript库。例如Prototype,YUI,MooTools等等。其中Prototype是最早成型的JavaScript库之一,因为成型年代比较早,对面向对象的编程思想把握不是很到位,所以结构比较松散,现在似乎在慢慢改进,仍旧有一些网站使用这个库。

YUI是由Yahoo公司开发的JavaScript工具集,封装了一系列比较丰富的功能。现在和大龙在做的Moodle开发中,其中的JavaScript库使用的便是YUI。看过YUI2的部分文档,YUI2虽然封装了很多工具,但是使用上还是不够方便,有很多类似JavaScript的原始方法。YUI3作出了很大改进,向着简单易用的方向,改善了许多。

jQuery如此流行的原因就是因为它简单易用,容易上手。拥有轻量级的库,强大的选择器,出色的DOM操作,各种事件处理,兼容性解决方案等等特性。

jQuery强调的理念是写得少,做得多。虚的东西不多说了,咱们主要是分享经验,不是给jQuery做广告。

2、代码示例

点我穿越

一般来说,一个button的点击不会出现任何效果。但是可以利用JavaScript来控制它的点击效果。比如,我点这个按钮,浏览器就显示出个OK。再点一下又出来个OK。这都是浏览器解释出来的,并没有写到html文档中。我再刷新一下这个页面,这些OK就消失了。

$(),美元符号,这个是jQuery的工厂函数。能做选择器来用,也能用来创建节点。示例代码中的$(“button”)就是选中下面文档里<button></button>这个节点。同理,$(“#box”)是选中ID为box的节点。这里括号里面的选择方法和CSS是一样的。Click还有append就是jQuery的一系列方法中的两个。前者是监测点击事件,后者是用来向HTML中添加字符串或者各种元素。

这里说到了节点,为什么说成是节点,我们往下看。

3、jQuery对象 VS DOM对象

初次接触jQuery,经常分不清jQuery对象和DOM对象。冷不丁写出来一段代码,很有可能就不知道用什么方法来进行下一步。对用惯了JavaScript直接编码的人来说,这种障碍可能更大一些。初学者直接跨过JavaScript而是用jQuery的话,也需要对这两个对象深入理解才能进行更深入的学习。

什么是DOM?英文全称是Document Object Model,即文档对象模型。每一份DOM都可以表示成一棵树。树中的每个节点都是DOM元素节点。通过JavaScript方法获得的DOM元素就是DOM对象。而通过jQuery选择器取得的DOM元素,是对DOM对象进行的一个包装,此时得到的就是jQuery对象。对于jQuery对象,就可以使用相应的jQuery方法。

DOM对象,jQuery对象,我想了很久,想到一个比较形象的比喻可以解释他们的关系。想在用户交互界面实现一个功能,可以使用JavaScript方法操作DOM,也可以使用jQuery方法来操作DOM实现同样的功能。这就像是煮饭。有米有水,一个人选择生火用大锅煮饭,另一个人选择用电饭锅来煮。这两个人呢相当于不同的选择器;使用的灶台大铁锅,或者是电饭锅就是不同的封装;灶台点火,电饭锅插电,这就是两种不同方法。当然最后的结果都是生米煮成熟饭。而灶台不能插电,电饭锅不能点火,两种不同的对象不能使用此对象不存在的方法。不知道说清楚了没有,大家还要自己主动去研究研究理解理解。

分清DOM对象和jQuery对象对以后的使用会有很大帮助。DOM对象和jQuery对象之间还可以进行转换,这里就不详细介绍了,很简单。

4、DOM操作

DOM操作是JavaScript控制里最常用的操作之一。做前端,那必然会对页面显示的样式做各种各样的控制。这就离不开DOM操作。我将示例代码1做了一点点小修改,于是就诞生了示例代码2。我当时学jQuery的时候基本就是这样一点点研究这东西怎么用的。其实特别容易上手,有一些地方跟Java的语法比较像。

示例代码1里面已经提到了DOM的选择器以及向文档中插入文本。插入节点也是同样的道理,只要把文本换成HTML代码就是了。插入这个节点以后呢,DOM那棵树里面就多了一个节点。

看代码示例2,点我穿越。这段代码比示例代码1多了一个变量,用于标记一下是第几次点击。JavaScript中的变量是用var来声明的,和PHP中的变量类似,也是弱类型的,随着使用,可以随时将它的类型改变成需要的类型。然后,我每点击一次 “It works!”,就向id为box的盒中的ul节点下面添加li节点。这就是基本的向DOM中添加节点的方法。很简单,和添加字符串一样。Append方法和appendTo方法,这俩挺有意思。这个我就不说了,你们如果有兴趣研究jQuery的话,查文档的时候就能看到,然后实际编码实现一下就知道怎么回事了。

既然有创建和添加节点,那肯定有删除节点对吧。删除一个节点是使用remove方法。$(“#box”).remove();只要执行这一句,ID为box的节点就被删除了。我在给Cybery Reader添加Ajax效果的时候我就想,用户点击一个订阅源,我要把中间的内容清空,然后显示这个订阅源下的文章。然后呢,我就用了remove()方法。结果发现,整个盒都被删了。难道我还得新建一个盒?然后我就把删掉的盒子又用前面创建节点的方法添加回去了……再把订阅源中的文章添加到这个节点下。想想这种方法挺对的是吧?

我就想,我这办法也太闹心了吧,就没有个简单点的办法?后来我翻了一下方法列表,给找到了。清空节点中的内容可以使用empty方法,empty方法只清除当前选中元素的子元素。我们试一下,在代码示例2里面,给$(“#box ul”)对象添加一个empty()方法是什么效果。注意,jQuery支持方法的连接操作。用“.”将一个jQuery对象要执行的方法依次连接起来,执行的时候浏览器就会按照方法连接的顺序依次执行。

DOM操作中还有属性操作,样式操作以及文本操作。以Cybery Readeractions.js中的代码为例说明一下属性操作的方法attr()。Attr()接收两个参数,第一个参数是属性名称,第二个参数是属性的值,这两个参数都是字符串。如果只有一个参数,返回值是DOM元素中这个属性的值。如果再加上第二个参数,则把第一个参数指定的属性的值设置为第二个参数的值。例如actions.js第100行这段代码里面。首先取src属性的值,判断一下它是什么,然后108行和116行就是对这个属性进行修改。

样式操作、设置和获取HTML、文本的示例可以参考jQuery手册,不外乎使用几个方法,可能对一些值进行转换,也是比较简单的内容。不再举例了。

5、事件绑定

看代码示例3,点我穿越。一般的理解,我点击“伤不起有木有!”以后呢,这个列表中会再添加一个“伤不起”的项。这都没问题。我点新添加的“伤不起”,看看会不会再向列表中添加一个“伤不起”呢?

啊哦,一点反应都没有。这是为什么呢?因为新添加的节点对于浏览器来说是一个全新的对象,而脚本中并没有给这个新对象绑定任何动作。就好象我新买个电饭锅放家里,但是不插电,那它就永远无法工作。

给这段代码加一点小改进,就可以让新建元素工作了。看代码示例4,点我穿越,用count变量记录添加节点的顺序,为每个节点制定一个ID,然后新建节点以后用选择器选取此ID的节点,为它绑定一个click事件。这样就可以工作了。看看效果。我再点击“伤不起”的时候,这个伤不起的后面就出现了“有木有!”。有木有!有木有!

在一个jQuery对象后面加上.click这样就给这个对象绑定了click事件。还可以显示地使用bind(“click”, function(){…})来绑定click事件。如果想要取消绑定,可以使用unbind方法。

6、Ajax

Ajax全称Asynchronous JavaScript and XML,即异步JavaScript和XML。具体的技术细节这里就不研究了,直接说说jQuery中Ajax的使用。第一次作业里有的同学使用的iframe方法在当前页面载入其他页面的内容。有兴趣可以换成Ajax方法试试。

最简单的是load()方法了,这个方法有3个参数,url, data, callback。其中后两个参数都是可选参数。url参数是请求HTML页面的URL地址,data是发送至服务器的数据,callback是请求完成时的回调函数,无论请求成功或失败都会执行这个函数。

看下一个代码示例,点我穿越。看这段代码能不能大致了解一下我要做什么?点击”It works!”,然后向服务器发出GET请求,获取test.html页面。把这个页面中的内容添加到box中。

Load()方法通常用来从Web服务器上获取静态的数据文件,但是在实际项目中,总是需要给服务器传递一些参数。或许只是悄悄地上传一些数据,并不涉及到DOM操作。这时就可以使用$.post()和$.get()方法了。

看一下Cybery Reader中的Feed列表。这里面每一项都是一个链接,理论上我点击这个链接页面会跳转到链接制定的页面。但是我点一下,它为什么没有跳转呢?在click事件的function函数的最后打一行return false,这样就阻止了页面的跳转。并且使用POST方式向服务器发送了这个链接。

$.get()方法使用GET方法来进行异步请求,$.post()方法使用POST方式来进行异步请求。参数有url,data,callback,type。比load()方法多了一个type,表示服务器端返回内容的格式,包括XML,HTML,Json等。使用这两种方法能够显示地表现出用何种方式来进行异步请求。以actions.js中的代码来解释$.post方法的使用。40行使用Ajax动态添加评论。请求的页面是/comment/,发送的数据是comment。试着发送一条评论,看看Firebug上监视到的结果,结合我们这个callback function就知道这里是如何工作的了。$.get()方法与$.post()方法使用上完全相同。

Ajax就说到这里不再深入了。有兴趣的话,可以继续研究如何使用XML或者JSON来传送数据。

7、没讲到的东西

动画没有讲,这部分我用到的不是很多,感觉和事件处理也十分相似,看看jQuery文档就能知道个大概。

表单、表格的操作没有说。这个和DOM的属性操作很像。

XML、JSON会在Ajax中有涉及。XML就是另一种文档格式了,十分强大,在很多地方都用得上。已经超出今天的范围了,有兴趣的到图书馆借本书看看。或者查在线文档。JSON这个用得比较多,也是用来传递大块数据的。比如你的PHP脚本想要和JS脚本进行数组的传递,用JSON就很方便。

各种细节问题。单纯分享经验嘛,细节问题就不讨论了,不然就变成讲课了。其实说着说着已经变成jQuery快速入门了。快餐一般都没营养,想吃点好的,多看书多研究吧!

8、示例代码目录

Reset CSS的前生今世

存在即合理。那么Reset CSS从无到有,到底有神马用处呢?

1. 先来说说Reset CSS的由来

话说很早很早以前,傲来国海外的一座岛上有一块石头……不对不对,那是西游记……

重来。

话说大伙儿还在中学埋头啃书的时候,即不远不近的2004年,一个专注于Web标准的帅哥Tantek被CSS的浏览器兼容问题搞烦了,他苦恼于各种浏览器自定标准,于是就想自己统一一下CSS以方便使用,于是乎就产生了undohtml.css

所以说,Reset CSS存在的理由,就是因为它消除了不同浏览器对HTML元素的默认CSS解释的差异性。比如 <ul></ul> 在IE6-8和FF下默认的缩进就不一样。

IE6-8中是margin-left:40px;padding-left:0,而FF中是margin-left:0;padding-left:40px

2. Reset CSS的工作原理

其实Reset CSS的工作原理非常之简单啦。

就是写一个reset.css文件,在里面将HTML元素的一些style定义一次,然后在网页中引入这个reset.css文件就可以了。

有了这个reset.css,各个浏览器在解析CSS的时候就会遵循reset.css中统一的style定义,于是这个世界就清净了。

3. 实现方式

具体的实现方式请移步:打造自己的reset.css,作者写得非常好,我就不做重复性的劳动了。

这里给出YUI的reset.css让大家先睹为快吧:

body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td { margin:0; padding:0; } table { border-collapse:collapse; border-spacing:0; } fieldset,img { border:0; } address,caption,cite,code,dfn,em,strong,th,var { font-style:normal; font-weight:normal; } ol,ul { list-style:none; } caption,th { text-align:left; } h1,h2,h3,h4,h5,h6 { font-size:100%; font-weight:normal; } q:before,q:after { content:”; } abbr,acronym { border:0; }

4. 其他的声音

什么东西使用过度都是不对的。

对于Reset CSS的使用也有了很多反对的声音。

比如”打造自己的reset.css“的作者自己后来又写了一篇文章:”真的还需要reset.css么?“。

其实到底用不用Reset CSS,也是个见仁见智的问题,不能一概而论。

NB的Eric对于反对使用Reset CSS的回应是:

Because this isn’t a field of straightforward answers and universal solutions.We are often faced with problems that have multiple solutions, none of them perfect.

To understand what makes each solution imperfect and to know which of them is the best choice in the situation—that’s knowing your craft.

That’s being a craftsman/craftswoman. It’s a never-ending process that is all the more critical precisely because it is never-ending.

我个人的意见是:

  • 新手请用reset.css。优点是消除学习初期很多你觉得莫名其妙的bug,可以让你专注于你学习的东西而不是成天debug;缺点是没有这些debug的工作,你会少学很多知识。不过总的来说学习是个循序渐进的过程,所以还是推荐新手使用 reset.css。
  • 老手就不要直接使用reset.css了,而是应该直接根据项目的需要,设定好全局的CSS。

那么你对Reset CSS的看法是什么呢?用,还是不用?或者怎样使用呢?

欢迎大家发表自己意见 & 贴出自己使用的reset.css~

原文地址:http://www.fancycedar.info/2011/04/reset-css/

从CSS看浏览器的兼容性

访问量大了,用什么浏览器的鸟都有,用什么鸟浏览器的都有。

现在的浏览器种类太多,版本太多。而且每个种类的各个版本,都有用户在使用。

不要让用户产生疑惑:咦,这个网站怎么在公司电脑上看着挺好的,回家了看就乱七八糟的呢?

想让所有用户都能没有障碍地看到和分享你的劳动成果?那就提高你网站的浏览器兼容性吧!那就让你的网页在各个浏览器下都能呈现出相同的表现和行为!

(更多…)

PureWeber首批主题开放下载

前几天已经放出了截图,今天开放下载了。

小雨同学作品:7Honeycomb

酷酷的Android风格的主题,甚至连小雨同学的妈妈都赞不绝口。显然,这是一款老少咸宜的主题。

咸鱼同学作品:Cybery Cool

好吧,我承认,这个主题是我设计的,看起来还是挺不错的,清爽简洁,不是吗?(轻点拍砖好不好)

手套同学作品:Glovely

这个主题从里到外都散发着那么一股子文艺青年的味道。好吧,glove,我承认,你比我们都文艺。