文章分类 » 心得与总结

ORM到底是用还是不用?

ORM即Object/Relation Mapping的简写,一般称作“对象关系映射”,在Web开发中最常出没于和关系型数据库交互的地方。接口、中间件、库、包,你都可以这么称呼它。

我们可以结合PHP和MySQL,从ORM的四个核心理念来认识它:

  • 简单:ORM以最基本的形式建模数据。比如ORM会将MySQL的一张表映射成一个PHP类(模型),表的字段就是这个类的成员变量
  • 精确:ORM使所有的MySQL数据表都按照统一的标准精确地映射成PHP类,使系统在代码层面保持准确统一
  • 易懂:ORM使数据库结构文档化。比如MySQL数据库就被ORM转换为了PHP程序员可以读懂的PHP类,PHP程序员可以只把注意力放在他擅长的PHP层面(当然能够熟练掌握MySQL更好)
  • 易用:ORM的避免了不规范、冗余、风格不统一的SQL语句,可以避免很多人为Bug,方便编码风格的统一和后期维护

接下来再通过一个很基本的例子来说明一下ORM的使用,还以PHP和MySQL为例。

user这个数据模型是再普遍不过的了。假设我们有一张user数据表,结构如图:

在OOP中通常我们需要写一个对应的class User来作为user数据表的数据模型:

// 声明class User
class User{
    $id;
    $name;

    function create(){/*...*/}
    function load($id){/*...*/}
}

// 使用class User
$user = new User();
$user->name = 'fancy';
$user->create();

但是通过ORM,我们可以不用去声明class User,可以直接继承ORM提供的工厂类,比如:

// 直接使用!对于熟悉MVC的亲知道这个意义之所在!
$user = new ORM('user');  // ORM都有自己的规则,这里直接使用了MySQL的表名
$user->name = 'fancy';    // MySQL的表的字段就是$user对象的成员变量
$user->save();            // 掉用ORM提供的接口函数

ORM一般都针对数据模型提供了一下常见的接口函数,比如:create(), update(), save(), load(), find(), find_all(), where()等,也就是讲sql查询全部封装成了编程语言中的函数,通过函数的链式组合生成最终的SQL语句。

所以由这些来看,ORM对于敏捷开发和团队合作开发来说,好处是非常非常大的。这里就罗列一下我想到的ORM显著的优点

  • 大大缩短了程序员的编码时间,减少甚至免除了对Model的编码
  • 良好的数据库操作接口,使编码难度降低,使团队成员的代码变得简洁易读、风格统一
  • 动态的数据表映射,在数据表结构甚至数据库发生改变时,减少了相应的代码修改
  • 减少了程序员对数据库的学习成本
  • 可以很方便地引入数据缓存之类的附加功能

但是ORM并不是一个完美的东西,它同时也有其自身不可避免的缺点

  • 自动化进行关系数据库的映射需要消耗系统性能。其实这里的性能消耗还好啦,一般来说都可以忽略之,特别是有cacha存在的时候
  • 在处理多表联查、where条件复杂之类的查询时,ORM的语法会变得复杂且猥琐
  • 越是功能强大的ORM越是消耗内存,因为一个ORM Object会带有很多成员变量和成员函数。有一次修复bug时就遇见,使用ORM查询的时候会占用12MB的内存,而使用SQL的查询时只占用了1.7MB……

ORM就是这么一个让人又爱又恨的东西。回到我们开始的问题:“ORM到底是用还是不用?”。

Fancy个人的观点是:ORM要用!但关键部位不能用!

因为对于一般的Web应用开发来说,使用ORM确实能带来上述的诸多好处,而且在大部分情况下涉及不到ORM的不好的地方。但是在系统里面有大数据量、大运算量、复杂查询的地方,就不要用ORM。ORM的性能问题将给你带来灾难。在这些地方就可以使用纯SQL或者其他简单轻量的DB Helper库了。在详细了解ORM之后,你就可以扬长避短让ORM发挥其最大效用了。

原文链接: http://www.fancycedar.info/2013/01/orm/

提高代码质量之代码审查

写代码是一种创造性的劳动,是现在社会中少数的纯手工的工作之一。程序员就像手工艺人,代码就像手工艺品。手工艺品有自己独特的魅力,但是也缺乏流水线产品的严谨和一致性。所以代码审查(Code Review)就像是把玩鉴赏手工艺品一样,通过审查代码来体会编码者的思维逻辑,同时相互学习取长补短。代码审查是提高个人和团队的代码质量的一个很有用的方法。

个人对自己的代码可以进行代码审查,因为今天的你已经不是昨天的你,你可以站在不同的角度和不同的层次来审查自己过去的代码。子曰:温故而知新。所以对于自己的代码应该定期做Code Review。可以用好日程安排工具,比如Google Calendar之类。在自己做到觉得需要日后来审查一下的地方,就可以在日程安排上记录一笔。到时候就可以按照记录去审查了。作为一个想不断进取和自我提高的程序员来说,这是很高效的方法。

自己的代码审查很好进行,只要你有毅力。相比之下团队的代码审查就不是那么容易实施了。但是代码审查在团队中能体现出更大的促进作用。除了可以让团队成员之间相互学习进步、激发思考、统一编程风格之外,代码审查还能发现一些系统的潜在问题和QA测试不到的问题,从而提高代码质量。

但是在团队内进行代码审核的时候,也要注意方式方法,才能发挥其积极作用。否则还有可能产生负面的影响。

1. 引导团队成员对代码审核的正确认识

代码审核并非是给某人挑错,也不是瞻仰膜拜牛人的奇技淫巧,而是大家泡一杯咖啡端一杯茶,一起来鉴赏品玩代码而已。目的是为了促进团队成员的成长和提高。

如果在代码审查的时候发现bug,不要过于责问,而是应该从技术层面加以分析、建议和讨论。如果你是Manager, 一定要注意不要炫耀自己,低调一点,重点在做好组织工作。初期一定要引导好团队成员对代码审核的认识,不要变成个人代码秀或者挑错大会和批斗大会了。

2. 要让团队成员看到代码审查的好处

在组织Code Review的初期,一定要用心去挖掘一些可以让大家学到东西的代码段。让大家体会到,可以从别人严谨的逻辑和优雅的编码学习经验技术,也可以从自己和别人的脏代码以及疏忽大意来吸取教训。尝到了甜头,这么有好处有意思的事情,大家肯定乐意再来一次了。

3. 平等轻松的纯技术讨论

在做代码审查的时候,只能有组织者,不能有CTO、Manager、权威、叫兽砖家。这是一个平等的轻松的技术讨论会,可以佐以饮品和零食哈哈~要激励大家勇敢地说出自己的看法,置疑其他人的看法。这样才能激发出大家的参与热情和不断地思考。这种讨论其实就是一种头脑风暴。

4. 针对项目的热点和难点进行代码审查

针对一次代码审查进行选题的时候,可以多从项目的热点和难点入手,比如框架是怎么工作的?数据库是怎么封装的?缓存是怎么处理的?内存占用高的地方是怎么优化的?一些复杂的算法是怎么实现的?某个bug为什么会反复出现?————走进科学将带你走进代码审查的世界~~哈哈回到正题,代码审查的选题一定要对事不对人。记住!要避免针对某个程序员的代码审核。。。除非你想炒了他。

5. 少而精

代码审查是一项很激烈的脑力运动,而且在多人参与的时候尤其如此。和头脑风暴的本质差不多。不但自己要理清别人的代码,还要去审视和判断,还要说出自己和看法,还要听懂别人说出的看法。所以每次代码审查的内容和时间要少而精,否则大家疲劳之后,讨论就会变得冗余而无趣。

6. 发现问题由编码者自己去修正或者重写

当我们在审查时发现了问题、讨论了修正和改进的方案,我们肯定需要一个人来讲这些方案实现出来。这个时候就应该由造成问题的程序员来做了。因为只有真实去改动代码的时候,才会将问题最真实的原因暴露出来。这个程序员才能去彻底修复这个bug。同时在他也会从自己的错误中得到提高,在之后的职业生涯中应该不会再犯同样的错误。

7. 做好讨论记录和问题跟踪

在大家的思想相互撞击的时候肯定会有很多灵光闪呀闪,如果不记录下来就太可惜了,丧失了讨论的意义。所以每次代码审查一定要有专人来负责做记录。讨论之后将记录整理并email给所有人。

PM和Manager之类的就可以根据讨论记录来分配改进任务。每个团队都应该有自己的项目管理系统,或者说是bug追踪系统吧。如果没有,赶紧去搞一个。推荐开源的Redmine (Ruby on Rails)Mantis (PHP/MySQL),以及提供在线服务的Lighthouse

特别要说一下Redmine,支持中文,功能强大且简洁,跨平台使用很舒服,而且也支持多种数据库(MySQL, PostgreSQL or SQLite),同时可以和git集成使用(在git push时自动更新ticket状态)。

8. 使用适合自己团队的代码审查工具

现在很多团队都转向了使用GIT,那么就可以利用Github来作为代码审查的工具。在Github里面可以针对某个branch的某个commit提交评论,然后Github会给项目的参与者发送一封邮件。通过这种在线的评论来进行代码审查,让大家可以利用零散时间去看一些小的代码段,就像在论坛发帖回帖一样,不用一定要坐在一起,不会打断正常的工作,同时也完整地保留了讨论的过程。如果是个人或者小团队,不想开源自己的代码的话,也可以利用Bitbucket来建立私有库托管代码和进行代码审查。

总之

XXXX是一把双刃剑,代码审查也是如此。 进行代码审查对于组织者的能力要求比较高,要多思考和调整,激发大家一起来做好代码审查,发挥其最有益的效用。

对提高团队代码质量的些许愚见

做开发总是避免不了和Bug打交道。自从第一只真正的Bug被发现以后,Bug就像幽灵一样时刻伴随着软件开发。

Bug是不可避免的,这个是真理。听说有人写书叫”零Bug编程指南”,真是牛逼之极。莫非他是上帝?其实上帝也是会写出Bug的程序员,所以各个物种都在不断打补丁进化中。

虽然Bug不可避免,但是我们可以提高代码质量降低Bug出现的几率。代码也有熵的特质,特别是在现在多人多团队合作开发的情景里面,需要采取很多策略来提高代码质量。

首先对于团队来说,我觉得可以通过如下一些方式来提高代码质量:

一、最根本也是第一步要做的就是,在设计系统架构阶段就需要充分地考虑系统的可扩展性、模块的高聚合性以及接口灵活易用的性。要做到这一点,就和对需求的分析、系统的了解和经验有很大关系了,需要长期的积累和经常对架构的思考与实践。交给团队里面最牛逼的一个人去主导,比较牛逼的几人参与讨论来做这一步吧。

二、选用一个适合需求的开发框架,会让你事倍功半。PHP的框架有很多,各自有各自的特性和优劣,可以比较选择。Python的tornado在做Web应用的时候比较方便。同样前段也需要代码框架的支持,Javascript中jQuery能胜任大多数项目,HTML和CSS可以尝试使用Twitter的Bootstrap。使用框架对代码的健壮性有帮助吗?当然有!因为框架封装实现很多常用的功能,这样我们自己的代码量会大大减少。直观一点讲,代码量少了,bug自然就少了。其实最重要的是代码量少了,程序的逻辑和结构会更加清晰,从而减少Bug的出现。

三、多人协作需要良好的代码管理工具。SVN可以考虑淘汰了,用分布式的GIT。

四、团队还需要统一的开发环境。包括统一的编码规范、统一的语言版本、统一的编辑器配置(tab和空格之类)、统一的文件编码,统一的数据库等等。这样可以完全避免因为环境不同而导致的Bug。

五、较优秀的程序员应该负责较初级的程序员的代码质量,定期对初级程序员的代码进行review。同时团队内部应该有针对性对一些比较复杂或者变态的部分进行code review。

六、对于系统的破窗和肿瘤,要适时适量地清除,绝对不能放任不管。

后面的几点就是针对个人了。想要提高代码质量,对程序员个人的专业素质就要有高的要求。大到模块的划分和实现,小到变量的命名等,都能体现出一个程序员的专业素质。

一、类名函数名变量名有简洁有意义,复杂难懂的地方要给出详细的注释。

二、对代码进行合理的封装和复用。不要有过多的重复代码,也不要过度封装和过度面向对象。如果一部分功能代码出现了第二次,就应该思考可否提取成一个公共的方法。如果出现第三次,就应该警觉了。同时也要多利用数组和链表,不要什么数据都做成对象。

三、严禁太深的嵌套,算法复杂度会较高,同事也严禁过多的if else,这样会使程序员头晕的。

四、对数组下标要小心检查,不要越界。

五、个人要自律要按照大家约定的习惯和代码风格编码。这样有利于代码层面的交流,方面相互复用代码和修改代码。

六、逻辑复杂的地方先画图设计,再编码。

七、控制代码文件的长度。。。太长了只能割了。

八、预见性的编码,考虑更多的输入情况和容错,做到宽进严出。

当然,在提高代码质量的环节里,测试部门是不可或缺的:

一、尽量部署自动化测试,用手动测试去弥补自动化测试的不足。

二、QA应该对每个developer有一张反馈表,记录dev容易犯错或者忽略的地方,定期反馈。

要提高代码质量,团队和个人都需要努力。一旦团队磨合好了之后,代码质量在不断的迭代开发中也能得到保障。但提高代码质量也不是一朝一夕的事情,需要长期实行,定期反馈修正才可以长治久安。

个人知识管理(PKM)简介

知识工作者

指那些主要工作内容为处理信息和知识,并在工作中利用信息和知识的人。(由管理学大师彼得·德鲁克最早提出)

如果你是一名知识工作者,那么请继续阅读这篇文章,因为它将告诉你如何管理好自己的知识。

PKM

什么是PKM?

PKM = Personal Knowledge Management(个人知识管理)。在企业中,各个团队会有自己的KM(Knowledge Management)。

PKM有五大核心内容:

  • 学习知识
  • 保存知识
  • 共享知识
  • 利用知识
  • 创新知识

一、学习知识

在学习知识之前,我们首先要搞清楚学什么,确定自己的学习方向。如今知识大爆炸,全世界每天出版的书籍超过4000种,面对汪洋的知识海洋,而我们每个人一天只有24小时,我们还要吃饭、睡觉,还要孝敬老人、教育孩子,还要用心经营爱情、维护朋友,还要……

要学的知识太多,怎么办呢?

1.做减法———聚焦

我们的兴趣要远远大于我们的能力和时间约束。所以我们在确定自己的方向时,在你众多的兴趣中,我们必须做减法:聚焦。

首先你需要在一个细分的领域达到专家的水平,这个聚焦越细越好。

2.专注擅长的

传统的教育告诉我们什么差补什么,这个在基础教育阶段是没错的。可是如果你一辈子都在关注自己的短处,都在补自己的最差的部分,那么我们将郁闷一生,因为我们永远看到的都是自己的最差的地方。最多也就是:差的部分:50——>70分(普通)还不如好的部分:70——>90分(专家)。

如果你不知道你擅长什么,那么可以采用“求求你表扬我”这个方法来发现自己擅长的。

3.专注喜欢的

“如果你们和我有任何不同的话,那就是我每天起床后都有机会做我最爱做的事,天天如此。” ———— 巴菲特

选择权在我们自己的手里,我们可以选择自己的道路,那么干嘛不选择一个你喜欢的东西去学习?

“每天都能学习自己喜欢的东西,就如同天天能跟心爱的人在一起,同样幸福快乐。”———— KJlmfe

对于学习的知识,我们要学习到什么程度呢?

菜鸟学到80%就飞走了,这80%恰恰是这个行业和领域的人都知道的。我们需要做的就是在80%的基础上,再多增加一点。

学习的路线:菜鸟——>坚持——>深入——>专家

怎样学习呢?

我相信,找书自学是学习知识的好方法,同时,把题从头到尾做一遍是很好的自学方法。

如果你正在学习编程语言,那么我推荐你一字不漏的把一本书上的代码都敲一遍。

二、保存知识

  • 看看自己的电脑桌面,是不是像猪窝一样乱啊?
  • Oh,My God! 我U盘丢了,我要“火”了!
  • 咦?那个xxx文件放到哪里去了呢?
  • 我勒个去,硬盘被我不小心格式化了,我那上G的资料啊!
  • ……

上面的情况,你是不是勾起了你曾经的记忆呢?

保存知识有三个原则:

  • 周期性整理(安排到自己的GTD系统里)
  • 合理分类(根据类型、时间等)
  • 数据在云端(不怕丢)

保存知识的工具

  • Evernote——笔记本
  • Dropbox——文件
  • Picasa(Google+)——照片
  • Google Docs——文档、演示文稿、电子表格
  • Chrome——网站收藏
  • Gmail——邮件保存
  • GitHub(Bitbucket)——代码
  • Google Reader——资讯订阅
  • Read IT Later——深入阅读
  • 豆瓣——书籍、电影、音乐
  • Blog——个人品牌
  • Wiki——团队知识传承
  • 纸和笔——最便捷、最实在的保存工具

三、共享知识

咱们先来看一个插叙

知识的分类

  • 显性知识:能够用语言、文字、肢体等方式表达清楚的知识
  • 隐形知识:虽然知道如何去做、但却很难告诉别人或者写明白、说明白(有点像茶壶里煮饺子,倒不出来的感觉)

绝大多数人知识现状

  • 知道的 > 能说出来的 > 能写出来的(213青年)
  • 隐性知识 > 显性知识(普通青年)
  • 书不尽言,言不尽意(文艺青年)

三句话阐述的是同一个意思,那么如何将隐性知识显性化呢?

插叙结束

为什么要共享知识?

知识工作者不能做“隐士”,你不能“我觉得怎么样”,而应该让别人觉得你怎么样,你应该通过共享知识形成别人对你的认识,控制别人对你的感觉,而不是一副高高在上,牛气十足的面孔,这样的人将十分可憎而非可爱。

任何人都有区别于他人的优势,你怎么突出自己的优势、特点和能力,怎么让更多的人知道你、了解你、认识你、信任你,方法就是共享你的知识,通过知识影响别人。

你现在阅读我的这篇文章,其实就是我在向你做知识共享工作,你通过这篇文章,大致了解了PKM,同时从字里行间中,你对我也有了一点了解。

知识共享的好处

  • 共享带来合作(故事一
  • 共享协助找到工作(故事二
  • 共享出来才能真正掌握(共享知识的过程,本质上就是隐形知识显性化的过程,)
  • 结实高质量的朋友(他人通过你的共享内容,发现与你有共同的兴趣点)
  • 建立个人品牌的最简单方式(共享知识好比在给自己做广告,例如:Matrix67 阮一峰 陈浩 刘未鹏

没有了解,交流、合作的机会就会很低。谁能主动地共享知识,让别人去了解自己,谁就占据了竞争的优势,在同样的条件下获得更多的机会。

共享途径

  • Facebook
  • Google+
  • 人人网
  • Twitter
  • 新浪微博
  • 豆瓣
  • Blog
  • Email
  • 分享会
  • 出书

四、使用知识

此处略去512字……

五、创新知识

推荐工具:思维导图

推荐阅读

OpenGL与分形几何

开场白

今天跟大家做的这个分享会跟以往不同,今天我不跟大家讲技术。以我现在的功力,不具备什么特殊的技术,都是花拳绣腿,都是基本功,无非就是CSS HTML什么的,尤其今天学长们都在下面坐着,对他们来说我讲这些东西就好比回忆儿时的经历,我说我讲技术,那属于不知好歹。

事实上我原打算真就是讲个什么什么技术的了,尤其在听过上几次的分享会,更觉得理所当然应该讲个什么技术。不过上个星期段哥放出来的话,迫使我不得不改变我原来的策略。所以我不讲技术,你看我多坦诚。

今天的思路是这样的,题目是“OpenGL-分行几何-非线性科学”,以这三个东西为主线,讲述我这一学期的关于他们的经历,在讲述的过程中,我会顺便跟大家分享一下我对他们的看法和理解。我不给你们讲课,我讲故事。

那我们开始吧:

第一部分 – OpenGL

事情发生在七个月之前,也就是上学期的中下旬。创新研修大家都知道吧。我那时点正,抢上了最后一个,就是苏小红老师的自然景物与分型艺术的那个课。隔壁寝室的仁哥也选上了,那时候还没有分寝室,后来分完寝室我们就在一个寝室了。两天之后苏老师召集我们十个人讲了一下上课的要求还有作业的事,当时也没全来,要求很简单,来不来都行,作业呢就是交个大纲上要求的程序就可以合格了。后来经过七个月的心理准备,终于在上周我跟仁哥开始了这项任务。开始的时候一看大纲当时仁哥就急了:“这咋办?下周就要交作业了,咋办交不交?”,我说那怎么办也不能不交作业啊,再毕不了业,那不就严重了么,那实在不行就得我来呗。于是我俩分工很快就明确了,我负责写代码,他负责审阅我的代码。

我当时在机房犯愁老半天,这一学期的课,一周时间我怎么才能把它编出来?那没办法,整不出来你也得整啊,一步一步走呗。于是我就开始在网上搜OpenGL,这个东西怎么用,当时不知道OpenGL具体是什么,就知道用它能做这个程序。看了好半天,稍微有点那个意思,当时在网上讲OpenGL提的最多的就是说OpenGL是个“状态机”,这也是我第一次听见这个名词。什么是状态机呢?我当时翻了不少技术科普的博客。我现在听到状态机这个词,脑海里浮现出来的是一个类似流程图一样画面,每一个方框都是这个状态机,它按照连线的指示,从哪里走到哪里然后又走到哪里。一个状态机,我给它一个指令,他会从一个坐标移动到另一个坐标,这样不同的指令会让他做不同的事,但最终的目的是让他走到另一个状态。对OpenGL它来说,状态就是当时它的复杂的状态,比如说现在已经准备好了要画点了啊,比如说现在已经准备好颜色了啊,就等着你下指令了,你一发出画图的箭头我就会画这个颜色…;而指令就是他自带的函数,就像是操纵杆,你可以通过这些操纵杆来控制这台机器向左走还是向右走。这个状态机像是一个机器人,机器嘛,你来控制它怎么走,来改变状态。在我看来,说白了就是一个大的全局变量,一个全局的节点,一个全局的对象,你通过他的成员函数,来该操纵它只不过改变的是状态。它有记忆的能力,能够记住自己当前的状态。它可以接收输入,根据输入的内容和自己的当前的状态,修改自己的状态,并且可以得到输出。我们的电脑就是一个状态机,典型的状态机。

(打开终端,进入目录,vi源代码)

这就是我写出来的代码,当时看书的时候,对这句话特别感兴趣:

(对下面四行代码用p命令跟其他代码分开来,然后Shift+v高亮显示)

glBegin(GL_POINTS); glColor3us(red[i][j], green[i][j], blue[i][j]); glVertex2d(x, y); glEnd();

这四行代码,第一句这个说的是,下面我要画点的方式是GLPOINTS模式的,就是说画出来的是一个一个单点,不连线也不什么的。这个值是个宏,是系统自带的。如果你选别的,你指定了几个点,OpenGL可能就会把这几个点连成一条折线,或者是连成一个多边形。第二句话,说的是设置点的颜色,参数就是我们常说的RGB。这里有件事很有意思,我不知道是不是别的语言也有过这样的类似的措施,就是你看函数名这后面这个后缀那个3us,我一直觉这个语言这个地方设计得很有意思,3代表参数的个数,us代表参数的类型,比如说如果我把3us改成2sd这个函数那我就得给他传两个参数,而且这两个参数都得是double,这个d,就是double的意思,要是8f就得添八个float变量,酱紫。第三刚也是,你看我用2d我这儿就两个参数吧,这两个参数声明的时候都是double类型。这个函数画出一个点,坐标值是x y,我们现在看到的画布是这样分割的,零零点在中间,从左到右是负一到正一,从上到下也是,不过这个无所谓,这都可以改。你看到我把中间这两句话都缩进了,他们是四个函数,我为什么要把他们俩缩进了呢?按理说这四句话是四个并列的函数,我不应该给他们俩缩进。当时也是看书上在这个地方缩进了,在书上看例子的时候,就这句话一下子让我明白它这个OpenGL了是怎么工作的。第一句glBegin(GLPOINTS);这个操作让他进入画点的准备状态,接下来两句话是进行画点,最后画点结束,退出状态,这就好像一个机器人,你让他到秋林,就必须首先让它走到西大桥,然后才能让他往左拐进屋买东西,如果它还没有走到西大桥,往左拐就不一定到哪了,而且去秋林卖完东西还要回来c。这就是所谓状态机原理,语句不是线性执行的,他们是有先后条件的,是有关系的。同样还有这段:

(在代码里找到下面三句用p命令跟其他代码分开来,然后Shift+v高亮显示)

glutDisplayFunc(&display); glutMouseFunc(&mouse); glutMainLoop();

前两句话的参数都是函数的地址,其实这前两句话都是对第三句话的设置,第三句话叫做主循环,第一句说的是如果在主循环里要显示图片,那么就掉用&display所指向的函数来显示,而第二句是说,若在主循环内发生鼠标事件,则调用&mouse所指向的函数处理。这就是这个自动机的工作方式。另外鼠标时间我比较感兴趣,以前老听别人说鼠标事件鼠标时间,不是很理解,这回我就真切的体验了一回,他试着样的。所谓鼠标事件就是鼠标在窗口上点击,这里说的点击包括左键右键而且还包括滚轮的上下滚动,如果说事件的话,那它应该还包括你在这个窗口内的移动等等所有的只要是在这个窗口里的,鼠标的动作,都叫鼠标时间。在这个窗口里的所有的鼠标的动作,也就是鼠标事件,都会被当成参数传给这个mouse函数,那这些动作是怎么传给函数的呢?我觉得这就是大多数语言实现鼠标动作捕捉的方法。在OpenGL里是这样的,任何一个鼠标动作都会被解释成为数,传给负责处理的函数。每发生一次鼠标事件,都会调用一次鼠标函数,而一种动作对应一个数。比如说:

(在鼠标函数添加一句话,修改成这样:)

/* mouse: display the 坐标 you clicked void mouse(int button, int state, int x, int y) { printf(“x:%d y:%d button:%d state:%dn”, x, y, button, state); // 添加这句话 julia(x, y); return; }

(编译运行,在出现的画布上来回左击右击,滚轮上下翻动,在右侧的命令行上会输出相应的参数,下面讲解参数 )

那,现在你就明白了,鼠标事件怎么是实现的呢,其实就是用一组数来代表一种事件,一个事件就对应一个数,这样来区分和表示,标志事件。现在我在画布上点击和移动滚轮,你们可以在运行终端看到一行一行的输出,这些输出是我刚才添在mouse函数里面的,在每次调用画图函数之前,都会将接收的参数输出来看看。现在我们重来,一个一个分析。

现在我按下左键,你看右面,它的button参数是0,看来在这里左键用来代表。他输出的是两行说明这个mouse函数调用了两次,可我只按了一次,可见按下与弹起都是鼠标事件,每次都掉用一次mouse函数,state参数就是这个相关的数值,按下的时候是0,弹起的时候他为1,这就是一次点击。

(右键按下弹起)

同样试一下右键。看来它用2来代表右键。

接下来我们看滚轮的动作是如何表示的。

(滚轮向上一次再换个位置向下一次)

然后我们看看滚轮动作他是怎么解释的。我现在就向上翻滚轮,你们可以看到它是用3来代表向上的滚轮。同样下翻,发现它使用4来代表向下的滚轮。这样一来就可以解释滚轮的动作了。

那,这就是鼠标事件了,这确实是一个捕捉事件的好方法,起码在我第一次接触鼠标事件的时候我是这样感觉的。

第二部分 – 分形

OpenGL就现说到这吧,这是OpenGL刚刚会始,然后蛋疼的是后头,当我看这个教材的时候我越看越觉得心跳加速,分型几何学这一章涉及到欧氏几何,拓扑几何学,复变函数,仿射变换,微积分,线性数学,形式语言与子自动机…,尼玛这些都是各个数学专业的看家神课啊!不过好在看进去之后还有点点明白。用到的知识倒不是很多,不过这个过程也告诉我了一件事,那就是无论什么都会涉及到数学,多复杂的数学都能用的上,幸运的是数学并不复杂,我想到大一的时候我们工数老师李冬松说过,“我们上大学的时候我们老师就跟我们说过这样一句话,我非常同意他的观点,他说数学不能复杂,数学是吃苹果,分鸭梨,吃出来的学问,他怎么能复杂呢?”,他还说过:“一本书,你要看他符号特多,名词都不认识,跟牛津辞典那么厚,你别怕,这本书很容易,她之所以用那么多名词,引用那么多符号只是为了让话更简洁,其实用大白话也能说明白,就是说得比较费劲,往往你要把他的概念能弄懂,那这本书你基本就学完了,因为这种学问本来也没什么内容,你要面临的主要困难就是那些概念和符号,其实他们之间的逻辑极其直白,极其简单。而如果你看见一本书它说的每句话你都能看懂,尤其是还就薄薄几百页,那这本书你不用看了,你没点学问是看不懂的,你比如说费马定理,都能听懂吧,小学生都能明白。这种东西你别碰,几百年都没人能学明白。”。我当时就觉得冬松简直太有道了,说得太有道理了,我现在就是这种情况,只要你脚一沾水,这汤浑水就开始沉淀了,就从你看第一句话开始,这门学问就在以一个稳恒的速度澄清。那我们现在来说说这个分形究竟是什么。

事情缘起于一次英国海岸线的测量,当时人们对它的测量发现,如果我换一个精确一点的尺来测量那么它的长度会稍微大一些,这很好理解,因为海岸线是弯的嘛,如果用精度更高一些的尺来测量肯定就会更接近于真实值,随着尺度的减小测量值会趋于海岸线的真实值。于是随着人们更精确的测量,海岸线的测量值确实在一点一点的增大,增大的幅度也一点一点的在减小,但是计算结果发现,海岸线的长度并没有收敛于一个常数值,增长确实在变得缓慢,但是他的增长没有停止,他的趋近值是正无穷。这让全世界震惊了。提出这个问题的人就是我们分型的鼻祖–曼德勃罗(B.B.Mandelbrot)。最后得出的是一个戏剧性的结果:英国海岸线的长度是不确定的!后来,分形几何学就以此展开了。

分形这个东西最令我感兴趣的是他的维度,他不是一个整数的整数的维度,你比如说一个正方形,你可以所他是二维的,一个正方体你可以说他是三维的,但是一个典型分形的维度往往不是整数的,比如Koch曲线就是1.2几维的,还不是个有理数,它是无理数。正常来说我们的维度怎么确定?假设有一根单位长度为一维的线段L 若将它的边长扩大到原来的3倍,则可得到3个原始对象(单位长度为A),也就是 3*L=3^2*L 再看二维的情况,二维平面上一个边长为单位长度的正方形P. 若将其边长扩大到原来的3倍,则可得到9个正方形,既有: 9*P=3^2*P

对于三维空间中的一个边长为单位一的正方体V,若将其边长扩大到原来的三倍,则可得到27个立方体,即有:s7*V=3^2*V。按照这个规律有这样一个关系,维数D个放大倍数B相乘就是放大的倍数,两边取对数变形为D = lnM / lnB。这是从放大(或者说‘填充’)的角度看问题,还可以从他的反面即细分(或者说“铺砌”)的角度去看。设N为每一步细分的数目,S为细分时缩放的倍数,则分数维度D可以定义为:D = lnN / ln(1/S)。现在我们来计算刚才说过的Koch曲线。

给定线段AB,Koch曲线可以由以下步骤生成:
将线段分成三等份(AC,CD,DB)
以CD为底,向外(内外随意)画一个等边三角形DMC
将线段CD移去
分别对AC,CM,MD,DB重复1~3。

就是说它每一步细分线段的个数为4,而细分时缩放的倍数为1/3,因此,Koch曲线的分数维为:D = ln4 / ln3 = 1.2619...。如果按照欧氏几何的方法,将一条线段四等分,则 N=4,S=1/4,D=1

那接下来就是Mandelbrot集合和Julia集合。这两个集合都是在基于同一个复变函数:f(z) = z^2 + c。只不过屏幕上没一点对应的参数不一样。Mandelbrot是这样的,像素上每一个点对应的是函数里面的c,而Julia集,每个像素对应的是一个z0,就是z的初始值。上面这个函数,在无穷迭代的过程中,z的情况是我们感兴趣的,初始条件的不同也就死Z0的不同,以及c值额不同,会造成z的变化情况趋向于三个极端,一种是z越变与大,也就是他的模越变越大没有上界,一种情况是,他的模越编越小,最终趋于零,还有一种情况是随着他不断的自我迭代,z的模会进行一个周期的变化,有上界和下界。在计算机中,只会生成发散和收敛两种情况,然而我们却能看到中间那种情况,因为发散和收敛的点画出来的中间的边界就是这种情况。接下来的问题就是怎么判定他的颜色呢,怎么规定它的颜色。教材上的方法是通过设置最大迭代次数N和判断收敛于发散用的阀值M里对屏幕上的点进行着色。就是说对那些迭代N次,而z的模认为超过阀值M,则认为z是受脸的;反之若迭代k次之后,z的模就开始大于M了,那么就判定他是发散的,然后根据这个k值来定义他的颜色,不同的公式会画出来不同的颜色,我自己在试颜色的时候就感觉老过瘾了…。最终确定这个颜色比较好看:

red[i][j] = exp(k); blue[i][j] = sin(k); green[i][j] = k * k * k + k * k + k;

这需要一点想象力,但关键是运气。结果出来的图像就是这样的了:

当时写的第一个程序是这样的,首次运行会给你显示一个Mandelbrot集,然后你用鼠标在任意位置点击(左右键都可以,滚轮也可以),就会生成这一点对应的Julia集。代码在这里:

/****************************************************************** * 用复迭代方法程序设计实现不同参数条件下的Mandelbrot集绘制 * * 并通过鼠标选择Mandelbrot集上的指定的点来画出相应的Julia集图形 * ******************************************************************/

include

include

include

define MAX 700

define M 1024 * 1024 * 1024

define N 255

int red[MAX][MAX]; int green[MAX][MAX]; int blue[MAX][MAX]; int r[MAX][MAX]; int g[MAX][MAX]; int b[MAX][MAX];

void display(void); void compute(void); void julia(int , int); void mouse(int, int, int, int); void set(int, int, int);

/**************************************** * * * 计数单位: * * i from 0 to MAX * * j from 0 to MAX * * * * 画布坐标: * * x = -1 + i / (MAX / 2) * * y = 1 – j / (MAX / 2) * * * * 复平面坐标: * * a = -2.25 + i / (MAX / 3) * * b = 1.5 – j / (MAX / 3) * * * ****************************************/ main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(10, 10); glutInitWindowSize(MAX, MAX); glutCreateWindow(“OpenGL”); compute(); glutDisplayFunc(&display); glutMouseFunc(&mouse); glutMainLoop(); return 0; }

/* display: 显示 */ void display(void) { int i, j; double x, y; glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < MAX; ++i) for (j = 0; j < MAX; ++j) { x = -1 + (double)i / (MAX / 2); y = 1 – (double)j / (MAX / 2); glBegin(GL_POINTS); glColor3us(red[i][j], green[i][j], blue[i][j]); glVertex2d(x, y); glEnd(); } glFlush(); }

/* compute: 计算逃逸次数k ,并将其传递给set函数写入颜色索引 */ void compute(void) { int i, j, k; double a, b, real, imag, real2, imag2;

for (i = 0; i < MAX; ++i) for (j = 0; j < MAX; ++j) { /* 一个 c 对应一个屏幕上一个点; step = 3 / (MAX – 1) */ a = -2.25 + (double)i / ((MAX – 1) / 3); b = 1.5 – (double)j / ((MAX – 1) / 3); real = 0; imag = 0; for (k = 0; k < N; ++k) { real2 = real * real – imag * imag + a; imag2 = 2 * real * imag + b; real = real2; imag = imag2; if (real * real + imag * imag > M) { set(i, j, k); break; } } } return; }

/* set: set color at red[] green[] blue[] */ void set(int i, int j, int k) { red[i][j] = exp(k); blue[i][j] = 0; green[i][j] = k * k * k + k * k + k; return; }

/* mouse: display the 坐标 you clicked */ void mouse(int button, int state, int x, int y) { printf(“x:%d y:%d button:%d state:%dn”, x, y, button, state); julia(x, y); return; }

/* julia: compute the julia set based on the point you have clicked */ void julia(int a, int b) { int i, j, k; double p, q, d, x, y, x2, y2, xy2;

p = -2.25 + (double)a / (MAX / 3); q = 1.5 – (double)b / (MAX / 3); for (i = 0; i < MAX; ++i) for (j = 0; j < MAX; ++j) { red[i][j] = 0; green[i][j] = 0; blue[i][j] = 0; }

for (i = 0; i < MAX; ++i) for (j = 0; j < MAX; ++j) { /* 一个初始值对应屏幕上一个点; step = d */ d = 3.0 / (MAX – 1); x = -1.5 + (double)i * d; y = -1.5 + (double)j * d; for (k = 0; k < N; ++k) { x2 = x * x; y2 = y * y; xy2 = x * y * 2; x = x2 – y2 + p; y = xy2 + q; if (x2 + y2 > M) { set(i, j, k); break; } } } display(); return; }

就这样,我玩了好半天。这里面是有规律的,当你的初始z0值选在M集的中心这个空洞的时候也就是收敛区域的时候,它形成的Julia集是一个闭合环形,书上叫他拟圆,当你选的点恰到好处,他会形成一个真的圆,但通常是扁的。

当你选的是这个桃心外面的点,他生成的Julia集是形如树脂那种东西,书上叫他“发状”分支。

而有意思的是在他们的边界,也就是桃心的轮廓上,它形成的Julia集是菜花状的。

第三部分 – 非线性科学

这就是这两个集合,然后咱么上升到哲学层次,其实大自然到处都是分形,雪花,树叶,我们的大脑,到处都是非线性现象,然而我们只会解决线性问题,什么是线性?什么是非线性?当时我们老师讲微分方程的时候是这样说的,他在黑板上写,说到“y=kx,这就是线性的,我们会且仅会解决线性问题,什么是非线性问题?y=x^2,这就是非线性问题,高难课题。”。事实却是如此,我想到我小学学加法的时候,我们是用小棒来模拟运算过程的,你右手拿两根小棒,左手拿三根小棒,然后你把左右手的小棒放在一起,你可以从一开始数,一直数到最后一根小棒,结果是5,那么就解决了3+2的问题,当我们学乘法的时候,我们背的是99乘法表,用冬松的话说就是“那是你背下来的,你们不真会。”我们解决非线性的时候,用的都是线性的手段,来模拟和逼近。计算机只会一加一,他连减法都是用加法算的,一切复杂的问题最后都是mos管电平的高低序列。可它解决的是这样复杂的问题,这是计算机的智慧,也使我们人类看世界的方法。

尾声

结果,结果还不错,作业写完了,前两天她让我改改学习心得,改完之后就告诉我可以打印上交了。

GTD 简介

引言(为什么介绍GTD?)

  • 如果你在任何情况下,任何时间内都能够随心所欲地控制自己的一切事物,情况会是怎么样呢 ?
  • 你是否曾经有过一种这样的状态(高效状态——回想一下上一次你感觉工作高效时的情形,很可能你当时感觉自己完全能够控制一切,丝毫没有紧张的感觉。你全身心投入到工作中去,时间的概念似乎消失了(怎么已经到了午餐的时间),而且你还明显感受到了工作上取得的进展),是不是自己早已远远地脱离了那种理想状态,想不想再一次回归到这种状态呢?
  • 你是否感觉压力大、事务繁忙、时间不够、经常忘记事先安排的事情、突然的灵光一闪的想法过一段时间就忘了、甚至患有拖延症。

如果你想解决上述的三个问题、那么我想你有必要了解一下GTD,甚至去实践一下GTD。

什么是GTD?(GTD是关于什么的?)

  • GTD = Getting Things Done
  • 定义:是一种行为管理方法。
  • 阐述:把所有事情都从你的脑袋里弄出来。在事情出现前就做好相关行动的一系列决定,而不是在事情爆发的时候,以合适的类别组织好你的项目的各种提醒以及下一步行动。保持你的系统更新和完整,及时进行回顾,使你在任何时候都能信任你的系统和对任务的处理。
  • 总而言之:对任何事情都做好准备。

如何实践GTD?(GTD五大步骤)

收集(Collect)

收集什么?

  • 一切引起我们注意的事务和信息(“材料”)

用什么收集

  • 小本
  • Email
  • 手机
  • 录音笔

为什么要收集?

大脑是CPU&&RAM,不是Hard Disk,所以大脑是靠不住的,我们应将“材料”放到外在的可靠系统里

处理(Process)

处理过程见下图的黑边框

组织整理(Organize)

组织整理过程见下图黑边框

 

回顾(Review)

  • 在纸上记下你需要牛奶是一回事,而在商店里回想起你需要牛奶就是另一回事了
  • 同样,把“给朋友打电话,询问他项目进展情况”记录下来,绝不等同于当你守着一部电话无事可做的时候,就能够唤起记忆
  • 所以每隔一段时间/不同的场景…..回顾一下自己的列表(归档系统)

行动(Do)

  • 如果你把自己的时间都花在组织整理工作,而不是执行它们,那么这样的系统是个只说不做的无用功系统。
  • 前面的步骤都是为了在你做事情的时候,使它变得简单、容易、有趣、让你不会拖延,或者被太多的琐事分心。

我的实践后的体会

  • 收集“材料”时,多次因为手头没有笔等工具,而导致收集不全
  • 在实践过程中,纠结于各种工具,最后迷恋于各种工具的尝试,无法自拔,导致重点偏移,记住GTD的重点在于行动(Do)
  • GTD不是一蹴而就的,GTD是一套持续的系统,需要不断地时间,才能更好的掌握,从而成为信任的系统
  • 我个人认为,如果想形成这套系统,需要付出很多,至少需要半个月吧
  • 我更倾向于把GTD看做是一种生活方式、一种理念、一种态度

推荐阅读

初识jQuery

初步了解JavaScript后,其实对于新手来说,很难写出兼容性良好的JavaScript代码。 这里对上述的兼容性,做一点补充:对于相同的一段JavaScript代码,不同的浏览器可能会给出不一样的解释与运行结果。如果你想了解一些兼容性的例子,可以看看这篇文章《IE和Firefox的Javascript兼容性总结》

不过,如果依靠一些JavaScript框架,就能很容易构建出适应各种浏览器的代码。比较流行的JavaScript框架有jQuery,YUI等等。它们的使用都很简单,只要在页面中引入框架的js脚本文件,就能在接下来的编程中使用框架中提供的各种方法了。

1.什么是DOM (DOM——HTML与JavaScript的桥梁)

DOM是Document Object Model的缩写,从字面翻译看,叫做“文档对象模型”

以下是我对它的理解:

    1.一种抽象的树形结构(将文档中的各个对象通过树形结构链接起来) 2.一种抽象的编程接口 (通过DOM我们可以访问文档的API)
总的来说,DOM将文档文件解析成为一种树形结构,树的结点是文档中的元素,然后我们可以通过这颗树的节点选取文档中的元素,通过文档元素的属性、方法和事件来掌控、操纵和创建动态的html元素。

我们可以将HTML文档理解为一座大楼,文档中的的房间、物品等相当于HTML文档中的对象,JavaScript看做是一个在大楼外面的人,DOM看做是大楼所有入口的集合。大楼外的人是无法访问大楼内部的事物的,除非这个人会穿墙术,当然这是不可能的,作为大楼的HTML为了让大楼外的人可以访问、修改它内部的东西,提供了许多入口,人通过入口进入大楼后,就可以对大楼内部经行操作了。

2.JavaScript对象和jQuery对象的区别

JavaScript对象 = 通过JavaScript方法获得的DOM元素的对象 jQuery对象 = 通过jQuery选择器取得的DOM元素的对象

其实对于同一个DOM元素,我们既可以通过JavaScript选取它,也可以通过jQuery选取它。

他们的区别是:

  • 对于JavaScript对象我们只能使用JavaScript里的方法
  • 对于jQuery对象我们只能使用jQuery里的方法
  • 如果非要使用对方的方法,我们可以先将其转换为对方对象

3.如何为页面元素绑定事件(点击,鼠标移入,鼠标移除,失去焦点等事件)

  • 用JavaScript绑定
    • 方法一:调用addEventListenr()方法 例子:element.addEventListenr(“click”,function(){},true)
    • 方法二:直接绑定 例子:element.onclick=function(){}
    • 方法三:调用attachEvent()(IE的绑定模式) 例子:element.attachEvent(“onclick”,function(){})
  • 用jQuery绑定
    • 方法一:调用bind()方法 例子:$(“#div1”).bind(“click”,function(){})
    • 方法二:使用快捷事件 例子:$(“#div1”).click(function(){})
注:用jQuery绑定事件是多浏览器兼容的,因此可以忽略浏览器对于绑定事件的差异

4.如何使用简单的动画效果(淡入,淡出,滑动等)

jQuery的动画效果函数主要有:animate() fadeIn() fadeOut() fadeTo() 通过调用这些函数,就可以实现相应的动画效果 具体用法:《jQuery 参考手册 – 效果》

5.一个小动画页面示例(采用jQuery框架)

演示地址:jQuery小动画示例

动画效果说明: 第一个按钮:以滑动效果出现一个白色黑边框的正方形 第二个按钮:正方形变成红色 第三个按钮:正方形淡出消失 第四个按钮:点击依次循环执行上述三个按钮的功能

HTML代码

<button id="one">淡入</button>
<button id="two">变红</button>
<button id="three">消失</button>
<button id="four">只点我</button>

Javascript代码

$(document).ready(function() 
{
    var count = 0;

    $("#one").bind("click",function(){
        $("#block").css("left","100");
        $("#block").css("opacity","0");
        $("#block").css("background-color","white");
        $("#block").animate({opacity: "1",left: "200px"},1500)
    });

    $("#two").bind("click",function(){
        $("#block").css("opacity","0")
        $("#block").css("background-color", "red")
        $("#block").animate({opacity: "1"}, 1000)
    });

    $("#three").click(function(){
        $("#block").animate({opacity: "0"}, 1000)
    });

    $("#four").click(function(){
        count++;
        count = count % 3;
        if( count == 1 ){
            $("#block").css("left","100");
            $("#block").css("opacity","0");
            $("#block").css("background-color","white");
            $("#block").animate({opacity: "1",left: "200px"},1500)
        }
        if( count == 2 ){
            $("#block").css("opacity","0")
            $("#block").css("background-color", "red")
            $("#block").animate({opacity: "1"}, 1000)
        }
        if( count == 0 ){
            $("#block").animate({opacity: "0"}, 1000)
        }
    });
});

Html5新特性概览

  • 主讲人 : 李洪祥
  • 时间 : 2011-11-06

注意:本文中的所有测试页面请使用Google chrome或其他对html5兼容较好的浏览器测试,避免可能的浏览器兼容问题对测试结果产生的影响。

Html的简单历史

  • 超文本置标语言(第一版)——在1993年6月作为互联网工程工作小组(IETF)工作草案发布(并非标准)
  • HTML 2.0——1995年11月作为RFC 1866发布,在RFC 2854于2000年6月发布之后被宣布已经过时
  • HTML 3.2——1996年1月14日,W3C推荐标准
  • HTML 4.0——1997年12月18日,W3C推荐标准
  • HTML 4.01——1999年12月24日,W3C推荐标准

HTML 5——在Html 4问世七年之后,因为当时W3C的工作目标是制定并推行XHtml语言,于是还没有开发下一代HTML的工作组,W3C内部的一些人就开始想做点什么了, 于是,在2004年W3C成员内部的一次研讨会上,当时Opera公司的代表伊恩·希克森(Ian Hickson)提出了一个扩展和 改进HTML的建议,他建议新任务组可以跟XHTML 2并行,但是在已有HTML的基础上开展工作,目标是对HTML进行扩展。但W3C投票表决的结果是——”反对”,因为他们认为HTML已经死了,XHTML 2才是未来的方向。然后,Opera、Apple等浏览器厂商,以及其他一些成员说:”那好吧,不指望他们了,我们自已一样可以做这件事,我们脱离W3C。”于是他们成立了Web Hypertext Applications Technology Working Group(Web超文本应用技术工作组,WHATWG) ,WHATWG决定完全脱离W3C,在HTML的基础上开展工作,向其中添加一些新东西。这个工作组的成员里有浏览器厂商,因此他们不仅可以说加就加,而且还能够一一实现。结果,大家不断提出一些好点子,并且逐一做到了浏览器中。

WHATWG的工作效率很高,不久就初见成效。在此期间,W3C的XHTML 2没有什么实质性的进展。特别是,如果从实现的角度来说,用原地踏步形容似乎也不为过。等到2006年W3C认识到xhtml 2并不符合当前的发展实际,同时他们认识到了html5的重要性,于是在2007年他们又投了一次票,同意成立html5开发小组,”在WHATWG工作成果的基础上继续开展工作”并与WHATWG并肩工作,于是逐渐有了我们现在讨论的HTML5问世。

浏览器对html5 的支持情况

目前,对 HTML5 支持最好的是 Chrome,Safari 次之,Firefox 和 Opera 旗鼓相当,IE从IE9终于开始拥抱标准。鉴于这种情况,假如你想使用Html5创建一个先锋体验式站点,现在的 HTML5 可以让你实现,假如你想大规模应用于实际项目,现在还为时过早。

主流浏览器对HTML5 图形和内嵌内容支持情况:

主流浏览器对HTML5 图形和内嵌内容支持情况

主流浏览器对HTML5 Web 应用程序的支持情况:

主流浏览器对HTML5 Web 应用程序的支持情况

Html5移除的元素

Html语言的作用是标记文本的结构,而非用于网页表现,所以用于网页表现的<front><center>等可以用CSS达到同样目的的元素被移除,其他被移除的元素还有:font, center, strike, big, s, u, acronym, applet, dir等。此外还有一些无用或者不被使用的元素属性被移除,例如link的traget属性,这个属性几乎不被浏览器支持。还有<script>的language属性,html4.01推荐使用type属性替代language属性,该属性将被废弃使用,所以language属性没有存在的价值,还有其他的一些属性例如link和a元素的rev属性,body元素的alink,link,text和vlink属性等因为类似的原因被移除。

Html5的基本布局(语义化的标记)

Html是用来描述网页的一种语言,它是一种标记语言,标记语言就是一套标记标签,比如用来描述一段文字是标题的<h1>,标记一个图像的<image>等。html4中使用没有任何语义的<div>用于内容分块,所以html4的网页基本布局是这样的,许多div加上用于命名区块的class或者id,

<div id="wrapper">
    <div id="header"></div>
    <div id="main">
        <div id="sidebar"></div>
        <div id="content"></div>
    </div>
    <div id="footer"></div>
</div>

在html5中,这种情况将被改变,html5新增了若干个明确语义化的标签,在html5中,<div id="header">将会被简洁的<header>代替,如下:

<article>
    <header></header>
    <section></section>
    <section></section>
    <aside></aside>
    <footer></footer>
</article>

其中的<section><article>标签值得注意,<section>标签用来分组相类似的信息,而<article>标签则应该是用来放置诸如一篇文章或是博客一类的信息,你可以在<artile>中嵌入<header><section><footer>等内容。<article>标签,正如它的名称所暗示的那样,提供了一个完整的信息包。相比之下,<section>标签包含的是有关联的信息,但这些信息自身不能被放置到不同的上下文中,因为这样的话其所代表的含义就会丢失。

一个普通的Html 5页面结构会如下所示:

<!DOCTYPE html>
<html>
    <title>标题</title>
    <body>
        <header></header>
        <nav>导航</nav>
        <article>
            <section>区块</section>
        </article>
        <aside>侧边栏</aside>
        <footer>页脚</footer>
    </body>
</html>

Html5对表单的支持

Html5新增了多个控件类型,如输入网址的url类型,输入电子邮箱地址的email类型,用于输入日期的date类型,更有用于输入颜色的color类型等等。更为神奇的是这些类型还内建表单验证,如required属性就说明该表项不能为空,max属性提供了该表项输入允许的最大值,当然在html4中这些功能也可以通过javascript来实现,但是的内建在html5中的表单验证优越性不言而喻。需要注意的是,现在Html5的输入类型还没有被所有浏览器所支持。

测试代码:

<form>
    Email:<input type="email" required /></br>
    Number:<input type="number" max="10" /></br>
    Date :<input type="date"></br>
    File:<input type="file" accept="image/png" /></br>
    <input type="submit">
</form>

实例页面:input.html

Html5中的Media

Html5 的另一大特点就是不借助其他插件就可播放视频和音频文件,在网页中添加如下代码就可以用一个宽度为320像素、高度为240像素的带控制条的浏览器内置播放器来播放”movie.mp4″视频文件,而不再需要使用Adobe Flash播放器。效果就像这样:video.html

<video src="movie.mp4" width="320" height="240" controls="controls">
    Your browser does not support the video tag.
</video>

当然这种直接使用视频源文件的方法会牵扯到视频文件格式的版权问题,所以各主流浏览器都做不到对所有的视频格式都完全支持,这时就需要使用如下的代码来实现视频播放:

<video>
    <source src="movie.mp4">
    <source src="movie.ogv">
    <object data="movie.swf">
        <a href="movie.mp4">Download</a>
    </object>
</video>

<video></video> 之间插入的内容是供不支持 video 元素的浏览器显示的,由于视频格式的版权问题,不同的浏览器支持不同的视频格式,所以video 元素含有允许多个 source 元素。source 元素可以链接不同的视频文件。浏览器将使用第一个可识别的格式。在上面的那个程序里:

  1. 如果浏览器支持video元素,也支持H264(mp4格式),那么就使用第一个视频;
  2. 如果浏览器支持video元素,不支持H264(mp4格式)但支持Ogg,那么用第二个视频;
  3. 如果浏览器不支持video元素,那么就播放Flash;
  4. 如果浏览器不支持video元素,也不支持Flash,那么就给出了下载链接,这下就该没有问题了吧。

不得不提,html5的支持媒体播放的特性会冲击adobe flash在网络媒体中的地位,Adobe公司已经深刻意识到了这个问题,更多信息参见关于Adobe最新的Flash/HTML5策略的问答

动画元素Canvas

HTML5 的 canvas 元素可以使用 JavaScript 直接在网页上绘制图像。在canvas中,画布是一个很重要的概念,画布是一个矩形区域,利用canvas可以控制其每一像素。canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。

创建 Canvas 元素十分简单,只需要向 HTML5 页面添加 canvas 元素,规定元素的 id、宽度和高度:

<canvas id="myCanvas" width="200" height="100"></canvas>

然后通过 JavaScript 来绘制,canvas 元素本身是没有绘图能力的,因此所有的绘制工作必须在 JavaScript 内部完成:

var c=document.getElementById("myCanvas");
var cxt=c.getContext("2d");
cxt.fillStyle="#FF0000";
cxt.fillRect(0,0,150,75);

JavaScript 使用 id 来寻找 canvas 元素:

var c=document.getElementById("myCanvas");

然后,创建 context 对象:

var cxt=c.getContext("2d");

getContext("2d") 对象是内建的 HTML5 对象,拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。

下面的两行代码绘制一个红色的矩形:

cxt.fillStyle="#FF0000";
cxt.fillRect(0,0,150,75);

fillStyle 方法将其染成红色,fillRect 方法规定了形状、位置和尺寸。fillRect 方法拥有参数 (0,0,150,75)。意思是:在画布从左上角开始 (0,0)绘制一个 150×75 的矩形,很简单吧。上面的例子是最简单的例子,canvas是十分强大的,现在大多数html5的Demon页面都是在展示html5强大的动画能力,通过canvas完全可以实现与flash动画相媲美的页面,下面的几个网页供大家惊叹:

Drag&Drop

HTML5为元素新增了用于拖拽的属性draggable,这个属性决定了元素是否能被拖拽, 如果draggable=”true”,则元素可被拖拽,否则只能选择元素的文本。下面几行简单的代码可以简单的说明Html5的Drag&Drop特性:

<section>
    <p draggable="true" ondragstart="dragstartHandler(event)">
    Drag me!Drag me!!</p>
    <p draggable="false">Don’t drag me!!</p>
</section>

Section区块中包含两行文本,第一行文本的draggable = true,即可拖拽的,且声明了发生dragstart事件是调用的函数;第二行文本draggable = false,即不可拖拽的。下面的<script>实现了发生dragstart事件时调用的函数,显示一个提示框。

function dragstartHandler(e)
    {alert('dragstart');}

实例页面:drag.html

运行这段代码可以发现,当拖拽第一行文本时会弹出一个提示框,而拖拽第二行文本时除了复制文本以外没有任何反应,这是因为当拖拽第一行文本时会触发ondragstart事件,从而调用相应的处理函数产生一个提示框。同样的定义其他拖拽事件如ondragenter、ondragover、ondragover、ondrop等的动作函数就可以完成一个完整的拖拽动作,实现想要实现的目的。

下面是一个网络上的demon供大家尝鲜:

把本地文件直接拖拽上传

Html 5的Application Cache

现在,web应用的火爆已经是不折不扣的现实,并且相对传统的应用,web应用不需要安装,所占空间小的特性使其具备传统软件应用所不具备的优势,然而,目前制约web应用最大的问题在于网络连接不能够无时无处。在飞机上,汽车上,火车上,有很多地方都无法被网络信号所覆盖,因此web应用也就无法使用。

HTML5的离线存储使得这个问题迎刃而解。HTML5的web storage API 采用了离线缓存,会生成一个清单文件(manifest file),这个清单文件实质就是一系列的URL列表文件,这些URL分别指向页面当中的HTML,CSS,Javascrpit,图片等相关内容。

一个Mainfest file实例:

–  CACHE MANIFEST
   /demo/test/style.css
   /demo/test/jquery.min.js
   /demo/test/test.html

当使用离线应用时,应用会引入这一清单文件,浏览器读取这一文件,下载相应的文件,并将其缓存到本地。使得这些web应用能够脱离网络使用,而用户在离线时的更改也同样会映射到清单文件中,并在重新连线之后将更改返回应用,工作方式与我们现在所使用的网盘有着异曲同工之处。

Local storge

Web应用的发展,使得客户端存储使用得也越来越多,而实现客户端存储的方式则是多种多样。最简单而且兼容性最佳的方案是Cookie,但是作为真正的客户端存储,Cookie则存在很多致命伤。此外,在IE6及以上版本中还可以使用userData Behavior、在Firefox下可以使用globalStorage、在有Flash插件的环境中可以使用Flash Local Storage,但是这几种方式都存在兼容性方面的局限性,因此真正使用起来并不理想。针对以上情况,HTML5中给出了更加理想的解决方案:假如你需要存储复杂的数据则可以使用Web Database,可以像客户端程序一样使用SQL(不过Web Database标准当前正陷于僵局之中,而且目前已经实现的浏览器很有限);假如你需要存储的只是简单的数据则可以使用Web Storage。

Web Storage实际上由两部分组成:sessionStorage与localStorage。

sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。

localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

下面一段代码同时包含sessionStorage和localStorage用于统计页面的访问次数:


if (sessionStorage.pagecount){
    sessionStorage.pagecount=Number(sessionStorage.pagecount) +1;
}else{
    sessionStorage.pagecount=1;
}
document.write("Visits "+ sessionStorage.pagecount + " time(s).");
if (localStorage.pagecount){
    localStorage.pagecount=Number(localStorage.pagecount) +1;
}else{
    localStorage.pagecount=1;
}
document.write("Visits "+ localStorage.pagecount + " time(s).");

多次刷新页面locaStorage.html可以发现,两种计数每刷新一次就增加1,如果把页面关闭然后再打开,那么sessionStorage计数将会从0开始重新计数,而localStorage仍然继续上次的计数。这正是因为sessionStorage仅仅存储本次会话中的数据,而localStorage则会持久的存储数据。

Html 5 相关网页

参考资料

JavaScript事件冒泡和事件委托

接触JavaScript不久,学的东西也不是特别多。小雨就是习惯把平时学到的东西拿出来分享。一方面加强自己的印象,一方面可以让自己的经验为他人答疑解惑。我们知道JavaScript可以监控页面上元素的各种事件,常用的事件有很多,例如点击,鼠标移入、移出,元素改变等等。这次主要说一下事件冒泡及其一个比较酷的应用,事件委托。不做特殊说明,以下都在jQuery框架内执行。

事件冒泡

什么是“事件冒泡”呢?假设这里有一杯水,水被用某种神奇的方式分成不同颜色的几层。这时,从最底层冒出了一个气泡,气泡会一层一层地上升,直到最顶层。而你不管在水的哪一层观察都可以看到并捕捉到这个气泡。好了,把“水”改成“DOM”,把“气泡”改成“事件”。这就是“事件冒泡”。

为了可以直观地观察到这一现象,我写了一个小程序。这个页面中一共有4个嵌套的正方形。最大的那个在最顶层,最小的那个在最底层。我为每一层都单独绑定了一个点击事件,当这一层被点击时,会为这层涂色。试试看,点击最小的正方形会发生什么?点击其他的又会发生什么呢? (点击这里查看demo)

CSS

.white{background-color:#fff;}
#d1{width:400px;height:400px;border:1px solid #000;margin:50px 50px;}
#d2{width:300px;height:300px;border:1px solid #000;margin:50px 50px;}
#d3{width:200px;height:200px;border:1px solid #000;margin:50px 50px;}
#d4{width:100px;height:100px;border:1px solid #000;margin:50px 50px;}

HTML

<div id="d1" class="white">
    <div id="d2" class="white">
        <div id="d3" class="white">
            <div id="d4" class="white"></div>
        </div>
    </div>
</div>
<button id="reset1">重置</button>

Javascript

jQuery('#d4').click(function(){jQuery(this).css('background-color', 'yellow')});
jQuery('#d3').click(function(){jQuery(this).css('background-color', 'green')});
jQuery('#d2').click(function(){jQuery(this).css('background-color', 'blue')});
jQuery('#d1').click(function(){jQuery(this).css('background-color', 'red')});
jQuery('#reset1').click(function(){jQuery('.white').css('background-color', '#fff')});

没错,点击最小的那个,外面所有的都会被上色。你会发现,点击里层的正方形,外层所有的正方形都会被上色。因为它们也都捕捉到了点击事件。看,他们抓到“气泡”了!

事件委托

上一节的例子我们做一点小小的修改。气泡带上了某种信息,会告诉其经过的每一层自己是在哪一层产生的。JavaScript的事件确实会带着这个属性。当程序捕获一个事件的时候,它会知道这个事件来自于页面上哪个元素。修改上面的程序,使用事件委托来处理点击事件。当最顶层捕获点击事件时,查看事件来源于哪一层,然后只将那一层涂色。再次点击每一层,查看实际效果。只有当前点击的正方形变色了,其他的都毫无反应。(点击这里查看demo)

jQuery('#d1').click(function(e){
        var t = jQuery(e.target);
        var id = t.attr('id');
        if (id==='d4'){
                t.css('background-color', 'yellow');
        } else if (id==='d3') {
                t.css('background-color', 'green');
        } else if (id==='d2') {
                t.css('background-color', 'blue');
        } else {
                t.css('background-color', 'red');
        }
});

当然,如果你有这样嵌套的页面元素,使用了事件委托,委托到了最顶层,这时需要注意:如果其中某个元素,你不希望它的事件冒泡,那么可以使用某种方式阻止事件的冒泡。在jQuery框架中,可以使用stopPropagation()方法来实现而不必关心浏览器兼容性。

$('#bind').click(function(){
    if ($(this).is(':checked')) {
        $('#d4').bind('click', function(e){
            e.stopPropagation();
            alert('冒泡被阻止,这块将不会改变颜色');
        });
    } else {
        $('#d4').unbind('click');
    }
});

重置后选中“阻止最小的方块的事件冒泡”,再点击最小的方块,看是否变色。显然是不会变色,阻止了冒泡,父层将无法接收到点击事件。

注意事项

事件委托是事件冒泡的一个应用,可以减少绑定元素的个数,也不必担心子节点被替换后可能需要进行重新的事件绑定。因为事件的捕获和后续代码的执行已经完全委托给了其父节点。如果页面中含有大量元素需要绑定事件,这样做会减少事件绑定数量,为浏览器减负,无疑会提高页面性能。

但也有些需要注意的。如果用于捕获事件的节点会在某些情况下return false,而你的一个点击事件未委托给父节点,那么,你可能需要阻止这个节点的事件冒泡来达到正确的目的。例如:我在一个div里面有一些按钮和其他元素。利用事件委托来处理这些按钮的点击,如果不是按钮则return false。这时,错误就出现了。如果其他元素中含有链接,那么链接的点击事件也会被委托给div。然而点击链接,会没有任何反应。解决办法一是在委托的代码中对链接进行处理,二是阻止链接的事件冒泡。

源代码

源代码打包下载

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

工具视图

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

示例代码:下载