WebGL 3D开发实战详解 第2版

978-7-115-51936-8
作者: 吴亚峰于复兴索依娜
译者:
编辑: 曹修山

图书目录:

详情

本书系统地介绍了HTML5的基本知识和新特性、WebGL的基本知识,并引导读者完成了WebGL的基础案例。同时,本书也对在WebGL中,实现可编程渲染管线着色器的语言进行了系统介绍,帮助读者进行着色器的高级开发打下坚实的基础。另外,本书介绍了3D开发的多种投影、变换原理及实现,以及点、线段、三角形三大类的绘制方式。 本书适合程序开发人员、游戏开发人员和虚拟现实开发者阅读,也可作为大专院校相关专业师生的学习用书,以及培训学校的教材。

图书摘要

版权信息

书名:WebGL 3D开发实战详解(第2版)

ISBN:978-7-115-51936-8

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

著    吴亚峰 于复兴 索依娜

责任编辑 张 涛

人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

读者服务热线:(010)81055410

反盗版热线:(010)81055315


本书系统地介绍了HTML5的基本知识和新特性、WebGL的基本知识,并引导读者完成了WebGL的基础案例。同时,本书也对在WebGL中实现可编程渲染管线着色器的语言进行了系统介绍,为读者进行着色器的高级开发打下坚实的基础。另外,本书介绍了3D开发的多种投影、变换原理及实现,以及点、线段、三角形的绘制方式。

本书适合程序开发人员、游戏开发人员和虚拟现实开发者阅读,也可作为大专院校相关专业师生的学习用书,以及培训学校的教材。


随着各大浏览器先后支持WebGL以及HTML5的兴起,越来越多的开发者与公司开始将目标转向WebGL的开发。网页游戏市场的火热发展也催生了很多优秀的引擎诞生,像白鹭的egret3D、LayaBox的LayaAir引擎在这块“蓝海”上已经抢占了先机。与市场的火热不相称的是学习资料的匮乏,国内专门系统介绍WebGL开发的图书和资料很少,不能满足初学者学习需要。根据这种情况,作者结合多年从事游戏应用开发经验编写了本书。

了解WebGL的技术人员可能知道,WebGL是一种通过统一标准的跨平台的OpenGL ES接口实现的,用在浏览器中绘制、显示三维计算机图形的技术。该技术的优势在于同一个程序能够通过浏览器运行在多种设备上,避免了程序在各个平台的兼容与适配问题。

随着HTML5和微信等平台的兴起,使得WebGL项目推广的难度大大降低。越来越多的读者希望深入学习WebGL技术。通过JavaScript语言来开发HTML5与WebGL 3D应用,就能在页面中呈现出酷炫的3D画面,可以说是“海阔凭鱼跃,天高任鸟飞”。目前,WebGL有1.0和2.0 两个版本,本书将着重介绍WebGL 2.0。

本书内容组织上本着“起点低,终点高”的原则,覆盖了从最基础的与HTML5相关的知识到学习WebGL 2.0 3D应用开发必知必会的基础知识,再到基于Three.js引擎和Babylon.js引擎实现各种高级特效。同时,本书还详细介绍了如何结合3D物理引擎Bullet的JavaScript版本Ammo进行开发。为了让读者不但能掌握好基础知识,而且还能学习到一些实际项目的开发经验,本书最后还给出了一个具体案例。

这样的组织形式使得初入网页3D开发的读者可以一步一步成长为WebGL 2.0的开发达人,这符合绝大部分想学习页面3D游戏和应用开发的学生、软件开发人员以及相关技术人员的需求。

本书配合每个需要讲解的知识点给出了丰富的插图与完整的案例,使得初学者易于上手,有一定基础的读者便于深入。书中所有的案例均是结合作者多年的开发心得进行设计,结构清晰明朗,便于读者学习。同时书中还给出了很多作者多年来积累的编程技巧与心得,希望对读者有一定的参考价值。

本书的内容组织及安排既考虑了读者自学的需要,也考虑了作为高等院校相关专业课程教材的需要,最后一章的案例可以作为课程设计的参考案例。

本书共分为15章,内容按照由浅入深的原则进行安排。第1章主要介绍了HTML5开发的基础知识;第2~7章为WebGL 2.0开发中必知必会的基础知识;第8~10章为WebGL 2.0开发中的一些高级知识;第11~12章介绍了对WebGL封装比较好的Three.js引擎;第13章介绍支持WebGL 1.0和2.0两个版本的Babylon.js引擎;第14章介绍了3D物理引擎Bullet的JavaScript版本——Ammo;第15章给出了一个完整的项目实战案例——在线3D模型交互式编辑系统。主要内容介绍如下表所示。

章 名

主 要 内 容

第1章 HTML5开发基础——进入WebGL世界的第一道坎

主要介绍HTML 的起源、发展历程,包括HTML5的基础开发,标签的使用和常见标签的开发、属性的使用以及样式表的开发

第2章 初识WebGL 2.0

主要介绍WebGL 2.0的一些基本知识,内容包括着色器与渲染管线,通过一个完整的案例展示了WebGL程序是如何开发的

第3章 着色语言

对于实现WebGL 2.0可编程渲染管线着色器的着色语言进行了系统介绍

第4章 必知必会的3D开发知识——投影及各种变换

介绍3D开发中投影、各种变换原理与实现,同时还介绍几种不同的绘制方式

第5章 光照效果

介绍WebGL 2.0中光照的基本原理与实现、点法向量与面法向量的区别以及光照中每顶点计算与每片元计算的差别

第6章 纹理映射

介绍纹理映射的基本原理与使用,同时还介绍不同的纹理拉伸与采样方式、多重过程纹理技术以及压缩纹理

第7章 3D模型加载

介绍如何使用自定义的加载工具类直接加载使用3ds Max创建的3D立体物体

第8章 混合与雾

主要介绍混合以及雾的基本原理与使用

第9章 常见的3D开发技巧

主要介绍一些常见的3D开发技巧,包括标志板、天空盒与天空穹、镜像技术、灰度图地形、高真实感地形等

第10章 渲染出更加酷炫的3D场景——几种剪裁与测试

主要介绍在WebGL 2.0中经常使用的几种剪裁与测试,包括剪裁测试、模板测试以及任意剪裁平面等

第11章 Three.js引擎基础

主要介绍对WebGL封装比较好的Three.js引擎,包括创建场景、摄像机、基本形状物体、加载模型等

第12章 Three.js引擎进阶

介绍在Three.js中一些高级效果的实现,包括粒子系统、渲染到纹理、雾与混合效果的开发、音频处理、任意剪裁平面等一些比较高级的内容

第13章 Babylon.js引擎

主要介绍支持WebGL1.0和2.0两个版本的Babylon.js引擎,包括基本组件、加载模型、纹理贴图、物理引擎,以及一些比较高级的内容

第14章 Ammo物理引擎

主要介绍Ammo物理引擎,它是Bullet物理引擎的JavaScript版本,包括刚体、软体等的创建与使用

第15章 在线3D模型交互式编辑系统

在线3D模型交互式编辑系统是基于WebGL技术并结合Three.js 3D引擎开发的一款基于浏览器的软件。案例中综合运用了前面多章的知识,适合在学习完本书前面所有介绍的具体技术后进行学习

本书内容丰富,从基础知识到高级特效再到Ammo物理引擎,从简单的应用程序到完整的项目实战案例,适合不同需求、不同水平层次的各类读者。

WebGL与OpenGL/OpenGL ES十分相似,且WebGL通过统一标准的跨平台OpenGL ES接口实现的,免去了开发人员学习不同接口的麻烦。本书可帮助此类读者迅速熟悉WebGL的开发。

传统HTML5的开发人员在网页开发中已有了相当丰富的经验,但部分人员希望在网页开发中加入酷炫的3D场景,但因为未能掌握WebGL技术而苦恼。此类读者通过对本书的学习,并结合自己的开发经验能够快速地提高3D开发水平。

虽然此类开发人员具有一定的编程基础,但缺乏此方面的开发经验,在实际的项目开发中往往感到吃力。本书既对项目开发中所需要的HTML5开发基础进行了详细介绍,又结合作者的开发经验对WebGL 2.0的整体开发框架和技巧进行细致讲解。该类读者通过本书的学习可快速掌握相关的开发技巧,了解详细的开发流程,进一步提升编程开发能力。

由于此类读者在学校学习的知识偏重理论基础,因此实际操作与开发能力较弱。本书既有基础知识介绍又有完整的案例。读者可以在学习基础知识的同时,结合案例进行分析,使学习过程更高效。

此类读者具有一定的WebGL 3D开发基础,并且希望学习最新的WebGL 2.0技术以提升开发能力。本书主要介绍WebGL 2.0技术,结合具体案例帮助读者学习WebGL 2.0的特性。

吴亚峰,毕业于北京邮电大学,后留学澳大利亚卧龙岗大学取得硕士学位。1998年开始从事Java应用的开发,具有十多年的Java开发与培训经验。主要的研究方向为Vulkan、OpenGL ES、手机游戏,以及VR/AR。同时,他是3D游戏、VR/AR独立软件工程师,并兼任百纳科技软件培训中心首席培训师。近十年来为数十家著名企业培养了上千名高级软件开发人员,曾编写过《OpenGL ES 3x游戏开发》(上下卷)、《Unity 案例开发大全》(第1~2版)、《VR与AR开发高级教程——基于Unity》《H5和WebGL 3D开发实战详解》《Android应用案例开发大全》(第1~4版)、《Android游戏开发大全》(第1~4版)等畅销技术图书。2008年年初开始关注Android平台下的3D应用开发,并开发出一系列优秀的Android应用程序与3D游戏。

于复兴,北京科技大学硕士,从业于计算机软件领域十余年,在软件开发和计算机教学方面有着丰富的经验。工作期间曾主持科研项目“PSP流量可视化检测系统研究与实现”,主持研发了多项省市级项目,同时为多家单位设计开发了管理信息系统,并在各种科技刊物上发表了多篇相关论文。2012年开始关注HTML5平台下的应用开发,参与开发了多款手机娱乐、游戏应用。

索依娜,毕业于燕山大学,现任职于华北理工大学。2003年开始从事计算机领域教学及软件开发工作,曾参与编写《Android核心技术与实例详解》《Android平板电脑开发实战详解和典型案例》等技术图书。近几年曾主持市级科研项目一项,发表论文8篇,拥有多项软件著作权,多项发明及实用新型专利。同时多次指导学生参加国家级、省级计算机设计大赛并获奖。

本书在编写过程中得到了华北理工大学以升大学生创新实验中心移动及互联网软件工作室的大力支持,同时王琛、刘亚飞、夏新园、宋润坤、张争、苏瑞梦、杨明、忽文龙以及作者的家人为本书的编写提供了很多帮助,在此表示衷心感谢!

由于作者水平和学识有限,且书中涉及的知识较多,难免有疏漏之处,敬请广大读者批评指正,并提宝贵意见,本书责任编辑的联系邮箱为zhangtao@ptpress.com.cn。

作 者


本书由异步社区出品,社区(https://www.epubit.com/)为您提供相关资源和后续服务。

本书提供如下资源:

要获得以上配套资源,请在异步社区本书页面中单击,跳转到下载界面,按提示进行操作即可。注意,为保证购书读者的权益,该操作会给出相关提示,要求输入提取码进行验证。

如果您是教师,希望获得教学配套资源,请在社区本书页面中直接联系本书的责任编辑。

作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。

当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,单击“提交勘误”,输入勘误信息,单击“提交”按钮即可(见下图)。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。

我们的联系邮箱是contact@epubit.com.cn。

如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。

如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/ selfpublish/submission即可)。

如果您所在学校、培训机构或企业想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。

如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。

“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT技术图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT技术图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://
www.epubit.com。

“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近30年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。

异步社区

微信服务号


本书主要介绍WebGL技术,但在进入WebGL世界之前,我们首先需要迈过HTML的门槛,因为这是通向WebGL的必经通道。

到底何为HTML呢?HTML(Hypertext Markup Language,超文本标记语言)诞生于20世纪90年代初,其为标准通用标记语言下的一个应用。其中“超文本”是指页面内可以包含图片、链接、程序等非文字元素,其结构由“头”与“主体”两部分组成。大家先来看一下HTML的发展背景。

一个组织或者个人在万维网上放置的用户打开浏览器时默认打开的页面称为主页,主页中通常包括指向其他相关页面的超级链接,所谓超级链接,就是一种统一资源定位器(URL)指针,通过激活它,可使浏览器方便地获取新的网页。这也是HTML能获得广泛应用的最重要原因之一。

在逻辑上将一个整体的一系列页面的有机集合称为网站。超级文本标记语言(HTML)是为“网页创建和其他可在网页浏览器中看到的信息”设计的一种标记语言。网页的本质就是超级文本标记语言,结合使用其他的Web技术(如脚本语言、公共网关接口等),创造出功能强大的网页。

现在业界常习惯于用数字来描述HTML的版本(如HTML5),但是最初的时候并没有HTML1,而是1993年IETF团队的一个草案,但这并不是成型的标准。在1995年HTML有了第二版,即HTML2.0,当时它是作为RFC1866来发布的。

有了以上的两个历史版本,HTML的发展可谓突飞猛进。1997年HTML3.2成为W3C推荐标准。2000年基于HTML4.01的ISO HTML成为国际标准化组织和国际电工委员会的标准。

在2008年1月22日,第一份HTML5正式草案被发布。HTML5草案的前身名为Web Applications 1.0,于2004年被WHATWG提出,于2007年被W3C接纳,并成立了新的HTML工作团队。2014年10月28日,发布了HTML5正式的推荐标准。

2016年3月11日,HTML5.1标准工作草案发布。2016年8月18日,公开HTML5.2工作草案。2016年11月1日,HTML5.1正式推荐标准发布。2017年12月14日,HTML5.2正式推荐标准发布。W3C HTML规范和时间线如表1-1所示。

表1-1 W3C HTML规范和时间线

规  范

时 间 线

HTML 3.2

1997年1月14日

HTML 4.0

1998年5月24日

HTML 4.01

1999年12月24日

HTML5(草案)

2010年6月24日

HTML5(正式推荐标准)

2014年10月28日

HTML5.1(草案)

2016年3月11日

HTML5.2(草案)

2016年8月18日

HTML5.1(正式推荐标准)

2016年11月1日

HTML5.2(正式推荐标准)

2017年12月14日


说明 

上面简述了HTML的发展历史,在其诞生至今已过20多年,如此短的篇幅是不够完全介绍的,这里只是简单介绍一下,在很多专门介绍HTML的书或者网站上都会对此有详细的介绍。由于本书重点并不是这些,所以简单地一带而过。


HTML5不仅是HTML规范的最新版本,它还是一系列用来制作现代丰富Web内容的相关技术的总称。其中最重要的三项技术分别是HTML5核心规范、CSS(Cascading Style Sheets,层叠样式表)和JavaScript。

HTML5核心规范定义用于标记内容的元素,并明确其含义。CSS可控制标记过的内容呈现在用户面前的外貌。JavaScript则可以用来操作HTML文档的内容以及响应用户的操作,此外如果要想使用HTML5中一些为编程目的设计的新增元素,那么也需要用到JavaScript。


提示 

看不懂上面所说的东西不要紧,在下面几节中会较为详细地介绍HTML元素、CSS和JavaScript。


为了应对漫长的标准化过程以及标准落后于常见用法的情况,HTML5及其相关技术是作为一系列小标准而指定的,其中一些标准只有几页,涉及的只是高度细化的一个方面。当然,一些标准会有几百页,几乎包含了相关功能的所有方面。

这样做有利也有弊,好处是可以加快标准制定的步伐。主要的弊端在于难以全面掌握制定中的各个标准的情况以及这些标准之间的关系,技术规范的质量也会有所下降。有些标准中存在的一些歧义会使在浏览器实现中出现了不一致的情况。

最大的不足之处可能是没有一条可评估HTML5是否达标的基准线。虽然现在还处于初始阶段,但是用户所用到的所有浏览器不可能都实现了要用的特性。W3C公布过一个正式的HTML5徽标,如图1-1所示,但是它并不代表对HTML5标准及相关技术的全面支持。

▲图1-1 W3C公布的正式的HTML5徽标

“我们想做的事情已经不再是通过浏览器观看视频或收听音频,或者在一部手机上运行浏览器。而是希望通过不同的设备,在任何地方,都能够共享照片、网上购物、阅读新闻,以及查找信息。虽然大多数用户对HTML5和开放的Web平台并不熟悉,但是它们正在不断改进用户体验。”

上述是2014年10月28日W3C的HTML工作组在发布HTML5的正式推荐标准(W3C Recommendation)时万维网联盟创始人Tim Berners-Lee所说的一段话,这意味着新标准带来的改变是巨大的,我们来看一下HTML5中引入的新特性。

HTML5正式推荐标准虽然已经推出,但仍在继续改动中,虽然其中有一些调整,但是变化不大。这意味着本书现在所讲的标准与今后新出的标准可能会有出入,标准正式出炉还需要等好些年,最终版本与现在版本的差别应该不会很大。

浏览器支持是决定HTML5命运的一项至关重要的因素。各浏览器越快统一对标准的支持,HTML5标准落到实处也就越快,从2012年开始,全球各大浏览器逐步加大对HTML5的支持。

最流行的浏览器基本都已实现了许多HTML特性。本书示例演示效果时所用的浏览器是Google的Chrome或者Mozilla的Firefox。从国际形式来看,通过对比各独立内核浏览器(IE、Firefox、Chrome、Safari、Opera),可知各大浏览器对标准的支持都有显著的提高。

移动平台上主流的浏览器(iOS Safari 6.0,Android Browser 4.1,Opera Mobile 12.1,Chrome for Android 18.0,Firefox for Android 15.0)目前对标准的支持度均高于60%,其中表现居首的是Chrome for Android,而支持度相对较低的Android Browser也在60%以上,如图1-2所示。

上述内容虽然不是很详细,但是对于HTML的基本内容都已介绍。限于篇幅,只是大概介绍一部分。若有读者想详细了解这些内容,那么可以找一些专门讲解HTML的资料或者云网站查阅。

▲图1-2 移动浏览器对HTML5的支持

如果想要掌握WebGL,那么开发人员还需要了解一些关于HTML的内容。HTML是WebGL的基础,因为WebGL是在网页里展示的,所以其必然是基于HTML开发的。在正式讲述WebGL之前先来给大家介绍一下HTML的基本内容。

HTML是一种标记语言,其标记以应用文档内容(例如文本)的元素为存在形式,现在HTML的标准为HTML5。下面在介绍各种HTML5的标签时我们会按照其作用进行划分,读者阅读时会更有条理性。在讲解一些比较重要的标签时都会有相应的小案例供大家参考。

HTML5中的一大主要变化是基本理念方面的:将元素对其内容呈现结果的影响和其语义分开。从原理上讲这的确合乎情理,HTML元素负责文档内容的结构和含义,内容的呈现则由应用于元素上的CSS样式来控制。

元素由三部分组成,其中有两部分是开始标签和结束标签,夹在两个标签之间的是元素内容,两个标签与它们之间的内容构成了一个元素。从本节开始介绍各个标签的作用,并结合案例来介绍用法与注意事项。

在介绍标签时,我们知道标签由开始标签与结束标签组成。例如<html>为开始标签,</html>为结束标签。在标签之间写的是需要发挥的部分(即元素的内容部分),开始标签中有时会有一些属性,这些属性声明了标签的个体属性。下面如果有特别需要注意的局部属性,我们都会标注出来。

与局部属性相对应的就是全局属性,这部分内容在下面小节中会有详细介绍,每段都会有详细的代码与注释以供读者参考。接下来先来看标签中的基础标签都有哪些,在表 1-2~表1-10中列出了这些标签及其作用,以及一些标签中的局部属性。

表1-2 基础标签及其作用

标  签

描  述

标  签

描  述

<!DOCTYPE>

定义文档类型

<html>

定义HTML文档

<title>

定义文档标题

<body>

定义文档主体

<h1>-<h6>

定义文本标题

<p>

定义段落

<br>

定义简单的折行,即换行

<hr>

定义水平线

<!--..-->

定义注释

</..>

结束标签

表 1-2 所示为基础标签的描述,接下来我们将这些标签全部应用到一个案例中,这个案例仅为展示这些标签的基本应用,其中还有一些标签会有其特有的属性,在这里并没有具体列出来,这些属性的应用相当简单,读者可以自行查阅资料更改这些代码进行验证。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_1.html。

1    <!DOCTYPE html>
2    <html><head><title>这里为标题,     Sample1_1案例</title></head>
3    <body>
4    此处为主体部分
5    <h1>这里为文本标题1</h1>
6    <h2>这里为文本标题2</h2>
7    <h3>这里为文本标题3</h3>
8    <h4>这里为文本标题4</h4>
9    <h5>这里为文本标题5</h5>
10   <h6>这里为文本标题6</h6>
11   <p>这里为段落,本例主要向读者展示先前介绍的标签用法,这些标签为基本标签
12   <hr></br>这里演示在段落中的换行<hr></br>是接着上面的段落。</p><!--此处为html文档注释
13   本案例介绍了基础标签的一些内容-->
14   此处主体结束
15   </body></html>

下面来看一下案例效果,本案例以及本书中的案例都是在Google Chrome浏览器或者Firefox浏览器上运行的,读者也可以自行选择合适的浏览器运行案例,选择时需要注意浏览器是否支持HTML5特性。图1-3所示为本案例的效果。

对基础标签有了基本认识后,那么剩下的在标签用法上与其并无差异,只是在功能上有所不同。下面来看一下格式标签及其作用,如表1-3所示,表中列出了格式标签以及它们的描述。

▲图1-3 Sample1_1基础标签案例效果

表1-3 格式标签及作用

标  签 描  述 标  签 描  述
<abbr> 定义缩写 <address> 定义文档作者的联系信息
<b> 定义粗体文本 <bdi> 定义文本的文本方向
<bdo> 定义文字方向 <biq> 定义大号文本
<blockquote> 定义长的引用 <center> 定义居中文本
<cite> 定义引用 <code> 定义计算机代码文本
<del> 定义被删除文本 <dfn> 定义项目
<em> 定义被强调文本 <i> 定义斜体文本
<ins> 定义被插入文本 <kbd> 定义键盘文本
<mark> 定义有记号的文本 <meter> 定义预定义范围内的文本
<pre> 定义预格式文本 <progress> 定义任何类型的任务进度
<q> 定义短的引用 <rt> 定义ruby注释的解释
<ruby> 定义ruby的注释 <s> 定义加删除线的文本
<samp> 定义计算机代码样本 <small> 定义小号文本
<strike> 定义加删除线文本 <sup> 定义上标文本
<sub> 定义下标文本 <time> 定义日期
<tt> 定义打字机文本 <u> 定义下划线文本
<var> 定义文本的变量部分 <wbr> 规定换行
<font> 定义文本的字体、尺寸和颜色
<rp> 定义不支持ruby元素的浏览器显示的内容
<strong> 定义语气更加强烈的强调文本

由于上面列出的这些格式标签在平时用到比较多,所以每个标签都有一个小案例介绍如何使用。但是这些案例仅是向读者展示了最基本的用法,由于还没有讲到属性,所以只能介绍最简单的部分,现在只需将每个标签的基本作用记住即可。

接下来我们先来看一下格式标签中一些比较简单的标签用法,由于每个标签的案例都比较简短,在主体部分每个都是几行代码,所以下面的案例是将几个标签合在一起编写的一个简单案例,读者在阅读时注意区分。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_2.html。

1    <!DOCTYPE HTML>
2    <!--本案例演示了格式标签中使用一部分标签的小案例,剩下一部分会在下面给出-->
3    <html><body>
4    这里演示的为缩写示例:The <abbr title="World Wide Web Consortium">W3C</abbr>
5    was founded in 1994.
6    <p>这里演示加粗文本示例 <b>此处加粗</b>.</p>
7    <!--根据H5规范,粗体为最后选择,没有其他标签适用时才会
8    选择,应先从标题、被强调文本、标记文本等标签中进行选择-->
9    <ul>
10   <!--此处为bdi标签,设置一段文本使其脱离父元素的文本方向设置-->
11    <li>User <bdi>Bob</bdi>: 60 points</li>
12    <li>User <bdi>Jerry</bdi>: 80 points</li>
13    <li>User <bdi>Tom</bdi>: 90 points</li>
14   </ul>
15   <p>接下来显示的为bdo标签,其中可以定义dir属性来覆盖默认的文本方向</p>
16   <bdo dir="rtl"><!--dir的值有rtl从右向左与ltr从左向右两种值-->
17   现在展示的是从右向左的文本方向
18   </bdo><br />
19   <!--下面几个标签一般还会搭配id、class等一些属性来使用,这些属性在下面会有介绍-->
20   <big>这里演示big标签示例</big><br />
21   <em>这里演示em标签示例</em><br />
22   <i>这里演示倾斜标签i示例</i><br />
23   <small>这里演示small标签</small><br />
24   此处将演示下标标签的用法
25   <sub>subscript</sub><br />
26   此处将演示上标标签的用法
27   <sup>superscript</sup><br />
28   </body></html>

看完一些标签的使用方法后,我们还需要看一下效果图,毕竟用文字表达不如图像表达直观且更容易使人接受与记住。图1-4所示为上述程序的运行效果。

▲图1-4 Sample1_2格式标签案例效果

对于上述标签,在外观上能够区分清楚是什么标签,这也便于读者理解记忆。下面我们来看看另外一些格式标签的效果图与开发,本部分除了介绍标签之外也介绍了一些标签中相应的属性,图1-5所示为表格中剩下一些标签的使用效果。

▲图1-5 Sample1_3格式标签案例效果

对于图1-4与图1-5中所示文本样式,如果只是想要样式,则可以用CSS制作出更好和更多的效果,在后续知识点中会介绍这方面的知识。接下来看一下Sample1_3案例的开发过程,本案例也是格式类中的一部分标签。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_3.html。

1    <html><body>
2    我们来看一下长引用、引用、短引用的标签示例。
3    <blockquote>
4    现在示例为一个长引用示例,之间的所有文本都会从常规文本中分离出来,经常会在左、右两边<br />
5    缩进(增加外边距),而且有时会使用斜体。也就是说,长引用拥有自己的空间
6    </blockquote>
7    <!--<cite> 标签通常表示它所包含的文本对某个参考文献的引用,把指向其他文档的引用分离出来,
8    尤其是分离传统媒体中的文档,如书籍、杂志、期刊等。如果引用的这些文档有联机版本,
9    还应该把引用包括在一个 <a> 标签中,从而把一个超链接指向该联机版本。-->
10   <cite>
11   现在进行引用示例讲解,引用的文本将以斜体来显示。它的一个隐藏功能是
12   可以使人从文档中自动摘录参考书目
13   </cite><br />
14   <!--长引用与短引用可以用cite属性定义出引用的来源-->
15   <q>现在为一个短引用示例,短引用中插入了双引号引导。</q>
16   <!--短引用与长引用是一样的,它们在显示上有所不同。如果需要从文本中
17   分离出比较长的内容就用长引用。-->
18   <p>下面介绍显示计算机代码的几种标签</p><br />
19   <code>此处示例为计算机代码标签</code><br />
20   <!--编程的朋友都习惯计算机代码与文本的格式是不同的,这样方便读者寻找计算机代码片段-->
21   <kbd>此处为从键盘上键入文本的标签示例</kbd><br />
22   <!--该标签用来表示文本是从键盘上键入的。浏览器通常用等宽字体来显示该标签中包含的文本。-->
23   <tt>这里演示宽体字标签示例</tt><br />
24   <samp>这里为samp标签示例</samp><br />
25   <!--该标签并不经常使用。只有从正常的上下文中将某些短字符序列提取出来,
26   并对它们加以强调的极少情况下,
27   才使用这个标签。-->
28   <var>此处示例定义变量标签</var><br />
29   <!--本标签是计算机文档应用中的另一个小窍门,这个标签经常与 <code> 和 <pre> 标签一起使用,
30   用来显示计算机编程代码范例及类似方面的特定元素。-->
31   <dfn>现在的示例可标记对特殊术语或短语进行定义的标签</dfn></br>
32   <!--本标签尽量少用为妙。作为一种通用样式,尤其在技术文档中,应该将它们与普通文本分开,这样
33   读者可以更好地理解文章当前的主题,此后就不要再对这个术语进行任何标记了。-->
34   <p>接下来再来介绍一下预定义格式文本</p>
35   <pre><!--该标签很适合显示计算机代码,本标签经常与code标签一起使用。
36   其中的width属性定义了每行最大字符数,一般为40、80、132。-->
37   这是预格式文本。
38   它保留了空格
39   和换行。
40   </pre>
41   <!--需要注意的是,制表符(tab)在 <pre> 标签定义块中可以起到应有的作用,每个制表符占据
42    8个字符位置。但是我们不推荐使用它,因为在不同的浏览器中,Tab的实现各不相同。在用 
43   <pre> 标签格式化的文档段中使用空格可以确保文本处于正确的水平位置。-->
44   <p>下面显示的标签定义了已知范围或分数值内的标量测量:</p>
45   <meter value="3" min="0" max="10">3/10</meter><br>
46   <meter value="0.6">60%</meter><br />
47   <!--该标签一般用于查询磁盘用量、查询结果的相关性,不应用于指示进度(在进度条中)。标记进度条
48   应使用 <progress> 标签。IE不支持meter标签。-->
49   接下来介绍进度条标签progress:<progress value="22" max="100">
50   </progress><!--该标签中的max属性表示任务一共需要多少工作,value表示已经完成了多少任务。-->
51   <!—IE 10, Firefox, Opera, Chrome以及Safari 6支持 <progress> 标签。-->
52   </body></html>

上面在介绍<pre>标签时说到了符号实体,在HTML中不能使用小于号(<)和大于号(>),这是因为浏览器会误认为它们是标签。如果希望正确地显示预留字符,则必须在HTML源代码中使用字符实体(character entities)。表1-4所示为部分符号实体。

表1-4 符号实体及对应编号

显 示 结 果

描  述

实 体 名 称

实 体 编 号

空格

&nbsp;

&#160;

<

小于号

&lt;

&#60;

>

大于号

&gt;

&#62;

&

和号

&amp;

&#38;

"

引号

&quot;

&#34;

'

撇号

&qpos;(IE不支持)

&#39;

&cent;

&#162;

£

&pound;

&#163;

欧元

&euro;

&#8364;

§

小节

&sect;

&#167;

©

版权

&copy;

&#169;

®

注册商标

&reg;

&#174;

商标

&trade;

&#8482;

×

乘号

&times;

&#215;

÷

除号

&divide;

&#247;

需要注意的是,实体名称区分大小写,HTML中的常用字符实体是不间断空格(&nbsp;)。浏览器总是会截断HTML 页面中的空格。如果在文本中写10个空格,则在显示该页面之前,浏览器会删除它们中的9个。如需在页面中增加空格的数量,需要使用&nbsp; 字符实体。

简要介绍了符号实体后,我们会在上个程序的<meter>标签中看到了几种属性,但是当时并没有讲解,在接下来的表1-5中将看到该标签中的属性介绍。

表1-5 < meter>标签属性列表

属  性

描  述

form

form_id

本元素所属的一个或多个表单

high

number

规定被视作高值的范围

low

number

规定被视作低值的范围

max

number

规定范围的最大值

min

number

规定范围的最小值

optimum

number

规定度量的优化值

value

number

必需属性,规定度量的当前值

需要注意的是,在form属性的值id中规定此值必须为同一文档中<form>元素的属性值。high属性必须小于max属性值,且必须大于low和min属性值。low属性必须大于min属性值,且必须小于high和max属性值。

通过Sample1_2与Sample1_3两个例子我们掌握了大部分格式标签的基本用法,接下来便介绍剩下没有提到的标签用法与一部分表单标签。首先来看一下本部分程序的效果图,图 1-6所示为表单标签使用效果。

▲图1-6 Sample1_4格式标签案例与表单标签效果

看完效果图以后不难发现,这些标签同之前讲的标签在外观表示形式上有所差别,这样便于大家的理解记忆。通过接下来的学习我们将学会如何在网页中制作出基础表单与多种多样的特效形式。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_4.html。

1    <html><body>
2    <p>这里为删除线标签示例"一打有 <del>二十</del> <ins>十二</ins> 件"。</p>
3    <!--大多数浏览器会改写为删除文本和下画线文本,一些老式的浏览器会
4        把删除文本和下画线文本显示为普通文本。-->
5    <p>这里为标记标签示例:出门记着带 <mark>钥匙</mark></p><!--此标签为H5新加的标签-->
6    <p>这里为时间标签示例:我在 <time datetime="2016-10-01">国庆节</time> 会放假。</p>
7    <!--本标签定义公历的时间(24小时制)或日期,时间和时区偏移是可选的。-->
8    <p>从现在开始就要进入表单类标签的学习,在这里将学到在网页世界中
9        经常见到与用到的东西。<br />
10   首先将要学习的是form标签,下面将是form标签示例:</p>
11   <form action="/example/html/form_action.asp" method="get">
12     <p>姓氏: <input type="text" name="姓氏" /></p>
13     <p>名字: <input type="text" name="名字" /></p>
14     <input type="submit" value="Submit" />
15   </form><!--由于本部分涉及服务器方面的知识,但是这里只介绍关于HTML的基础内容,所以
16   便不叙述服务器方面知识,想了解此方面内容的读者应当阅读相关书籍或资料。-->
17   <p>以上程序显示了基本的form标签如何使用,接下来分步来看一下文本域、密码域、
18   复选框、单选按钮。</p>
19   <form><p>现在为文本域创建示例:</p>
20   名:<input type="text" name="名"><br />
21   姓:<input type="text" name="姓">
22   </form><!--同上面程序,input标签的type属性为text时,即为文本域-->
23   <form><p>现在来看密码域的创建过程,在输入密码时浏览器会将用其他符号代替密码</p>
24   用户:<input type="text" name="用户"><br />
25   密码:<input type="password" name="密码">
26   </form><!--与文本域类似,将input标签的type属性改为password,即建立了一个密码域-->
27   <form><p>现在来看复选框的创建过程</p>
28   我喜欢步行:<input type="checkbox" name="步行"><br />
29   我喜欢汽车:<input type="checkbox" name="汽车">
30   </form><!—将input标签的type属性中改为checkbox,即为复选框的创建-->
31   <form><p>现在来学习单选按钮的创建过程</p>
32   男性:<input type="radio" checked="checked" name="Sex" value="male" /><br />
33   女性:<input type="radio" name="Sex" value="female" />
34   </form><!--当用户单击一个单选按钮时,该按钮会变为选中状态,其他所有按钮会变为非选中状态-->
35   </body></html>

上述程序介绍了表单的一部分标签,这使读者对表单有了初步的印象。接下来看一下表单标签中都有什么样的标签。表1-6列出了表单标签中的标签及其描述,学会其中所列这些标签后,我们便能够在网页中制作出各种类型的表单了。先来了解一下这些标签。

表1-6 表单类标签及其描述

标  签

描  述

标  签

描  述

<optqroup>

定义选择列表中相关选项的组合

<input>

定义输入控件

<output>

定义输出的一些类型

<keyqen>

定义生成密钥

<form>

定义供用户输入的HTML表单

<textarea>

定义多行的文本输入控件

<leqend>

定义fieldset元素的标题

<button>

定义按钮

<fieldset>

定义围绕表单中元素的边框

<select>

定义选择列表(下拉列表)

<label>

定义input元素的标注

<datalist>

定义下拉列表

<option>

定义选择列表中的选项

看了上一个程序中表单标签的基本用法再结合表1-6列出的标签,读者应该有更深刻的体会,下面我们将介绍剩下的标签用法。由于本部分的标签都会有几个自己的属性,所以在程序中只介绍用到的属性用法,下面我们会将剩下的属性进行介绍。

现在首先来看一下表单标签中未介绍标签的开发过程,图1-7 所示为表单标签制作出来后基础版的效果。因为本案例需要对多个标签进行介绍,所以在视觉上会感觉有些杂乱,读者在阅读时应该将每个标签与图对应,这样效果会更好。

看完了效果图后不难发现,上面所介绍的是在生活中常用的一些控件。相信读者心中肯定想要掌握这些控件的实现技术,现在就来介绍这些控件的开发过程。其实它们的原理与上面介绍过的标签开发无异,开发起来并不困难。

▲图1-7 Sample1_5表单标签效果

代码位置:随书源代码/第1章目录下的HTML5/Sample1_5.html。

1    <html><body>
2    <p>现在示例为下拉列表,您喜欢的汽车牌子:
3    <form><select name="汽车">
4    <option value="沃尔沃">沃尔沃</option>
5    <option value="奔驰">奔驰</option>
6    <option value="菲亚特">菲亚特</option>
7    <option value="奥迪">奥迪</option>
8    </select></form></p>
9    <p>现在示例为有预设值的下拉列表,您喜欢的汽车牌子为:
10   <form><select name="汽车">
11   <option value="沃尔沃">沃尔沃</option>
12   <option value="奔驰">奔驰</option>
13   <option value="菲亚特">菲亚特</option>
14   <option value="奥迪" selected="selected">奥迪</option>
15   </select></form></p>
16   <!--上面为大家演示了两种下拉列表,第一种没有预设值,
17   第二种多了一个selected属性即有预设值-->
18   <p>这里给大家演示多行输入文本</p>
19   <textarea rows="10" cols="30">
20   textarea标签定义多行的文本输入控件,其中文本的字体默认为等宽字体。
21   可以通过 cols和rows属性来规定textarea的尺寸,不过更好的办法是
22   使用CSS的height和width属性。</textarea>
23   <!--在文本输入区内的文本行间,用 "%OD%OA" (回车/换行)进行分隔。
24   可以通过wrap属性设置文本输入区内的换行模式-->
25   <p>下面介绍按钮标签:在button元素内部,您可以放置内容,
26   比如文本或图像。这是该元素与使用input元素创建按钮的不同之处。</p>
27   <button type="button">按钮1</button>
28   <form><input type="button" value="按钮2" /></form>
29   <!--需要注意的是,请始终为按钮规定type属性。IE的默认类型是 "button",
30   而其他浏览器中(包括W3C 规范)的默认值是 "submit"。-->
31   <!--如果在HTML 表单中使用button元素,则不同的浏览器会提交不同的值。IE
32   将提交 <button> 与 <button/> 之间的文本,而其他浏览器将提交value属性的内容。
33   请在HTML 表单中使用input元素来创建按钮。-->
34   <p>接下来看一下围绕数据的fieldset标签。如果
35   浏览器没有显示边框,则为浏览器版本老旧造成的。</p>
36   <form><fieldset><legend>健康信息</legend>
37       身高:<input type="text" />
38       体重:<input type="text" />
39     </fieldset></form><!--legend标签定义fieldset标签的标题-->
40     <!--当一组表单元素放到 <fieldset> 标签内时,浏览器会以特殊
41     方式来显示它们,该标签没有必需或者唯一的属性。-->
42   <p>下面介绍元素组合选项标签optgroup:</p>
43   <select><optgroup label="美国产的车">
44       <option value="ford">福特</option>
45       <option value="chevrolet">雪佛兰</option>
46     </optgroup><optgroup label="德国产的车">
47       <option value="mercedes">奔驰</option>
48       <option value="audi">奥迪</option>
49     </optgroup></select><!--option标签定义下拉列表中一个项目,
50   没有结束标签,常与select一起使用。optgroup元素用于组合选项。当您使用一个长的
51   选项列表时,对相关选项进行组合会使处理更加容易。-->
52     <p>接下来是output标签的使用,output标签定义不同类型的输出</p>
53     <form oninput="x.value=parseInt(a.value)+parseInt(b.value)">0
54   <input type="range" id="a" value="50">100
55   +<input type="number" id="b" value="50">
56   =<output name="x" for="a b"></output><!--需要注意的是,在IE浏览器中不支持这个标签。-->
57   </form></body></html>

至此,表单标签基本讲解完毕,但只有这些还是远远不够的,因为这些标签中还有许多元素没有讲述。这些标签只有在各种属性的配合使用下才会有更好的效果,下面就来看一下这些标签的属性及其用法,如表1-7所示。

表1-7 <form>标签的属性值及其描述

属  性

描  述

accept-charset

charset_list

规定服务器可处理的表单数据字符集

action

URL

当提交表单时向何处发送表单数据

autocomplete

on/off

规定是否用表单的自动完成功能

enctype

下面会有介绍

规定在发送表单数据之前如何对其编码

method

get/post

规定发送form-data的HTTP方法

name

form_name

规定表单的名称

novalidata

novalidata

如果使用该属性,则提交表单时不进行验证

target

_blank/_self/_parent/_top/framename

规定在何处打开action URL


说明 

上面表1-7介绍了<form>标签在HTML5中的属性,但是这部分要结合服务器来使用。由于篇幅问题并没有讲述服务器,有兴趣的读者可以自己查阅这方面的资料,结合本节介绍的属性来实践。属性是在开始标签中使用的,上面的每个例子中都有标签属性的使用。


表 1-7 中在介绍<enctype>标签时,并没有介绍其值,现在我们来看一下它。application/ x-www-form-urlen coded为在发送前编码所有字符为该属性默认值;multipart/form-data为在使用包含文件上传控件的表单时,必须使用该值;text/plain在编码时将空格转换为“+”号不对特殊字符编码。

通过对前面的案例学习,我们发现<input>标签及其属性的用法很多,并且那只是使用一个type属性所带来的效果,接下来看一下<input>标签的其余属性,表1-8所示为<input>标签的属性值及其描述。

表1-8 <input>标签的属性值及其描述

属  性

描  述

accept

mime_type

规定通过文件上传来提交的文件类型

alt

text

定义图像输入的替代文本

autocomplete

on/off

规定是否使用输入字段的自动完成功能

autofocus

autofocus

规定输入字段在页面加载时是否获得焦点

checked

checked

规定input元素首次加载时应当被选中

disabled

disabled

当加载input元素时禁用此元素

form

formname

规定输入字段所属的一个或多个表单

formation

URL

覆盖表单的action属性

formenctype

下面有介绍

覆盖表单的enctype属性

formmethod

get/post

覆盖表单的method属性

formnovalidata

formnovalidata

覆盖表单的novalidata属性

formtarget

同表单的target属性值

覆盖表单的target属性

height

pixel/%

定义input字段的高度

list

datalist-id

引用包含输入字段的预定义选项的datalist

max

number/data

规定输入字段的最大值

maxlength

number

规定输入字段中字符的最大长度

min

number/data

规定输入字段的最小值

multiple

multiple

如果使用该属性则允许使用一个以上的值

name

field_name

定义input元素的名称

pattern

regexp_pattern

规定输入字段的值的模式或格式

placeholder

text

规定帮助用户填写输入字段的提示

readonly

readonly

规定输入字段为只读

required

required

指示输入字段的值是必需的

size

number_of_char

规定输入字段的宽度

src

URL

定义以提交按钮形式显示图像的URL

step

number

规定输入字的合法数字间隔

type

之前的示例中已包含全部的值

规定input元素的类型

value

value

规定input元素的值

width

pixel/%

规定input字段的宽度

表1-8所示的这些属性为input元素的属性,其中包含了HTML5中新增的许多属性,接下来我们便来看一下这些属性的应用效果。图1-8所示为input元素属性应用案例效果,由于之前已经讲述了type属性,所以在这里便没有再叙述这部分知识。

▲图1-8 Sample1_6 input元素属性应用案例效果

看完了案例生成的效果图,就来看一下案例的开发过程。一如前面案例开发过程所示,本案例中大部分标签与属性的使用方法大家应该已经掌握了,现在来具体学一下input元素的局部属性的应用,其与大部分属性应用是相同的,读者学起来会很快。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_6.html。

1    <html><body>
2    <p>单击此图像即为提交,这里用图片代替按钮,alt属性只能与type="image"配合使用。
3    它为图像输入规定的替代文本。</p><form>
4      <p>姓: <input type="text" name="姓" /></p>
5      <p>名: <input type="text" name="名" /></p>
6      <input type="image" src="back.png" alt="Submit" width="64" height="64"/></form>
7    <!--即使alt属性不是必需的属性,但是当输入类型为image时,仍然应该设置该属性。如果
8    不使用该属性,则有可能对文本浏览器或非可视的浏览器造成使用障碍。除了Safari之外,所有
9    主流的浏览器都支持 "alt" 属性。height属性只适用于 <input type="image">,它规定image 
10   input的高度。其属性pixel以像素为单位,%为百分比为单位。-->
11   <p>这里是表单的自动完成功能测试,填写并提交表单,然后再输入一遍相同的数据来体
12   验一下自动完成功能。</p><form autocomplete="on">
13   姓:<input type="text" name="姓" /><br />
14   名: <input type="text" name="名" /><br />
15   <input type="submit" /></form><p></p>
16   <!--自动完成功能允许浏览器预测输入的字段。当用户在开始键入字段时,浏览器基于之前键入的值,
17   应该显示出在字段中填写的选项。autocomplete属性适用于 <form>,以及下面的 <input> 类型:
18   text, search, url, telephone, email, password, datepickers, range以及color。-->
19   <p>这里显示加载时自动获得焦点与禁用输入字段示例,使用该属性的input元素获得焦点。</p>
20   <form>
21     姓: <input type="text" name="姓" autofocus><br>
22     名: <input type="text" name="名" disabled="disabled"><br>
23     <input type="submit"></form>
24   <!--被禁用的input元素既不可用,也不可单击。可以设置disabled属性,直到满足某些其他的
25   条件为止(比如选择一个复选框等)。然后,需要通过 JavaScript来删除 disabled值,
26   将input元素的值切换为可用。-->
27   <p>这里显示max与min属性示例,max属性与min属性配合使用,
28   可创建合法值范围。</p><form>
29   输入数量: <input type="number" name="输入数量" min="0" max="10" />
30   <input type="submit" /></form>
31   <!--max和min属性适用于以下 <input> 类型:number, range, date, datetime, datetime-local,
32    month, time以及week。-->
33   <p>这里为输入段字符最大长度属性示例:</p><form>
34     <p>姓: <input type="text" name="姓" maxlength="85" /></p>
35     <p>名: <input type="text" name="名" maxlength="55" /></p>
36     <input type="submit" value="Submit" />
37     <!--maxlength属性规定输入字段的最大长度,以字符个数计。
38   maxlength属性与 <input type="text"> 或 <input type="password"> 配合使用。-->
39   </form><p>此处示例为可接受多个值的上传字段,请尝试在浏览文件时选取一个以上的文件。
40   </p><form>选择图片:<input type="file" name="img" multiple="multiple" />
41   <input type="submit" /></form>
42   <p>这里pattern属性规定验证输入字段的模式,输入时请按要求输入3个字母的国家代码:
43   </p><form>国家代码:<input type="text" name="country_code" pattern="[A-z]{3}"
44   title="3个字母的国家代码" />
45   <input type="submit" /></form>
46   <!--模式指的是正则表达式,pattern属性适用于以下 <input> 类型:text, search, 
47   url, telephone, email以及password。pattern属性规定用于验证输入字段的模式。-->
48   <p>接下来演示输入字段预期值的属性,提供可描述输入字段预期值的提示信息,
49   该提示会在输入字段为空时显示,并会在字段获得焦点时消失。</p><form>
50   <input type="search" name="user_search" placeholder="输入字段预期值" />
51   <input type="submit" /></form>
52   <!--placeholder属性适用于以下的 <input> 类型:text, search, url,  password等。-->
53   <p>接下来我们演示的为required与size属性,required属性规定必须在提交之前填写输入字段。
54   如果不填写任何内容,则会有提示出现。</p><form>
55   姓名: <input type="text" name="usr_name" required="required" size="35"/>
56   <input type="submit" value="提交" /></form>
57   <!--required属性适用于以下 <input> 类型:text, search, url, telephone, email,
58    password, date pickers, number, checkbox, radio以及file。-->
59   </body></html>

目前为止我们便将表单标签的基础内容学习完毕,本节的内容有些繁杂,知识点零碎且每点都比较容易接受。

下面来看一下图像类、链接类与列表类的标签介绍,表1-9所示为图像链接列表标签及其描述,我们先来总体学习一下这些标签。

表1-9 图像链接列表标签及其描述

标  签

描  述

标  签

描  述

<img>

定义图像

<area>

定义图像地图内部的区域

<map>

定义图像映射

<command>

定义命令按钮

<figcaption>

定义figure元素的标题

<a>

定义超链接

<link>

定义文档与外部资源的关系

<nav>

定义导航链接

<ul>

定义无序列表

<ol>

定义有序列表

<li>

定义列表的项目

<dl>

定义列表

<dt>

定义列表中的项目

<dd>

定义列表中项目的描述

<menu>

定义命令的菜单/列表

<figure>

定义媒介内容的分组,以及它们的标题

<menuitem>

定义用户可以从弹出菜单中调用的命令/菜单项目

<canvas>

定义图形,在1.6节中会专门讲这部分的内容

看完这些标签的类型与描述后,先来看一下由这些标签制作出来的网页效果,通过观察这些标签效果,我们再来深究一下它们的具体用法。图1-9所示为图像链接列表标签应用实例。图中有一个图片加载失败信息,这是故意写错路径名进而显示alt属性的。

▲图1-9 Sample1_7图像链接列表标签应用案例效果

本部分标签因为篇幅问题分成了两部分,我们刚才看到的效果图为第一部分标签案例的示意图。本部分标签为图像标签与一部分列表标签的示例,表1-9列出的Canvas标签由于是本书的重点内容,所以放到了1.6节进行细致的讲述,先来看一下Sample1_7的案例开发过程。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_7.html。

1    <html><head><title>Sample1_7</title></head><body>
2    <p>这里演示img标签及其属性的用法,本标签创建的是被引用图像的占位空间。</p>
3    <img src="pic/H5.jpg"  alt="W3C的正式HTML5徽标" height="128" width="128" />
4    <img src="pic/H523.jpg"  alt="W3C的正式HTML5徽标" height="128" width="128" />
5    <!--src和alt为该标签的必需属性,在HTML中img标签没有结束标签,
6    第二个img标签演示如果图像不能显示,则显示alt属性。-->
7    <p>接下来演示的是为设置背景图片,如果图片小于页面那么图片会重复。</p>
8    <body background="pic/background1.png">
9    <p>接下来演示的是设置图像的对齐方式:</p>
10   <h2>未设置对齐方式的图像:</h2>
11   <p>图像 <img src ="pic/back.png"> 在文本中</p>
12   <h2>已设置对齐方式的图像:</h2>
13   <p>图像 <img src="pic/back.png" align="bottom"> 在文本中的对齐方式为bottom</p>
14   <p>图像 <img src ="pic/back.png" align="middle"> 在文本中的对齐方式为middle</p>
15   <p>图像 <img src ="pic/back.png" align="top"> 在文本中的对齐方式为top</p>
16   <!--其中bottom对齐方式是默认的对齐方式-->
17   <p>现在把图像作为链接来使用:
18   <a href="Sample1_6.html">
19   <img border="0" src="pic/back.png" /></a></p>
20   <p>现在演示带有可供单击区域的图像地图,其中每个区域都是一个超链接,
21   请单击图像上的星球,把它们放大。</p>
22   <img src="pic/xingqiu.jpg" border="0" usemap="#planetmap" alt="星球" />
23   <map name="planetmap" id="planetmap">
24   <area shape="circle" coords="180,139,14" href ="pic/jinxing.png"
25       target ="_blank" alt="金星" />
26   <area shape="circle" coords="129,161,10" href ="pic/shuixing.png"
27       target ="_blank" alt="水星" />
28   <area shape="rect" coords="0,0,110,260" href ="pic/sun.jpg"
29       target ="_blank" alt="太阳" /></map>
30   <!--area标签定义图像映射中的区域,它总会嵌套在map中,shape属性定义了区域形状,coords
31   为区域的坐标值,一般4个坐标值为矩形的左上角与右下角的坐标值xy;3个值为圆形
32   的原点坐标与半径;多边形poly的坐标为x1,y1,x2,y2,..,xn,yn。-->
33   <!--img元素中的 "usemap" 属性引用map元素中的 "id" 或 "name" 属性(根据浏览器而定),
34   所以应同时向map元素添加"id" 和 "name" 属性。以上几个例子在涉及href属性时
35   给出的是路径位置,这里也可以给URL。target属性值blank为在新链接中打开。-->
36   <p>接下来演示一下无序列表的使用,首先看到的是不同类型的无序列表:</p>
37   <h4>Disc 项目符号列表:</h4>
38   <ul type="disc">
39    <li>苹果</li><li>香蕉</li><li>柠檬</li><li>橘子</li>
40   </ul><h4>Circle 项目符号列表:</h4>
41   <ul type="circle">
42    <li>苹果</li><li>香蕉</li><li>柠檬</li><li>橘子</li>
43   </ul><h4>Square 项目符号列表:</h4>
44   <ul type="square">
45    <li>苹果</li><li>香蕉</li><li>柠檬</li><li>橘子</li></ul>  
46   <p>下面将看到嵌套类型的无序列表:</p>
47   <h4>一个嵌套列表:</h4><ul>
48     <li>咖啡</li><li>茶
49       <ul><li>红茶</li><li>绿茶</li></ul>
50     </li><li>牛奶</li></ul>
51     <!--标签li定义列表项目,无序列表标签ul常与有序列表标签ol一起使用。-->
52   </body></html>

看完前一部分的标签开发过程后,我们来学习剩下一部分的标签开发。在本案例中用到的几个链接统一规定将Sample1_4.html作为主页,在跳转主页时都跳转到此页上。另外对于图片路径,我们统一放到了pic目录下,读者练习时注意一下这些问题。

接下来看一下案例的开发过程。如果有读者在运行过程中加载不出图片,则应该是在设置路径时出现了一些问题。应该仔细确认图片的位置,然后再根据图片所在位置更改URL,之后再进行实验。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_8.html。

1    <html><head><title>Sample1_8</title></head><body>
2    <p>接下来看一下有序列表的使用,我们看到的是不同类型的有序列表:</p>
3    <h4>数字列表:</h4>
4    <ol><li>苹果</li><li>香蕉</li><li>柠檬</li><li>橘子</li></ol>  
5    <h4>字母列表:</h4>
6    <ol type="A">
7     <li>苹果</li><li>香蕉</li><li>柠檬</li><li>橘子</li></ol>  
8    <h4>小写字母列表:</h4>
9    <ol type="a">
10    <li>苹果</li><li>香蕉</li><li>柠檬</li><li>橘子</li></ol>  
11   <h4>罗马字母列表:</h4>
12   <ol type="I">
13    <li>苹果</li><li>香蕉</li><li>柠檬</li><li>橘子</li></ol>  
14   <h4>小写罗马字母列表:</h4>
15   <ol type="i">
16    <li>苹果</li><li>香蕉</li><li>柠檬</li><li>橘子</li>
17   </ol><!--有序列表的默认类型为阿拉伯数字,其余还有字母、小写字母、罗马字母等。-->
18   <p>接下来看一下定义列表标签dl的用法:</p>
19   <h2>一个定义列表:</h2>
20   <dl>
21      <dt>计算机</dt>
22      <dd>用来计算的仪器 ... ...</dd>
23      <dt>显示屏</dt>
24      <dd>以视觉方式显示信息的装置 ... ...</dd>
25   </dl>
26   <!--<dl> 标签用于结合 <dt>(定义列表中的项目)和 <dd>(描述列表中的项目)-->
27   <!--<menu>与<command>两个标签在各大主流浏览器中都不支持,由于<menuitem>只有Firefox浏览器
28       支持,所以这3个标签在这里不介绍。-->
29   <p>现在看一下超链接标签a的用法:</p>
30   <a href="http://www.baidu.com">Baidu</a>
31   <!--<a>用于从一个页面链接到另一个页面,在用于样式表时,<link> 标签得到了几乎
32   所有浏览器的支持,但是几乎没有浏览器支持其他方面的应用,所以在此便不再介绍link标签-->
33   <p>现在看一下HTML5标准中新增的标签nav的用法,本例中暂定案例1_4为主页:</p>
34   <nav><a href="Sample1_4.html">主页</a>
35   <a href="Sample1_3.html">前一页</a>
36   <a href="Sample1_5.html">后一页</a></nav>
37   <!--<nav> 标签定义导航链接的部分,IE 8以及之前的版本不支持本标签,其余的主流
38   浏览器都支持本标签。-->
39   <p>接下来看一下同一页面内的跳转:<br />
40   <a href="#C4">查看章节 4。</a></p>
41   <h2>章节1</h2>
42   <p>这里是章节内容</p>
43   <h2>章节2</h2>
44   <p>这里是章节内容</p>
45   <h2>章节3</h2>
46   <p>这里是章节内容</p>
47   <h2><a name="C4">章节 4</a></h2>
48   <p>这里是章节内容</p>
49   //……这里省略了部分代码,读者可以自行查阅随书源代码来查看
50   <p>被锁在框架中了吗?</p> 
51   <a href="Sample1_4.html" target="_top">请单击这里!</a> 
52   <!--target属性设置为_top,这个目标使得文档载入包含这个超链接的窗口,用 _top目标将会清除所有被
53        包含的框架并将文档载入整个浏览器窗口。-->
54   </body></html>

目前为止,图像、链接、列表标签的开发已完毕,本部分标签不多,但是每个标签的属性都不少,读者在学习时应将注意力放到各属性上。幸运的是,不少属性的作用与前面标签中的属性是一样的,读者学起来不会太难。

到目前为止需要学的主要标签将要介绍完毕,接下来介绍一下剩下的标签。这部分的标签表格与元信息我们会详细介绍,剩下部分的标签因为用到次数较少便不再赘述其开发过程,表1-10所示为表格、元信息等标签及其描述。

表1-10 表格、元信息等标签及其描述

标  签

描  述

标  签

描  述

<param>

定义对象的参数

<table>

定义表格

<object>

定义嵌入对象

<caption>

定义表格标题

<embed>

为外部应用程序定义容器

<th>

定义表格中的表头单元格

<script>

定义客户端脚本

<tr>

定义表格中的行

<vido>

定义视频

<td>

定义表格中的单元

<source>

定义媒介源

<thead>

定义表格中的表头内容

<audio>

定义声音内容

<tbody>

定义表格中的主体内容

<head>

定义关于文档的信息

<tfoot>

定义表格中的表注内容

<meta>

定义关于HTML文档的元信息

<colgroup>

定义表格中供格式化的列组

<base>

定义页面中所有链接的默认地址或默认目标

<col>

定义表格中一个或多个列的属性值

<noscript>

定义在脚本未能执行时的替代内容

<track>

定义用在媒体播放器中的文本轨道

表格标签<table>定义了HTML表格,简单的表格由table及一个或多个tr、th或td组成。复杂的HTML表格可能会包括caption、col、colgroup、thead、tfoot以及tbody元素。我们现在来看一下第一个表格类程序,图1-10所示为表格标签的案例效果。

▲图1-10 Sample1_9表格标签应用案例效果

本案例是本章的第一个表格类案例,通过案例运行效果图与标签介绍,我们便可以使用本部分介绍的表格标签案例创造出各种样式的且在日常生活中需要的类型表格,现在就来看一下案例Sample1_9的开发过程。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_9.html。

1    <html><head><title>Sample1_9</title></head><body>
2    <p>从现在开始学习表格标签的使用,首先看到的是table标签的用法:</p>
3    <h4>只有一行一列的表格:</h4>
4    <table border="1"><tr>
5      <td>100</td>
6    </tr></table>
7    <h4>一行三列的表格:</h4>
8    <table border="1"><tr>
9      <td>100</td><td>200</td><td>300</td>
10   </tr></table>
11   <h4>两行三列的表格:</h4>
12   <table border="1">
13     <tr><td>100</td><td>200</td><td>300</td></tr>
14     <tr><td>400</td><td>500</td><td>600</td></tr></table>
15   <!--每个表格由table标签开始,表格行由tr标签开始,每个数据由td标签开始。-->
16   <p>现在学习的是带有边框的表格:</p>
17   <h4>带有普通的边框:</h4>
18   <table border="1"><tr>
19     <td>100</td><td>200</td></tr>
20     <tr><td>300</td><td>400</td></tr></table>
21   <h4>带有粗的边框:</h4>
22   <table border="8"><tr>
23     <td>100</td><td>200</td></tr>
24     <tr><td>300</td><td>400</td></tr></table>
25   <h4>带有很粗的边框:</h4>
26   <table border="15">
27     <tr><td>100</td><td>200</td></tr>
28     <tr><td>300</td><td>400</td></tr></table>
29   <h4>这个表格没有边框:</h4>
30   <table><tr>
31     <td>100</td><td>200</td><td>300</td></tr>
32     <tr><td>400</td><td>500</td><td>600</td>
33   </tr></table>
34   <!--上面演示的均为边框示例,其中没边框时可以不加border属性,也可以使其值为0。
35   border属性为边框的宽度。-->
36   <p>接下来演示表格中的标题与如何为表格添加标题:</p>
37   <h4>表头:</h4>
38   <table border="1">
39     <tr><th>姓名</th><th>电话</th><th>电话</th></tr>
40     <tr><td>张三</td><td>123456</td><td>123455</td>
41   </tr></table>
42   <h4>垂直的表头:</h4>
43   <table border="1"><tr><th>姓名</th><td>李四</td>
44   </tr><tr><th>电话</th><td>12345</td>
45   </tr><tr><th>电话</th><td>21345</td></tr></table>
46   <h4>这个表格有一个标题,以及粗边框:</h4>
47   <table border="6">
48   <caption>这是标题</caption><tr>
49     <td>100</td><td>200</td><td>300</td></tr>
50     <tr><td>400</td><td>500</td><td>600</td></tr></table>
51   <!--表格的属性,行用tr来表示,td表示列,th相当于表头,table表示表格,
52   这几个标签构成表单最基本的形式。th为表格中的表头,caption为表格的标题。-->
53   </body></html>

由于篇幅有限,所以本节的标签分为三部分进行介绍,它们其实可以组合成为一个程序,但是这样代码有些长不利于读者学习。上面的示例为第一部分,接下来看一下第二部分的案例运行图,图1-11所示为部分表格标签效果。

▲图1-11 Sample1_10 表格标签应用案例效果

本部分案例主要讲述了表格中各种边框的显示形式与表格的嵌套形式。这些形式在CSS中也可以进行设置,程序中会具体分析在什么情况下用到哪种形式,有时层叠样式表比本节演示的要简单,有时不如本节演示的简单,我们来看一下具体的案例开发。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_10.html。

1    <html><head><title>Sample1_10</title></head><body>
2    <p>接下来演示如何定义跨行或跨列的表格单元格:</p>
3    <h4>横跨两列的单元格:</h4>
4    <table border="1"><tr>
5      <th>姓名</th><th colspan="2">电话</th></tr>
6      <tr><td>张三</td><td>123456</td><td>123455</td></tr></table>
7    <h4>横跨两行的单元格:</h4>
8    <table border="1"><tr>
9      <th>姓名</th><td>李四</td></tr>
10     <tr><th rowspan="2">电话</th><td>12345</td></tr>
11     <tr><td>21345</td></tr></table>
12   <!--colspan属性规定表头单元格可横跨的列数,rowspan属性规定表头单元格可横跨的行数。-->
13   <p>接下来演示一下在表格内如何使用其他类型的标签</p>
14   <table border="1"><tr><td>
15      <p>这是一个段落。</p><p>这是另一个段落。</p>
16     </td><td>这个单元包含一个表格:
17      <table border="1"><tr>
18        <td>100</td><td>200</td></tr>
19        <tr><td>300</td><td>400</td>
20      </tr></table></td>
21   </tr><tr>
22     <td>这个单元包含一个列表:
23      <ul><li>苹果</li><li>香蕉</li><li>菠萝</li>
24      </ul></td><td>HELLO</td>
25   </tr></table>
26   <!—从本部分可以看出,如果想在表格内部嵌套一些其他标签,则直接在td标签内部继续添加标签即可。-->
27   <p>现在我们要演示单元格边沿与内容的距离,以及单元格之间的距离这两个属性的应用:</p>
28   <h4>没有cellpadding,即单元格与内容之间没有距离:</h4>
29   <table border="1"><tr>
30     <td>100</td><td>200</td></tr>
31     <tr><td>300</td><td>400</td></tr></table>
32   <h4>带有cellpadding,即单元格与内容之间有距离:</h4>
33   <table border="1" cellpadding="10"><tr>
34     <td>100</td><td>200</td></tr>
35     <tr><td>300</td><td>400</td></tr></table>
36   <!--cellpadding属性规定单元边沿与其内容之间的空白。-->
37   <h4>带有cellspacing:</h4>
38   <table border="1" cellspacing="10"><tr>
39     <td>100</td><td>200</td></tr>
40     <tr><td>300</td><td>400</td></tr></table>
41   <!--cellspacing属性规定的是单元之间的空间。从实用角度出发,
42   最好不要规定cellpadding,而是使用CSS来添加内边距。-->
43   </body></html>

到目前为止,剩下了为数不多的几个标签没有介绍,其中还包括一些今后开发中不常用的一些标签。由于在WebGL的开发中不常用,所以在此不再赘述。我们先来看一下图1-12所示的剩下的一些标签的案例运行效果。

▲图1-12 Sample1_11 表格标签应用案例效果

看了这些标签案例的示意图后,不难发现与上一个案例的内容其实是很相近的。所以本部分的标签也是在讲述表格标签的格式与样式。使用过Excel表格的读者都知道表格的排版其实也挺麻烦的,在之前与将要介绍的案例中会包含用得最多的一些格式,现在来看一下案例的开发过程。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_11.html。

1    <html><head><title>Sample1_11</title></head><body>
2    <p>接下来看一下如何向表格与单元格内部添加背景颜色或者背景图片:</p>
3    <h4>为表格添加背景颜色:</h4>
4    <table border="1" bgcolor="red">
5    <tr><td>100</td><td>200</td></tr>
6     <tr><td>300</td><td>400</td></tr></table>
7    <h4>为表格单元添加背景颜色:</h4>  
8    <table border="1"><tr>
9      <td bgcolor="red">100</td><td>200</td></tr>
10     <tr><td bgcolor="blue">300</td><td>400</td></tr></table>
11   <p>现在用align属性在单元格中排列内容</p>
12   <table width="400" border="1"><tr>
13     <th align="left">消费项目....</th>
14     <th align="right">一月</th>
15     <th align="right">二月</th></tr>
16     <tr><td align="left">衣服</td>
17     <td align="right">$100</td>
18     <td align="right">$200</td></tr>
19     <tr><td align="left">化妆品</td>
20     <td align="right">$100</td>
21     <td align="right">$150</td></tr>
22     <tr><td align="left">食物</td>
23     <td align="right">$500</td>
24     <td align="right">$600</td></tr>
25     <tr><th align="left">总计</th>
26     <th align="right">$700</th>
27     <th align="right">$950</th></tr></table>
28    <!--align属性规定单元格内容的水平对齐方式。其值除了left、right之外还有center(居中对齐)、
29    justify(对行进行伸展),这样每行都可以有相等的长度,char将内容对准指定字符。-->
30    <p>接下来演示如何使用 "frame" 属性来控制围绕表格的边框:</p>
31   <p>表格的frame属性为box:</p>
32   <table frame="border"><tr>
33       <th>月份</th><th>消费</th></tr>
34       <tr><td>一月</td><td>$100</td></tr></table>
35   <p>表格的frame属性为above:</p>
36   <table frame="above"><tr>
37       <th>月份</th><th>消费</th></tr>
38       <tr><td>一月</td><td>$100</td></tr></table>
39   <p>表格的frame属性为below:</p>
40   <table frame="below"><tr>
41       <th>月份</th><th>消费</th></tr>
42       <tr><td>一月</td><td>$100</td></tr></table>
43   <p>表格的frame属性为hsides:</p>
44   <table frame="hsides"><tr>
45       <th>月份</th><th>消费</th></tr>
46       <tr><td>一月</td><td>$100</td></tr></table>
47   <p>表格的frame属性为vsides:</p>
48   <table frame="vsides"><tr>
49       <th>月份</th><th>消费</th></tr>
50       <tr><td>一月</td><td>$100</td></tr></table>
51   <!--frame属性无法在IE中正确地显示。除了以上示意的5个值之外,还有void(不显
52   示外边框)、lhs(显示左边的外侧边框)、rhs(显示右边的外侧边框)、border(在所有边上显示外边框)。不过
53   从实用角度出发,最好不要规定frame,而是使用CSS来添加边框样式。-->
54   </body></html>

到此为止我们介绍完了HTML中的标签,因为本书的主体部分并不是HTML,所以介绍的这些标签省略了一部分,但是这些足以应付在今后开发WebGL时遇到的问题。我们在此只是介绍了其中的基础用法,所以在今后的开发中我们还应该多学习此方面的更多知识。

在上面介绍标签时就不止一遍地说过局部属性与全局属性,局部属性在介绍标签时我们已经介绍过局部属性中比较重要的一部分了,剩下的一些不常用的局部属性不再介绍。现在讲述一下HTML中的全局属性,如表1-11所示。

表1-11 HTML全局属性

属  性

描  述

属  性

描  述

contenteditable

规定元素内容是否可以编辑

accesskey

规定激活元素的快捷键

dir

规定元素内容的文本方向

draggable

规定元素是否可拖动

hidden

规定元素仍未或不再相关

id

规定元素的唯一id

data-*

用于存储页面或应用程序的私有定制数据

contextmenu

规定元素的上下文菜单。上下文菜单在用户单击元素时显示

Lang

规定元素内容的语言

spellcheck

规定是否对元素进行拼写和语法检查

style

规定元素的行内CSS样式

tabindex

规定元素的Tab键次序

title

规定有关元素的额外信息

translate

规定是否应该翻译元素内容

class

规定元素的一个或多个类名(引用样式表中的类)

dropzone

规定在拖动或被拖动数据时是否进行复制、移动或链接

全局属性适用于HTML中的各种标签,因为这些属性在平时开发的时候会经常用到,所以我们在本节中将其集中起来,然后将每个属性详细地介绍给大家,其中有一两个没介绍是因为主流浏览器并未支持该属性。现在先来看一下图1-13所示的部分全局属性示例。

▲图1-13 Sample1_12全局属性应用案例效果

在本例中演示了全局属性中的一部分,因为这些属性可以在支持全局属性的标签中使用,基本为全部的标签,所以这里只是演示了其中几种标签的全局变量的使用方法,在应用时读者也可以使用别的标签进行试验。下面我们来看一下程序的开发过程。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_12.html。

1    <!DOCTYPE html>
2    <html><head><title>Sample1_12</title>
3    <script type="text/javascript">
4    function change_header(){
5    document.getElementById("myHeader").innerHTML="Nice day!";}</script>
6    <style type="text/css">
7    h1.intro {color:blue;}
8    p.important {color:red;}</style>
9    <!--此处为样式表内容,在后面对此会有介绍,这里不进行详细介绍。-->
10   <style type="text/css">
11   h1.intro1{color:blue;}
12   .important1{background-color:yellow;}</style></head>
13   <body>
14   <p>首先来演示accesskey,其实质就是为某元素设置快捷键,使其获得焦点。</p>
15   <a href="http://www.baidu.com" accesskey="b">百度(accesskey键设为b)</a><br />
16   <a href="http://www.sina.com" accesskey="s">新浪(accesskey键设为s)</a>
17   <!--请使用Alt+accesskey或者Shift+Alt+accesskey来访问带有指定快捷键的元素,一般
18   这个属性用在<a>、<area>、button>、<input>、<label>、<legend>等标签中。-->
19   <p>现在演示class属性的应用,第一个示例为单个class值,
20   第二个示例为一个标签应用多个class值</p>
21   <h1 class="intro">h1标题1演示单个class属性值</h1>
22   <p class="important">请注意这个重要的段落。:)</p>
23   <p>现在演示一下应用多个classs值的案例:</p>
24   <h1 class="intro1 important1">h1演示多个class属性,只要在声明第一个值时加上空
25   格,之后再写入值即可</h1>
26   <!--class属性大多数时候用于指向样式表中的类(class)。不过,也可以利用它通过 
27   JavaScript来改变带有指定class的HTML元素。-->
28   <p>现在来讲述一下规定元素是否可编辑的属性应用:</p>
29   <p contenteditable="true">这里是一段可以编辑的段落,读者可以将光标点到这里自行编辑。</p>
30   <!--需要注意的是,元素中如果未设置contenteditable,则本元素会继承其父类元素。-->
31   <p>接下来看一下规定元素内容文本方向的属性应用:</p>
32   <p dir="rtl">文本方向为从右向左!</p>
33   <!--dir属性在以下标签中无效:<base>、<br>、<frame>、<frameset>、<hr>、<iframe>,
34    <param> 以及 <script>。dir的值有rtl与ltr两个值分别为从右到左与从左到右。-->
35   <p>现在看一下隐藏属性hidden,下面有两段话,一段有隐藏属性一段没有隐藏属性:</p>
36   <p hidden="hidden">这是一段隐藏的段落。</p>
37   <p>这是一段可见的段落。上面还有一段隐藏段落,这里我们只是在做实验。</p>
38   <!--hidden属性也可防止用户查看元素,直到某些条件(比如选择了某个复选框)匹配。
39   JavaScript可以删除 hidden属性,以使此元素可见。-->
40   <h1 id="myHeader">Hello World,这里演示了id属性的应用,用JavaScript取得本
41   元素id然后改变本元素的内容。</h1>
42   <button onclick="change_header()">改变文本</button>
43   <!--id属性规定HTML元素的唯一id,id属性可用作链接锚(link anchor),
44   通过 JavaScript(HTML DOM)或通过 CSS为带有指定id的元素改变或添加样式。-->
45   <p>这里为lang属性值的演示,对于lang属性值,必须使用有效的ISO语言代码。</p>
46   <p lang="fr">Ceci est un paragraphe.</p>
47   <p lang="en">Hello, How are you?</p>
48   <!--本属性可让浏览器调整表达元素内容的方式,可以使网页只显示某种特定语言。-->
49   </body></html>

上面案例为全局属性中的一部分,下面我们来介绍剩下一部分属性。在开发时或多或少都会用到样式表与开发的一些JavaScript 脚本,读者在看这些部分时不必着急,因为在下面的章节中会讲到CSS。至于JavaScript,本书开发的重点就是这部分,在以后的章节中我们会介绍这些内容。

图1-14所示为剩下的属性代码运行效果,看完了图后我们便发现本部分案例的内容并不多,但是这部分内容中的脚本有点繁杂,在开发时不进行重点讲述,因为这些东西会在下面的章节中专门介绍。读者看到这部分时可先跳过,主要看属性的开发。

▲图1-14 Sample1_13全局属性应用案例效果

代码位置:随书源代码/第1章目录下的HTML5/Sample1_13.html。

1    <!DOCTYPE html>
2    <html><head><title>Sample1_13</title></head>
3    <style type="text/css">
4    #div1 {width:350px;height:70px;padding:10px;border:1px solid #aaaaaa;}
5    </style><script type="text/javascript">
6    function allowDrop(ev){
7    ev.preventDefault();}
8    function drag(ev){
9    ev.dataTransfer.setData("Text",ev.target.id);}
10   function drop(ev){
11   var data=ev.dataTransfer.getData("Text");
12   ev.target.appendChild(document.getElementById(data));
13   ev.preventDefault();}</script>
14   <body>
15    <p>现在演示元素是否可拖动的属性draggable,下面一段话可以拖动到文本域中:</p>
16   <div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div><br />
17   <p id="drag1" draggable="true" ondragstart="drag(event)">
18   这是一段可移动的段落。请把该段落拖入上面的矩形内。</p>
19   <!--在head部分定义了div的样式,在下一节中会有专门的关于层叠样式表的讲述。
20   ondrop、ondragover、ondragstart为标签中的事件属性,它们表示元素被拖动时运行的脚本、当元素在
21   有效拖放目标上正在被拖动时运行的脚本、在拖动操作开端运行的脚本。这些事件属性表示当触发
22   这些事件时,会调用相应的JavaScript脚本方法,这些方法在head部分中已经写好。-->
23   <p>现在看一下style属性的应用:</p>
24   <h1 style="color:blue;text-align:center">这里为h1标题</h1>
25   <p style="color:red">这里为一个段落</p>
26   <!--style属性规定元素的行内样式(inline style),style属性将覆盖任何全局样式的设定,-->
27   <p>tabindex属性规定元素的Tab键控制次序,1是第一个</p>
28   <a href="http://www.baidu.com" tabindex="2">Baidu</a><br />
29   <a href="http://www.sina.com" tabindex="1">Sina</a><br />
30   <a href="http://www.w3school.com.cn/" tabindex="3">W3school</a>
31   <!--请尝试使用键盘上的 "Tab" 键在链接之间进行导航。-->
32   <p>下面将演示title属性的使用,title属性规定了元素的额外信息。</p>
33   <abbr title="World Wide Web Consortium">W3C</abbr> was founded in 1994.
34   <!--这些信息通常会在鼠标移到元素上时显示一段工具提示文本,title属性常与form 
35   以及a元素一同使用,以提供关于输入格式和链接目标的信息。同时它也是abbr和 
36   acronym元素的必需属性。-->
37   <p contenteditable="true" spellcheck="true">这里是可编辑的段落,请尝试编辑文本。</p>
38   <!--spellcheck属性规定是否对元素进行拼写和语法检查。-->
39   </body></html>

到此为止,我们便介绍完HTML中的全局属性了。其实到现在我们就可以开发出界面精美的网页了,但是还有一些功能实现不了,因为还没有介绍事件,通过事件的发生来调用自行开发的脚本便可以达到自己想要的效果了。

在 HTML 4 中增加了使事件在浏览器中触发动作的功能,比如用户单击元素时启动JavaScript,页面加载完毕后需要执行哪段代码,元素失去焦点时运行哪段脚本,鼠标单击或者移动时运行什么脚本等。在HTML5中又新加了不少新的事件,我们来看一下这些事件。

表 1-12所示为部分事件及其描述,接下来先看一下这些事件的案例开发效果图,如图1-15所示。因为本部分案例是在某些事件发生时才会触发的,所以效果图中不能显现出所有事件的运行效果,读者可自己去验证这些事件。

表1-12 HTML5中的事件

事  件

描  述

事  件

描  述

onafterprint

文档打印后运行的脚本

onbeforeprint

文档打印前运行的脚本

onload

页面加载介绍后运行的脚本

onresize

当浏览器窗口被调整大小时触发

onunload

一旦页面已下载则触发

onblur

元素失去焦点时运行的脚本

onchange

元素值被改变时运行的脚本

onfocus

当元素失去焦点时运行的脚本

onselect

当元素中文本被选中后触发

onsubmit

在提交表单时触发

onkeydown

在用户按下按键时触发

onkeypress

在用户敲击按钮时触发

onkeyup

在用户释放按键时触发

onclick

在元素上发生鼠标单击时触发

ondblclick

元素上发生鼠标双击时触发

onmousedown

在元素上按下鼠标按钮时触发

onmousemove

当鼠标指针移动到元素上时触发

onmouseup

在元素上释放鼠标按钮时触发

onmouseout

当鼠标指针移出元素时触发

onmouseover

当鼠标指针移动到元素上时触发

我们这里只演示一小部分事件,意在向读者介绍事件的基本用法,读者在日后的开发中肯定会遇到其他事件或者应用到其他事件。这里的示例仅为冰山一角,大家还需要自行查阅一些资料以了解事件属性。接下来看一下图1-15所示的案例开发过程。

▲图1-15 Sample1_14全局属性应用案例效果

代码位置:随书源代码/第1章目录下的HTML5/Sample1_14.html。

1    <!DOCTYPE html>
2    <html><head><title>Sample1_14</title>
3    <script>
4    function printmsg(){                    //文档打印之后执行的脚本方法
5    alert("此文档现在正在打印!");}
6    function load(){                        //页面加载完成后需要执行的脚本方法
7    alert("页面已加载!");}
8    function showMsg(){                     //浏览器窗口尺寸发生改变时执行的脚本方法
9    alert("您已改变浏览器窗口的尺寸!");}
10   function upperCase(){                   //元素失去焦点时执行的脚本方法
11   var x=document.getElementById("fname").value;
12   document.getElementById("fname").value=x.toUpperCase();}
13   function checkField(val){               //在元素值改变时执行的脚本
14   alert("输入值已更改。新值是:" + val);}
15   function copyText(){                    //单击鼠标时执行的脚本
16   document.getElementById("field2").value=document.getElementById("field1").value;}
17   function mouseDown(){                   //鼠标按下时执行的脚本
18   document.getElementById("p1").style.color="red";}
19   function mouseUp(){                     //鼠标抬起时执行的脚本
20   document.getElementById("p1").style.color="green";}
21   </script></head>
22   <body onafterprint="printmsg()" onload="load()" onresize="showMsg()">
23   <p>在本部分案例中实验事件执行脚本时只写了alert,这里只是一个示例,
24   在实际开发中应该在对应部分开发出需要的代码。</p>
25   <h1>请尝试打印此文档,这时候会有提示出现。</h1>
26   <p>onbeforeprint事件与onafterprint事件的用法一样,一个是在打印之
27   前执行脚本,一个是在打印之后执行脚本。</p>
28   <!--IE和Firefox支持onafterprint属性。在IE中,
29   onafterprint属性在打印对话框出现之前而不是之后。-->
30   <p>body元素中还有一个onload事件,该事件是在页面加载完毕后执行脚本。</p>
31   <p>onresize事件为当浏览器窗口改变时执行的脚本,本案例也进行了演示,
32   读者可以改变浏览器窗口大小看一下结果。</p>
33   <p>请随意输入一段英文字符,然后把焦点移动到字段外(鼠标单击输入框之外):</p>
34   请随意输入一段英文字符,在本元素失去焦点时小写字母会变为大写字母:
35   <input type="text" name="fname" id="fname" onblur="upperCase()">
36   <p>请修改输入字段中的文本,然后在字段外单击以触发onChange。</p>
37   请输入文本:<input type="text" name="txt" value="Hello" 
38       onchange="checkField(this.value)">
39   <p>当按钮被单击时触发函数。此函数把文本从Field1复制到Field2中。</p>
40   Field1: <input type="text" id="field1" value="Hello World!"></br>
41   Field2: <input type="text" id="field2"><br><br>
42   <button onclick="copyText()">复制文本</button>
43   <p id="p1" onmousedown="mouseDown()" onmouseup="mouseUp()">
44   请单击文本!当鼠标按钮在段落上被按下时触发mouseDown() 函数,此函数把文本
45   颜色设置为红色。在鼠标按钮被释放时触发mouseUp() 函数,mouseUp() 函数把文本
46   颜色设置为绿色。</p>
47   </body></html>

到此为止,HTML事件便介绍完毕了。因为篇幅有限,所以很多事件没有列出来也没有进行用法解释,读者若是需要这方面的内容,则可以在网上查找相关资料。事件部分并不困难,它的精髓在于JavaScript脚本的开发过程,我们在后面的章节中会将其介绍给大家。

CSS(层叠样式表)用来规定HTML文档的呈现形式和格式编排,本节会向读者简要介绍CSS。此部分不是我们开发的重点,讲解如何创建和应用CSS样式等以为将来的开发打下基础。把样式添加到HTML中是为了解决内容与表现分离的问题。

HTML标签原本被设计用于定义文档内容,同时文档布局由浏览器来完成,而不使用任何的格式化标签。由于HTML标签与属性不断被添加到HTML的规范中,创建文档内容使其清晰地独立于文档表现层的站点会变得越来越困难,所以W3C在HTML 4.0之外创造出样式。


样式表定义如何显示HTML元素,样式通常保存在外部的.CSS文件中。通过编辑一个简单的CSS文档,外部样式表使你有能力同时改变站点中所有页面的布局和外观。由于它允许同时控制多重页面的样式和布局,所以CSS可以称得上Web设计领域的一个突破。

作为开发者可以为每个元素定义好样式,并将其应用到不同的页面中。也可以进行全局布置,只需要简单地改变样式,然后网站中的所有元素均会自动更新。这样的工作方式大大减少了开发时间,提高了开发效率。

h1 {color:red; font-size:14px;}

上述代码为CSS的基本定义,并且代码中定义了多种样式信息。样式规定可以在单个的HTML元素中,在HTML 页的头元素中,或在一个外部的CSS文件中,甚至可以在同一个HTML文档内部引用多个外部样式表。

注意

一般而言,所有样式会根据下面的规则层叠于一个新的虚拟样式表中,其中数字4拥有最高优先权。

1.浏览器默认设置。

2.外部样式表。

3.内部样式表(位于 <head> 标签内部)。

4.内联样式(在HTML元素内部)。

内联样式(在HTML元素内部)拥有最高优先权,这意味着它将优先于以下的样式声明:<head> 标签中的样式声明,外部样式表中的样式声明,浏览器中的样式声明(默认值)。


CSS 规则由两个主要的部分构成,分别是选择器和一条或多条声明。选择器通常是需要改变样式的HTML元素,每条声明由一个属性与一个值构成,如果有多条属性即有多条声明,那么就用分号分开。声明中的属性为我们需要改变的样式属性,在下面的小节中我们会重点讲述它们。

声明样式时需要用大括号(花括号)包围声明,我们来看一下图1-16,所示代码为上一节介绍的那行代码,以此为例我们来看一下选择器部分为h1元素并且后面花括号中为两条声明,它们分别包含着属性与各自需要的值。

▲图1-16 CSS样式表声明

如果要定义多个声明,则需要用分号将每个声明分开。最后一条规则是不需要加分号的,因为分号在英语中是一个分隔符号,不是结束符号。然而,平时有经验的人都会在每条声明的末尾加上分号,这样的好处是,当从现有的规则中增减声明时,会尽可能地减少出错的可能性。

由于大多数样式表中不止有一条声明,所以在编辑时适时使用空格会使样式表更容易编辑。是否包含空格不会影响CSS在浏览器中的工作效果,但是加上空格后不论是自己还是其他人都会比较容易理解代码的结构。

h1,h2,h3,h4,h5,h6 { color: green;}

上述代码演示的为选择器的分组,在开发过程常会遇到多个选择器需要的样式是一样的,此时我们便会像上述代码一样编写而不是每个选择器写一遍。用逗号将选择器分开,这样这些选择器便会享有同样的声明。

在CSS中子元素继承父元素的属性,但是它并不总按照此方式工作。我们来看一下下面一行代码,根据继承原则来看,站点的body元素将使用Verdana字体。通过继承规则所有的子元素都会继承父元素(body)的属性,事实上也是这么回事。

body {font-family: Verdana, sans-serif;}

在浏览器大战的年代里,这种情况则未必会发生,那时候对标准的支持并不是企业的优先选择。比方说,Netscape 4就不支持继承,它不仅忽略继承,而且也忽略应用于body元素的规则。从IE/Windows直到IE6还存在相关的问题,表格内的字体样式会被忽略。

那么此时我们该怎么办呢?幸运的是,可以使用名为"Be Kind to Netscape 4" 的冗余法则来处理旧式浏览器无法理解的继承问题。IE4浏览器无法理解继承,不过它们可以理解组选择器。这么做虽然会浪费一些用户的带宽,但是如果需要对Netscape 4用户进行支持,就不必这么做。

1    body  {font-family: Verdana, sans-serif;}
2    p, td, ul, ol, li, dl, dt, dd  {font-family: Verdana, sans-serif;}

如果希望父元素中的某些元素不继承父类的属性,这时也可以像上述代码一样在声明完body元素的样式以后,单独声明一下与父类元素不同的元素样式,这样也就巧妙地避开了所有的子元素都必须继承父元素的问题。

当读到一个样式表时,浏览器会根据它来格式化HTML文档。插入样式表的方法有3种,外部样式表、内部样式表、内联样式。

当样式需要应用于很多页面时,外部样式表为首选。在使用外部样式表的情况下,可以通过改变一个文件来改变整个站点的外观。每个页面使用 <link> 标签链接到样式表。<link> 标签在(文档的)头部。下面代码就是如何引入外部样式表的示例。

<head><link rel="stylesheet" type="text/css" href="mystyle.css" /></head>

浏览器会从文件mystyle.css中读到样式声明,并根据它来格式化文档。外部样式表可以在任何文本编辑器中进行编辑,文件不能包含任何的html标签,样式表应该以 .css扩展名进行保存。下面是一个样式表文件的例子。

1    hr {color: sienna;}
2    p {margin-left: 20px;}
3    body {background-image: url("images/back40.gif");}

上述内容为一个简单的外部样式表文件,该文件以.css扩展名结尾。在编写这部分文件时需要注意,不要在属性值与单位之间留有空格。例如使用“margin-left: 20 px”而不是“margin-left: 20px”,它仅在IE 6中有效,但是在Firefox或Netscape中却无法正常工作。

有时候会遇到单独的某个界面需要特殊的样式,这时候外部样式表不再方便,我们会用其他的方法代替外部样式表,它就是内部样式表。内部样式表中使用<style>标签在文档头部定义内部样式表,其用法与其余标签并无多大差别,我们来看一下下面这个例子。

1    <html><head>
2    <style type="text/css">
3    h1 {color: red}
4    p {color: blue}
5    </style></head>
6    <body><h1>header 1</h1>
7    <p>A paragraph.</p>
8    </body></html>


说明 

本段代码单纯表示了<style>标签的用法,在style中,可以规定在浏览器中如何呈现HTML文档。type属性是必需的,它定义style元素的内容。唯一可能的值是 "text/css"。style元素位于head部分中。


除了上述两种插入样式表的方法外,还有内联样式,由于要将表现和内容混杂在一起,所以内联样式会损失掉样式表的许多优势。请慎用这种方法,要想使用内联样式,你需要在相关的标签内使用样式的style属性。style属性可以包含任何CSS属性。

1    <p style="color: sienna; margin-left: 20px">
2    This is a paragraph</p>

上述代码展示了如何改变段落的颜色和左外边距,在段落标签中使用了<style>属性。使用<style>属性比起前两种方法来说,当页面需要的样式比较多时,这会相当麻烦,这便损失了样式表的优势。

本节我们会就CSS的某些样式(比如背景、文本、字体、链接等)来详细讲解其用法,会有翔实的代码与运行效果图来帮助我们理解这些样式。本节介绍的都是CSS的基础样式,许多CSS的高级应用我们并没有讲述由于篇幅限制,有兴趣读者可以自己查找资料学习。

1.CSS背景应用

CSS允许应用纯色作为背景,也允许使用背景图像创建相当复杂的效果。CSS在这方面的能力远在HTML之上。本节在应用各种背景案例时也会将CSS背景的属性介绍给大家,读者在学习的同时也应注意这方面内容。

图 1-17 所示为CSS背景属性应用。本案例中的背景图片是放置在中间并且当滚动条被拖动时背景图片不会改变位置,始终在center位置。本部分内容除了书中讲述的以外,读者还需注意代码内容,段落标签与注释中的很多内容说明了该属性的注意事项,现在看一下案例的开发过程。

▲图1-17 Sample1_15背景属性应用案例效果

代码位置:随书源代码/第1章目录下的HTML5/Sample1_15.html。

1    <!DOCTYPE html>
2    <html><head><title>Sample1_15</title>
3    <style type="text/css">
4    body {background-image:url(pic/background1.png);
5    background-repeat: no-repeat;
6    background-attachment:fixed;
7    background-position:center;}
8    <!--背景图片的重复方式,此时为在不设置重复方式。x为在水平方向上重复,
9    不加x或者y时为水平方向与垂直方向上都重复。no-repeat为不重复只显示一张图片。
10   attachment属性设置为fixed才能保证position属性在Firefox与Opera中正常工作。
11   对于设置位置,除了规定的几个值之外,我们还可以自定%与像素值,并用两个百分数
12   代替center。-->
13   h1 {background-color: #00ff00}
14   h2 {background-color: transparent}
15   p.no1{background-color: rgb(250,0,255)}
16   p.no2 {background-color: gray; padding: 20px;}
17   span.highlight{
18   background-color:blue}
19   <!--background-color后跟的颜色值为设置的背景颜色,因为本例设置了背
20   景图片,所以就没有设置背景颜色,若想设置主体的背景颜色,则直接将
21   background-image改为color即可。若想在具体的某些元素中应用背景,那么直接在
22   样式表中相应元素的位置下设置background color或者image即可,这里演示了设置背景颜色
23   的方式,背景图片与其类似,不再演示。-->
24   </style></head>
25   <body>
26   <h1>这是标题 1</h1><h2>这是标题 2</h2>
27   <p class="no1">这是段落</p>
28   <p class="no2">这个段落设置了内边距。</p>
29   <p><span class="highlight">这是文本。</span> 这是文本。 这是文本。 这是文本。
30    这是文本。 这是文本。 这是文本。 这是文本。 这是文本。 这是文本。 这是文本。
31    这是文本。 这是文本。 这是文本。 这是文本。 这是文本。 这是文本。
32    <span class="highlight">这是文本。</span></p>
33   <p>如此编写代码是为了演示在这样设置背景图片时,图像不会随页面的其余部分滚动。</p>
34   <p>我们除了可以在style部分逐条设置属性之外,还可以这样设置,其与上面那样设置效果一样,</br>
35   但是不容易分辨。background: #ff0000 url(pic/background1.png) no-repeat fixed center</p>
36   <p>现在介绍一下CSS背景中的属性:</p>
37   <p>background为简写属性,其作用是将背景属性设置在一个声明中。</p>
38   <p>background-attachment为背景图片是否固定或随页面其余部分移动,</br>
39   除了上面的fixed之外还有scroll,它为默认值图像会随着页面移动。
40   inherit规定从父元素继承本属性的设置。</p>
41   <p>background-color设置背景颜色</p>
42   <p>background-image设置背景图片</p>
43   <p>background-position设置图片的起始位置</p>
44   <p>设置起始位置的值,不论用固定的几个值还是自定义的%或者像素</p>
45   <p>都为两个值,如果只规定了一个值那么第二个值默认会为50%或者center</p>
46   <p>top、bottom、center会与left、right、center搭配。</p>
47   <p>background-repeat设置背景图片的重复方式</p>
48   <p>其值有no-repeat(不重复),repeat-x(水平方向重复)</p>
49   <p>repeat-y(垂直方向重复),repeat(水平方向与垂直方向都重复)默认值</p>
50   <p>inherit为继承父元素本属性的值。</p>
51   <p>图像不会随页面的其余部分滚动。</p>
52   ……//此处省略一些同类代码,读者可以自行查阅随书源代码。
53   </body></html>

CSS背景应用基础属性的讲解到这里已经结束,虽然案例中的讲述十分简单,但是我们可以看到页面背景的一大部分。结合本节所学用的一些技巧,我们可以开发出很多精美的页面,读者学到这些基本内容后应该勤加练习才能掌握开发精美界面的技巧。

2.CSS文本应用

在日常浏览网页时不难发现,页面中的大部分内容是各种文本,所以文本的排版应用在HTML开发中占有很重要的地位。比起在每段文本标签中都加入文本样式,用统一的样式表来设置这些文本会更加简便。

图1-18所示为CSS文本案例应用效果,CSS文本属性可定义文本的外观。通过文本属性,可以改变文本的颜色、字符间距,以及对齐文本、装饰文本和对文本进行缩进等。在本案例中这些属性全部应用了,现在来看一下开发过程。

▲图1-18 Sample1_16全局属性应用案例效果

代码位置:随书源代码/第1章目录下的HTML5/Sample1_16.html。

1    <!DOCTYPE html>
2    <html><head><title>Sample1_16</title>
3    <style type="text/css">
4    body {color:red}
5    h1 {color:#00ff00}
6    p.ex {color:rgb(0,0,255)}
7    h2 {letter-spacing: -0.5em}
8    h4 {letter-spacing: 20px}
9    p.small {line-height: 90%}
10   p.big {line-height: 200%}
11   p.small1{line-height: 0.5}
12   p.big1{line-height: 2}
13   h3 {text-align: center}
14   h5 {text-align: left}
15   h6 {text-align: right}
16   p.a{text-decoration: overline}
17   p.b{text-decoration: line-through}
18   p.c{text-decoration: underline}
19   p.d{text-decoration: blink}
20   p.e{text-indent: 1cm}
21   p.s{word-spacing: 90px;}
22   p.t{word-spacing: -0.5em;}
23   </style></head>
24   <body>
25   <h1>这是标题1</h1>
26   <p>这是一段普通的段落。请注意,该段落的文本颜色是红色的。在body 
27   选择器中定义了本页面默认的文本颜色。</p>
28   <p class="ex">该段落定义class的值为ex。所以该段落中的文本是蓝色的。</p>
29   <p>下面为设置字符之间的间距与行间距:</p>
30   <h2>这里为标题2</h2><h4>这里为标题4</h4>
31   <p>这是拥有标准行高的段落。</br>
32   在大多数浏览器中默认行高是110%~120%。</br></p>
33   <p class="small">这个段落拥有更小的行高。</br>这个段落拥有更小的行高。</p>
34   <p class="big">这个段落拥有更大的行高。</br>这个段落拥有更大的行高。</p>
35   <p>现在的行高是像素规定的,这是拥有标准行高的段落。</br>默认行高大约是1。</p>
36   <p class="small1">这个段落拥有更小的行高。</br>这个段落拥有更小的行高。</p>
37   <p class="big1">这个段落拥有更大的行高。</br>这个段落拥有更大的行高。</p>
38   <p>接下来演示如何对齐文本:</p>
39   <h3>这是标题 3</h3><h5>这是标题 5</h5><h6>这是标题 6</h6>
40   <p class="a">这里的文本修饰是overline</p>
41   <p class="b">这里的文本修饰是line-through</p>
42   <p class="c">这里的文本修饰是underline</p>
43   <p class="d">这里的文本修饰是blink</p>
44   <p class="e">现在我们来看缩进文本,这里就是缩进文本示例。</p>
45   <p class="e">现在我们来看缩进文本,这里就是缩进文本示例。</p>
46   <p class="e">现在我们来看缩进文本,这里就是缩进文本示例。</p>
47   <p class="e">现在我们来看缩进文本,这里就是缩进文本示例。</p>
48   <p class="e">现在我们来看缩进文本,这里就是缩进文本示例。</p>
49   <p class="e">现在我们来看缩进文本,这里就是缩进文本示例。</p>
50   <p class="s">This is some text.</p><p class="t">This is some text.</p>
51   </body></html>

页面中的文本是HTML开发中有多种变化的一部分。由于在开发时需要每部分文本设置不同的文本样式,所以本部分介绍的属性读者应该熟练掌握,并且勤加练习。在练习的时候可以更改不同的值以达到学以致用的目的。

3.CSS字体应用

上一节介绍了页面中文本样式表的设置方法,本节我们来细化这个问题。设置好文本样式后,我们来设置一下组成文本的字体样式,CSS字体属性定义文本的字体系列、大小、加粗、风格(如斜体)和变形(如小型大写字母)。

图1-19所示为CSS字体案例应用效果。在平时生活中我们会经常接触Word文档,在文档里面会经常设置字体的大小、类型、颜色、加粗、倾斜等一系列形式。这就是我们现在所讲述的问题,即如何开发CSS字体,现在来看一下开发代码。

▲图1-19 Sample1_17全局属性应用案例效果

代码位置:随书源代码/第1章目录下的HTML5/Sample1_17.html。

1    <!DOCTYPE html><html><head><title>Sample1_17</title>
2    <style type="text/css">
3    p.serif{font-family:"Times New Roman",Georgia,Serif}
4    p.sansserif{font-family:Arial,Verdana,Sans-serif}
5    p.normal {font-style:normal}
6    p.italic {font-style:italic}
7    p.oblique {font-style:oblique}
8    p.varnormal {font-variant: normal}
9    p.varsmall {font-variant: small-caps}
10   p.wenormal {font-weight: normal}
11   p.wethick {font-weight: bold}
12   p.wethicker {font-weight: 900}
13   h1.px {font-size:60px;}
14   h2.px {font-size:40px;}
15   p.px {font-size:14px;}
16   h1.em {font-size:3.75em;}h2.em {font-size:2.5em;}
17   p.em {font-size:0.875em;}</style></head>
18   <body>
19   <p>现在演示的是指定字体系列:</p>
20   <p class="serif">This is a paragraph, shown in the Times New Roman font.</p>
21   <p class="sansserif">This is a paragraph, shown in the Arial font.</p>
22   <!--建议在所有font-family 规则中都提供一个通用字体系列,这样就提供了一个候选
23   在用户代理无法提供与规则匹配的特定字体时,就可以选择一个候选字体。需要
24   注意的是,只有当字体名中有一个或多个空格(比如New York),或者字体名包括 
25   # 或 $ 之类的符号,才需要在font-family声明中加引号。-->
26   <p>现在来看一下font-style属性,该属性最常用于规定斜体文本。</p>
27   <p class="normal">本段示例规定为font-style属性中的normal值。</p>
28   <p class="italic">本段示例规定为font-style属性中的italic值。</p>
29   <p class="oblique">本段示例规定为font-style属性中的oblique值。</p>
30   <!--font-style的值为上面演示的3个,斜体(italic)是一种简单的字体风格,
31   它对每个字母结构有一些小改动以反映变化的外观。与此不同,倾斜(oblique)
32   文本则是正常竖直文本的一个倾斜版本。在浏览器中我们看到两者没有差别。-->
33   <p>这里演示的是font-variant属性,该属性可以设定大小写字母。</p>
34   <p class="varnormal">This is a paragraph</p>
35   <p class="varsmall">This is a paragraph</p>
36   <p>现在来看一下字体加粗属性font-weight:</p>
37   <p class="wenormal">This is a paragraph</p>
38   <p class="wethick">This is a paragraph</p>
39   <p class="wethicker">This is a paragraph</p>
40   <!--100 ~ 900为字体指定了9级加粗度,100对应最细的字体变形,900对应
41   最粗的字体变形。数字400等价于normal,而700等价于bold。-->
42   <p>现在来演示一下如何设置字体大小:</p>
43   <h1 class="px">这是标题1,用像素设置字体大小</h1>
44   <h2 class="px">这是标题2,用像素设置字体大小</h2>
45   <p class="px">这是一个段落,用像素设置字体大小</p>
46   <!--有管理文本大小的能力在Web设计领域很重要。但是,不应当通过调整文
47   本大小使段落看上去像标题,或者使标题看上去像段落。请始终使用正确的HTML 
48   标题,比如使用 <h1> - <h6> 来标记标题,使用 <p> 来标记段落。如果没有规
49   定字体大小,则普通文本(比如段落)的默认大小是16像素-->
50   <p>现在来看一下用em来设置字体大小:</p>
51   <h1 class="em">这是标题1,用em设置字体大小</h1>
52   <h2 class="em">这是标题2,用em设置字体大小</h2>
53   <p class="em">这是一个段落,用em设置字体大小</p>
54   <!--16px=1em px表示像素。除了IE之外其余浏览器均可支持用像素
55   调整字体大小,但是为了在IE上也能调整W3C也推荐使用em尺寸单位。-->
56   </body></html>

CSS字体样式表的本质就是通过font-family、size、stretch、style、variant、weight这些属性来设置字体的系列、尺寸、拉伸、字体风格、小型大写字体或者正常字体以显示文本、字体粗细。通过设置一系列的字体属性达到与文本样式表的匹配进而实现精美界面。

4.CSS链接与表格应用

本节为CSS部分的最后一节,将要讲述CSS链接与表格的属性应用。由于篇幅限制这里省略了列表属性的应用,尽管不是描述性文本中的任何内容都可以认为是列表,但是CSS中列表样式不太丰富而且应用比较简单,所以便没有介绍它。

图1-20所示为CSS链接和表格案例应用效果。介绍链接属性之前我们来介绍一下链接的4种状态:link、visited、hover、active,它们分别代表未访问的链接、用户已经访问、鼠标直接位于链接上方、链接被单击的时刻,现在来看一下开发过程。

▲图1-20 Sample1_18全局属性应用案例效果

代码位置:随书源代码/第1章目录下的HTML5/Sample1_18.html。

1    <!DOCTYPE html>
2    <html><head><title>Sample1_18</title>
3    <style type="text/css">
4    a:link {color:#FF0000;}<!--未被访问的链接-->
5    a:visited {color:#00FF00;}<!--已被访问的链接-->
6    a:hover {color:#FF00FF;}<!--鼠标移动到链接上-->
7    a:active {color:#0000FF;}<!--正在被单击的链接--> 
8    a.one:link {color:#ff0000;}
9    a.one:visited {color:#0000ff;}
10   a.one:hover {font-size:150%;}
11   a.two:link {color:#ff0000;}
12   a.two:visited {color:#0000ff;}
13   a.two:hover {font-family:'微软雅黑';}
14   #customers{
15     font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;
16     width:100%;border-collapse:collapse;}
17   #customers td, #customers th{
18     font-size:1em;border:1px solid #98bf21;
19     padding:3px 7px 2px 7px;}
20   #customers th {
21     font-size:1.1em;text-align:left;padding-top:5px;
22     padding-bottom:4px;background-color:#A7C942;color:#ffffff;}
23   #customers tr.alt td {
24     color:#000000;background-color:#EAF2D3;}
25   </style></head>
26   <body>
27   <p><b><a href="Sample1_1.html" target="_blank">
28   这是一个链接</a></b></p>
29   <!--为了使定义生效,a:hover必须位于a:link和a:visited之后,
30   a:active必须位于a:hover之后-->
31   <p>链接除了设置color之外还可以设置背景颜色,
32   就是在样式表中将color换为background-color。</p>
33   <p>除了基本改变链接的颜色外,还可以改变链接字体、尺寸等,
34   这些实现起来并不困难,用到的方法全是之前讲述过的:</p>
35   <p><b><a class="one" href="Sample1_1.html" target="_blank">
36   这个链接可以改变字体尺寸</a></b></p>
37   <p><b><a class="two" href="Sample1_1.html" target="_blank">
38   这个链接可以改变字体</a></b></p>
39   <p>现在介绍一下表格的样式表,首先制作一个精美的表格。</p>
40   <table id="customers"><tr>
41   <th>Company</th><th>Contact</th><th>Country</th></tr>
42   <tr><td>Apple</td><td>Steven Jobs</td><td>USA</td></tr>
43   <tr class="alt"><td>Baidu</td><td>Li YanHong</td><td>China</td></tr>
44   <tr><td>Google</td><td>Larry Page</td><td>USA</td></tr>
45   <tr class="alt"><td>Lenovo</td><td>Liu Chuanzhi</td><td>China</td></tr>
46   <tr><td>Microsoft</td><td>Bill Gates</td><td>USA</td></tr>
47   <tr class="alt"><td>Nokia</td><td>Stephen Elop</td><td>Finland</td></tr></table>
48   </body></html>

在案例中只开发了一个表格,没有应用全部的表格属性,剩余的部分在之前讲述表格标签时已介绍过,但是应用到CSS时会有点差别。若有读者想了解这方面的知识,那么可以上网查询CSS表格应用属性,里面会有比较详细的介绍。

到此为止已将CSS介绍完毕,短短十几页的内容肯定不能将CSS的全部内容介绍完毕,但是已尽力将最常用与精髓部分进行介绍了。读者在应用时应该自己多查阅一些资料,勤加练习,多改一些内容,这样会学得更加充实。

JavaScript是面向Web的编程语言。绝大多数现代网站都是用了JavaScript,并且所有的现代Web浏览器——基于桌面系统、游戏机、平板电脑和智能手机的浏览器——均包含了JavaScript解释器。这使得JavaScript可称为史上使用广泛的编程语言。

“JavaScript”这个名字经常被误解。除了语法看起来和Java类似之外,JavaScript与Java是完全不同的两种编程语言。JavaScript早已超出了“脚本语言”本身的范畴,而成为一种集健壮性、高效性和通用性为一身的编程语言。

JavaScript是由Web发展初期的网景(Netscape)公司创建的,“JavaScript”是Sun Microsystem公司(Oracle)的注册商标,用来特指网景(Mozilla)对这门语言的实现。网景将这门语言作为标准提交给了ECMA(欧洲计算机制造协会),由于商标上的冲突,所以这门语言的标准版本改为“ECMAScript”。

当提到这门语言时,通常所指的语言版本是ECMAScript 3和ECMAScript 5,有时会看到JavaScript的版本号,这些是Mozilla的版本号:版本1.5基本上就是ECMAScript 3,JavaScript解释器也有版本号,现在为3.0。

本节中关注的是Web编程需要核心JavaScript特性。这里不会将全部的JavaScript 内容讲述清楚,因为若是想完成这些工作本书的厚度是不够的。如果读者想要深入学习这方面的知识,则可以在网上选购几本这方面的书来提升自己的能力。

在HTML文档中定义脚本时有几种方法可供选择,既可以定义内嵌脚本(即脚本是HTML文档的一部分,用<script>标签可实现),也可以定义外部脚本(脚本包含在另一个文件中,通过一个URL引用)。这两种方法都用到了script元素。

1    <!DOCTYPE HTML>
2    <html><head><title>Example</title></head>
3    <body><script type="text/javascript">
4    document.writeln("Hello");</script>                //输出语句
5    </body></html>

本段脚本的作用是在文档中加入单词Hello。script元素位于文档中其他内容之后,这样在脚本执行之前浏览器就已经对其他元素进行了解析,读者可以自行将本段代码输入到html文件中,并在网页中运行以查看效果。

上述代码为一个简单的JavaScript案例应用,并且定义HTML文档为内嵌脚本。在WebGL的开发中,除了在一些html文件中定义了stat方法外,剩下的脚本使用的都是通过URL来调用外部脚本。但是在本节介绍JavaScript基础时,我们会用内嵌脚本方式示例。

JavaScript的基本元素是语句,一条语句代表一条命令,通常以分号结尾。实际上分号也可以不用,不过加上分号可让代码更易阅读,并且可以在一行书写几条语句。下面我们来看一下使用输出语句与定义一些函数的案例。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_19.html。

1    <!DOCTYPE html>
2    <html><head><title>Sample1_19</title>
3    </head><body>
4    <style type="text/javascript">
5        document.writeln("输出一句话。");                  //输出语句
6        document.writeln("输出另一句话。");
7        function myFun(){                                //定义一个函数,用于输出一句话
8            document.writeln("调用方法输出一句话。);};
9        myFun();                                         //调用定义的函数
10       function mayFun1(name,weather){                  //定义一个带参数的函数
11           document.writeln("Hello"+name+".");
12           document.writeln("It is"+weather+"today.");};
13       myFun1("Tom","Sunny");                           //调用带参数的函数
14       function myFun2(name){                           //定义一个带返回结果的函数
15           return("Hello"+name+".");}
16       document.writeln(myFun2("Tom"));
17   </script></body></html>


说明 

上面代码内嵌在脚本中演示了语句如何使用。JavaScript的基本元素是语句。有时候可以将几条语句包含在一个函数中,浏览器只有遇到调用该函数的语句时才会执行它。函数所含语句被包围在一对大括号之间,成为代码块。


前面讲述的 HTML 事件,一般情况下大家在日后的开发中会结合某些事件来调用JavaScript函数。另外需要注意的是,在调用有参函数时,参数个数可以比定义的少,此时缺少的参数值便会默认为undefined。如果多出参数,那么多出的会被忽略。

熟悉Java开发的读者知道,在Java开发中大家可以开发函数名相同但是参数个数不同的函数,这在JavaScript中是万万不可的。如果有两个相同名字的函数但参数个数不同,那么第二个定义将会取代第一个。

使用关键字var定义变量,在定义同时还可以像在一条单独语句中那样为其赋值。定义在函数中的变量为局部变量,只能在该函数范围内使用。直接在script元素中定义的变量称为全局变量,可以在任何地方使用(包括在其他脚本中)。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_20.html。

1     <!DOCTYPE html>
2     <html><head><title>Sample1_20</title>
3     </head><body>
4     <script type="text/javascript">
5         var myglobalvar="apple";               //定义全局变量
6         function myFun(){                      //声明一个方法
7             var mylocalvar="sunny";            //定义局部变量    
8     return("Hello"+name+".Today is"+mylocalvar+".");};
9         document.writeln(myFun("Tom"));
10        document.writeln("I like"+myglobalvar+".");
11        var string1="This is a string.";      //使用JavaScript的基本类型——字符串变量
12        var string2="This is a string.";
13        var bool1=true;                       //使用JavaScript的基本类型——布尔变量
14        var bool2=false;
15        var daysinweek=7;                   //使用JavaScript的基本类型——数值变量
16        var pi=3.14;                        //JavaScript中的整数、浮点数都用var来声明
17        var hexValue=0xFFFF;                //十六进制数
18        var mydata=new Object();            //创建对象
19        mydata.name="Tom";                  //为对象属性赋值
20        mydata.weather="sunny";
21        document.writeln("Hello"+mydata.name+".");
22        document.writeln("Today is "+ mydata.weather+".");
23        var mydata1={                       //使用对象字面变量
24            name:"Tom",                     //为对象属性赋值
25            weather:"Sunny"};
26        document.writeln("Hello"+mydata1.name+".");        //使用对象属性
27        document.writeln("Today is"+mydata1.weather+".");
28        var mydata2={                       //为对象添加方法
29            name:"Tom",                     //为对象属性赋值
30            weather:"Sunny",
31            printMessages: function(){      //给对象属性声明一个方法
32                document.writeln("Hello"+mydata2.name+".");
33                document.writeln("Today is "+ mydata2.weather+".");}};
34        mydata2.printMessages();            //读取和修改对象属性值
35        var mydata3={
36            name:"Tom";                     //为对象属性赋值
37            weather:"Sunny";};
38        mydata3.name="Jerry";               //修改对象属性值
39        mydata3["weather"]="raining";
40        document.writeln("Hello"+mydata3.name+".");        //读取对象属性值
41        document.writeln("Today is "+ mydata3.weather+".");
42    </script></body></html>

使用对象的时候还可以枚举对象属性,可以用for…in语句枚举对象属性。for…in循环代码块中的语句会对对象的每一个属性执行一次。在每一次迭代过程中,所需要处理的属性名会被赋值给变量。大家看看下面这个简短的例子。

1    <!DOCTYPE HTML>
2    <html><head><title>Example</title></head>
3    <body><script type="text/javascript">
4        var mydata={                                   //声明一个对象
5            name:"Tom",                                //为对象的属性赋值
6            weather:"Sunny",
7            printMessages:function(){                  //为对象添加方法
8            document.writeln("Hello"+mydata.name+"."); //读取对象的属性值
9            document.writeln("Today is "+ mydata.weather+".");}};
10       for(var prop in mydata){                       //枚举对象的属性值
11           document.writeln("Name" + prop + "Value:" + mydata[prop]);}
12   </script></body></html>

图1-21所示为这段代码的运行效果,从中可以看到,作为方法定义的函数也被枚举出来了。JavaScript在处理函数方面非常灵活,方法本身也被视为对象的属性,这就是其结果。除了枚举对象属性,还有增删属性等。

▲图1-21 案例运行效果

在日后的开发中会经常用到对象,不论是内嵌在JavaScript脚本中创建的对象,还是外部定义的要通过URL引用JavaScript的脚本,大家可以通过创建对象引用来实现相应功能,这些在后面的开发中要多留心观察。

有编程经验的读者都明白,不论是什么语言都会经常用到运算符,JavaScript当然也不会例外。幸运的是,JavaScript的运算符与一般编程语言中的运算符没有多大的差别,所以这里简单介绍一下,表1-13所示为JavaScript运算符及其描述。

表1-13  JavaScript运算符

运 算 符

描  述

运 算 符

描  述

+

加法运算符

减法运算符

*

乘法运算符

/

除法运算符

%

求模,保留整数

++

累加运算

−−

递减

=

赋值运算

+=

x+=y等价于x=x+y

−=

x−=y等价于x=xy

*=

x=y等价于x=xy

/=

x/=y等价于x=x/y

%=

x%=y等价于x=x%y

通过浏览表1-13大家不难发现这些运算符在入门学习任何一门编程语言时都会有详尽的介绍,所以这里便不再赘述了。表中描述的xy假设均为已经声明好的变量旨在帮助读者理解运算符。

JavaScript数组的工作方式与大多数编程语言中的数组类似,一般在枚举数组时都会使用{},但在JavaScript中声明数组使用[]而不是用花括号。下面来看一下如何用JavaScript创建数组,以及使用数组对象。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_21.html。

1    <!DOCTYPE HTML>
2    <html><head><title>Sample1_21</title></head>
3    <body><script type="text/javascript">
4        var myarray=new Array();                       //创建与填充数组
5        myarray[0]=100;                                //为数组赋值
6        myarray[1]="Tom";
7        myarray[2]=true;
8        var myarray1=[100,"Tom",true];                 //使用数组字面量创建数组
9        var myarray2=[100,"Tom",true];                 //读取指定索引位置的数组元素值
10       document.writeln("Index 0" + myarray2[0]);
11       var myarray3=[100,"Tom",true];                 //修改数组内容
12       myarray3[0]="Tuesday";
13       document.writeln("Index 0" + myarray3[0]);
14       var myarray4=[100,"Tom",true];                 //枚举数组内容
15       for(var i=0;i<myarray4.length;i++){            //myarray4.length为数组的长度
16           document.writeln("Index 0" + myarray4[0]);}
17   </script></body></html>

此例需要注意两点,第一点是在创建数组的时候不需要声明数组中的元素个数,JavaScript数组会自动调整大小以便容纳所有元素。第二点是不必声明数组所含数据的类型,JavaScript数组可以包含各种类型的数据。

有编程经验的读者知道除了上面所讲的数组基础用法外还应知道一些数组方法,下面我们便来看一下表1-14所列出的常用数组方法。由于篇幅有限所以这些方法的应用不再过多介绍了,读者可以对照着说明自行试验。

表1-14  常用数组方法

方  法

说  明

返  回

concat(<otherArray>)

将数组和参数所指的数组内容合并为一个新数组。可指定多个数组

数组

join(<separator>)

将所有数组元素连接为一个字符串,各元素内容用参数指定的字符进行分隔

字符串

pop()

把数组当作栈来使用,删除并返回数组的最后一个元素

对象

push(<item>)

把数组当作栈来使用,将指定的数据添加到数组中

void

reverse()

就地反转数组元素的次序

数组

shift()

类似pop,但操作的是数组中的第一个元素

对象

slice(<start>,<end>)

返回一个子数组

数组

sort()

就地对数组元素进行排序

数组

unshift(<item>)

类似push,但新元素被插到数组的开头位置

void

讲完数组后,JavaScript的基础内容基本结束了,JavaScript与Java类似也有处理错误。这里的处理错误也是用try…catch语句来实现,如果有错误发生,那么try子句中语句的执行将立即被停止,控制权转移到catch子句中。发生的错误由一个Error对象描述,它会传递给catch子句。

在JavaScript中,不但可以使用系统提供的对象,还可以创建自己的对象,相当于把Java中类的声明和对象的创建合二为一了。由于创建对象时对象不止只有一个属性,所以属性与属性之间用逗号分隔,其余的声明规则与Java类似。其简略语法如下

<引用名>={<属性名>:<属性值>,{<属性名>:<属性值>……}}

在JavaScript中,对象实际上可以看作数组,因此对象的成员不仅可以用“<引用>.<属性>”的方式来访问,还可以用“<引用>[<属性>]”像数组一样来使用。如果希望对象可以重用,也可以像Java那样先声明类再new对象,其语法如下:

function<类名>([构造函数参数列表]) {
this.<属性名1>=<构造函数参数>;
……
this.<属性名n>=<构造函数参数>;
}

实际上类的声明就是一个函数的声明,只是在函数中多了“this.<属性名>”,这既是属性的声明同时又进行了初始化。大家都知道一个类不但可以有属性,还可以有方法,给类添加方法的语法如下:

function<类名>([构造函数参数列表]){
this.<方法名1>=<函数名1>;//函数可以是在任意地方声明的函数
……
this.<方法名n>=<函数名n>;
}

实际上方法的声明就是把已经写好的函数分配给一个属性。前面说过由于对象可以看作一个数组,所以可以对对象的属性进行遍历。在JavaScript中,可以方便地利用下面形式的for语句对指定对象的所有属性进行遍历:

for(var<变量>in<对象引用>){
//语句序列
}

对象操作的基本方法就这么多,用操作符“new”创建对象,释放(删除)对象时使用“delete”操作符。由于JavaScript是弱类型语言,所以在下一节中会看到无论声明什么类型的变量都会为var字符。有时判断变量的类型,这就要使用“typeof”操作符,如表1-15所示。

表1-15 typeof操作符的应用

(typeof ”aa”)==”string”

(typeof 20)==”number”

(typeof ma)==”object”

(typeof nothing)==”undefined”

(typeof true)==”boolean”

“typeof”操作返回的是一个字符串。从表1-15可以看到typeof返回了一个undefined。在JavaScript中不但true/false布尔类变量可以参与逻辑计算,undefined和null都可以当作逻辑false来使用。JavaScript支持原型,使用原型可以向已有对象类型注射新的方法、属性。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_22.html。

1     <!DOCTYPE html>
2     <html><head><title>Sample1_22</title>
3     </head><body>
4     <script type="text/javascript">
5          tom={name:"Tom",age:21};                       //创建自己的对象
6          document.write("Name:"+tom.name+"<br>");       //读取对象的属性值
7          document.write("Age:"+tom.age+"<br>");
8          //对象可以看作数组,用数组形式访问对象,下面的例子便演示了如何用数组形式访问对象
9          tom={name:"Tom",age:21};
10         document.write("Name:"+tom["name"]+"<br>");    //用数组形式访问对象
11         document.write("Age:"+tom["age"]+"<br>");
12             //对象的重用,可以像Java那样先声明类再new对象
13             function Student(sno,sname,sage,sclass){   //声明student类
14             this.sno=sno;                              //为student类添加属性
15             this.sname=sname;                          //为属性添加属性值
16             this.sage=sage;
17             this.sclass=sclass;}
18             tom=new Student("10001","Tom",21,"97002");    //创建Student对象
19             document.write(tom.sname+"<br>");
20             //给类添加方法,即为类中的属性添加方法
21             function Student1(sno,sname,sage,sclass){     //声明student1
22              this.sno=sno;               //将student类声明中传入的参数赋值给属性
23              this.sname=sname;           //为sname属性赋值
24              this.sage=sage;             //为sage属性赋值
25              this.sclass=sclass;         //为sclass属性赋值
26              this.toString=toString;}    //把toString方法挂接到Student
27         function toString(){             //声明toString方法
28             var result="";               //声明一个空白字符串
29             result+="学号: "+this.sno+"<br>";           //为字符串添加学号内容
30             result+="姓名: "+this.sname+"<br>";         //为字符串添加姓名内容
31             result+="年龄: "+this.sage+"<br>";          //为字符串添加年龄内容
32             result+="班级: "+this.sclass+"<br>";         //为字符串添加班级内容中
33             return result;}                             //将最终所得字符串返回
34             tom=new Student1("10001","Tom",21,"97002"); //创建Student1对象
35             document.write(tom.toString());
36         tom={name:"Tom",age:21,no:10001};               //对对象的属性进行遍历
37             for(var i in tom){                          //对象属性用循环进行遍历
38                   document.write(i+":"+tom[i]+"<br>");}
39         function toWyfString(){      //用原型给已有对象注射新方法、新属性
40                  var ss=this.wyfTime+this.toGMTString();  //得到系统时间
41                  return ss;}                              //将字符串返回
42             function toGMTString(){
43                  return "HaHa!!!";
44             }                        //使用原型可以向已有的对象类型注射新方法、属性
45                                      //对对象的功能进行扩展,同时也能覆盖原有的方法
46         Date.prototype.wyfTime="WYF: ";                   //拓展对象属性
47         Date.prototype.toWyfString = toWyfString;         //覆盖原有的方法
48         d=new Date();
49         document.write(d.toWyfString()+"<br>");
50         document.write(d.toGMTString()+"<br>");
51         Date.prototype.toGMTString = toGMTString;         //覆盖原有的方法
52         document.write(d.toGMTString()+"<br>");
53    </script></body></html>

上面代码为本节中所讲述内容的应用。前面已经讲述了创建对象与数组,本节讲述的是如何开发自己的类,以及声明自己的对象和对象的一些用法。这些内容与Java有些类似,有Java开发经验的读者肯定不会陌生。

有很多工具可简化JavaScript的编程工作,我们在调试程序时必不可少的一个环节便是调错。由于开发JavaScript不像开发其他语言有强大的编译环境,所以调错时不是很方便。幸运的是,现在的浏览器都会有内置的调试器,图1-22所示为Firefox浏览器的firebug插件。

用其他浏览器中的调试器也是可以的,作者在开发时习惯使用Google浏览器的内置调试器,遇到的一般情况都可以解决。但是有时有一些特别错误解决不了,这时firebug的强大能力便体现出来了,它可以设置断点、探查错误和逐句执行脚本。

使用JavaScript最简便的方式是使用某种JavaScript工具包或库。这种工具包多如牛毛,其中非常流行的且开发非常活跃并具有许多有用特性的是jQuery,它与配套程序库jQueryUI非常流行。有了它,JavaScript开发工作要变得轻松许多。

到此为止便将JavaScript部分的基础内容介绍完毕了。还是用之前说过的一句话,本部分内容不可能是这么几页就能够解决的,WebGL的开发没有这些基础又不行,所以其目的就是简要介绍一下。

▲图1-22 firebug插件调试

HTML5 Canvas是屏幕上由JavaScript控制的即时模式位图区域。即时模式是指在画布上呈现像素的方式,HTML Canvas通过JavaScript调用Canvas API,在每一帧中完全重绘屏幕上的位图。开人员需要做的就是在每一帧渲染之前设置屏幕的内容显示。

文档对象模型(DOM)代表了HTML页面上的所有对象,它是语言中立且平台中立的。它允许页面的内容和样式被Web浏览器渲染之后再次更新。用户可以通过JavaScript访问DOM。现在DOM已经成为JavaScript、DHTML和CSS开发中最重要的一部分。

画布元素本身可以通过DOM在Web浏览器中经由Canvas 2D环境访问。但是,在Canvas中创建的单个图形元素是不能通过DOM来访问的。正如本章前面讲到的,画布工作在即时模式,它并不保存自己的对象,只是说明在单个帧里绘制什么。

用JavaScript来创建Canvas应用程序,程序能在现有的任何Web浏览器中运行。在使用JavaScript为Canvas编程时会有一个问题,在创建的页面中哪里为JavaScript程序的起点?有两种方式,一种为放在<head>标签中,另一种为放在<body>标签中。

现在来开发Canvas之路上的第一个案例,即Canvas版的“Hello World”。本节将从开发程序的第一步开始,一步步地将程序开发的过程呈现给大家,让没有开发经验的读者对开发程序有一个整体的概念。

在上一节中讲到了JavaScript与Canvas的关系。由于在开发本部分内容时html文件中难免会嵌入JavaScript脚本,所以我们第一步来看一下如何将JavaScript程序中的方法封装起来,并留下JavaScript程序的入口。

1.封装JavaScript代码

Canvas应用程序与浏览器中运行的其他应用有所不同。由于Canvas只在屏幕上的特定区域内执行并显示结果,可以说它的功能是独占的,因此不太会受到页面上其他内容的影响,反之亦然。读者如果想在同一个页面上放置多个Canvas应用,那么在定义时必须将对应代码分开。

为了避免出现这个问题,可以将变量和函数都封装在另一个函数中。JavaScript函数本身就是对象,JavaScript对象既可以有属性也可以有方法。将一个函数放到另一个函数中,读者可以使第二个函数只在第一个函数的局部作用域中。

1    function eventWindowLoaded(){canvasApp();}  //JavaScript程序在Canvas中的入口函数
2    function canvasApp(){                       //入口函数需要调用的函数
3        drawScreen();                           //绘制场景函数
4        ……
5        function drawScreen(){……                //绘制函数,本程序中的重点
6    }}

上述代码讲解了如何将JavaScript代码封装起来,封装好的方法只留下eventWindowLoaded()方法。在下一节中还将绘制不同图形的方法并放到外部文件中,在<head>标签部分加载这些文件,待到需要绘制时直接调用相应的方法即可。

2.将Canvas添加到HTML页面中

在HTML的<body>标签中添加一个<Canvas>标签时,可以参考下述代码。<canvas>标签有3个主要属性。大家都知道在HTML中,属性被设置在相应的标签中,id、width、height这3个属性分别代表JavaScript代码中用来指示特定<canvas>标签的名字、画布的宽度与高度。

1    <canvas id="canvasOne" width="500" height="300">
2    若看到这个文字,则说明浏览器不支持WebGL!</canvas>

在开始标签和结束标签中可以添加文本,一旦浏览器在执行HTML页面时不支持Canvas,就会显示这些文字。以本章的Canvas应用程序为例,这里使用的是“若看到这个文字,则说明浏览器不支持WebGL”。事实上此处可以随意放置文字。

接下来用DOM引用HTML中定义的<canvas>标签。document对象加载后可以引用HTML页面的任何元素。需要一个Canvas对象的引用,这样就能够知道当JavaScript调用Canvas API时其结果在哪里显示了。

var  theCanvas=document.getElementById("canvasOne");

首先定义一个名为theCanvas的新变量,以保存Canvas对象的引用。接下来,通过调用document的getElementById()函数得到canvasOne的引用。canvasOne是在HTML页面中为创建的<canvas>标签定义的名字。

3.检测浏览器是否支持Canvas

现在已经得到了在HTML页面上定义的Canvas元素的引用,下面检测它是否包含环境。Canvas环境是指支持由Canvas的浏览器定义的绘图界面。简单地说,如果环境不存在,那么画布也不会存在。有多种方式可以对此进行验证。

这里使用的是modernizr.js库中的Modernizr,它是一个易用并且轻量级的库,可以检测各种Web技术的支持情况。Modernizr创建一组静态的布尔值,可以检测是否支持Canvas。在程序中已经包含modernizr.js,读者不用再自行下载了。

1    <script src="modernizr.js"></script>
2    function canvasSupport(){
3        return Modernizr.canvas;}

上面代码第1行为将外部.js文件导入到HTML文件中,下面的代码是为了检测是否支持Canvas,而将canvasSupport()函数进行修改。这里将要使用modernizr.js方法,因此它提供了测试Web浏览器是否支持Canvas的最佳途径。

4.获得2D环境

var context =theCanvas.getContext("2d");

最后需要得到2D环境的引用才能操作它。HTML5 Canvas被设计为可以与多个环境工作,包含一个建议的3D环境。不过这里只用到了2D环境。通过getContex()方法取得context,然后在之后的绘制函数中大家便可以用context来设置各个属性了。

5.绘制函数

现在可以创建实际的Canvas API代码了。在Canvas上运行的各种操作都要通过context对象,因为它引用了HTML页面上的对象。大家在案例中所看见的“屏幕”就是定义画布的绘图区域。首先应清空绘图区域。

1    context.fillStyle="#ffffaa";
2    context.fillRect(0,0,500,300);

上面的两行代码在屏幕上绘制出一个与画布大小相同的黄色方块。fillStyle()设置颜色,fillRect()创建一个矩形,并把它放到了屏幕上。在清空完绘图区域后,看一下绘制函数drawScreen()是如何开发的。

1    function drawScreen(){
2               context.fillStyle="#ffffaa";                //背景
3               context.fillRect(0,0,500,300);              //创建一个矩形
4               context.fillStyle="#000000";                //文字
5               context.font="20px Sans-Serif";             //设置字体的大小和字号
6               context.textBaseline="top";                 //设置字体的垂直对齐方式
7               context.fillText("Hello World!",195,80);    //将测试文本显示到屏幕上
8               var helloWorldImage=new Image();            //添加2D图像
9               helloWorldImage.onload=function(){
10                   context.drawImage(helloWorldImage,155,110);}
11              helloWorldImage.src="pic/helloworld.png";
12              context.strokeStyle="#000000";             //设置边框
13              context.strokeRect(5,5,490,290);
14              }

由于上面几节已将本例中的重点代码介绍了,所以就不再将全部代码在这里重写一遍了,读者可以查阅随书资源中的Sample1_23案例进行学习。下面来看一下第一个Canvas程序的运行效果,如图1-23所示。

▲图1-23 案例Sample1_23效果

读者在第一次开发时肯定会遇到一些问题,还会有调试程序的步骤。但是这里不会将可能的错误全部罗列出,读者在开发中遇到问题时可以用前面提到的浏览器自带调试器或者firebug进行调试。

学完Canvas版“Hello World”的开发过程后,大家来进一步深入学习一下Canvas提供的一些绘制基本图形的API。看完这些内容后读者就可以开发一些2D的内容了,这里提供的为系统的API,读者只要认真学习都可以掌握。

在看完第一个Canvas程序后大家对它已有了基本认识,HTML5 Canvas的使用是以强大的绘图、着色和基本二维形状变换为基础的。然而,可供选择的内建形状相对有限,程序员可以通过一组称作路径的线段来绘制出想要的形状。

现在学习一下新的内容,在Canvas上绘制一些基本图形。绘制这些图形基本上都会有相应的API,本案例中不同的图形会在不同的JavaScript文件中,相应的API在里边都会有所体现。读者阅读时结合着注释便能够轻松学会,现在看一下这部分的开发过程。

代码位置:随书源代码/第1章目录下的HTML5/Sample1_24.html。

1     <!DOCTYPE HTML>
2     <html><head><title>Sample1_24</title>
3     <script src="js/modernizr.js"></script>     //导入js文件夹下的modernizr.js文件
4     <script src="js/arc.js"></script>           //导入js文件夹下的arc.js文件
5     <script src="js/bezier.js"></script>        //导入js文件夹下的bezier.js文件
6     <script src="js/line.js"></script>          //导入js文件夹下的line.js文件
7     <script src="js/linejoin.js"></script>      //导入js文件夹下的linejoin.js文件
8     <script src="js/rect.js"></script>          //导入js文件夹下的rect.js文件
9     <script type="text/javascript">    //前面导入的为外部JavaScript文件,  
      这里为内嵌的JavaScript文件
10    var context;
11    function eventWindowLoaded(){canvasApp();} //封装加载JavaScript的方法
12    function canvasSupport(){                  //检测浏览器版本是否支持Canvas
13        return Modernizr.canvas;}
14    function canvasApp(){                      //实际JavaScript的入口方法
15        if(!canvasSupport()){return;}else{
16              var theCanvas = document.getElementById("canvas");
17              context=theCanvas.getContext("2d");}
18              drawScreen();    //绘制场景,不同的图形有不同的绘制方法,这里省略了其余的方法
19              function drawScreen(){             //绘制2D图形的方法
20              //画布背景色为白色,这不利于辨识,填充一个有颜色的区域便于标识
21              context.fillStyle="#aaaaaa";       //设置背景样式
22              context.fillRect(0,0,500,500);     //创建一个矩形    
23              context.fillStyle='#000000';          //文字
24              context.font='20px _sans';            //文字的大小和字号
25              context.textBaseline='top';           //设置文本垂直对齐方式
26              context.fillText("Canvas!",0,0);}}    //将测试文本显示到屏幕上
27    </script></head>
28    <body onload="eventWindowLoaded();">
29    <div style="position: absolute; top: 50px;left:50px;">
30    <canvas id="canvas" width="500" height="500">
31    若看到这个文字,则说明浏览器不支持WebGL!</canvas></div>
32    </body></html>

在程序中调用drawScreen()方法时需要注意的是,在程序开头导入的几个JavaScript文件,这些文件包含绘制圆、直线、曲线的一些图形API,读者可以自行查阅这些代码进行学习,其中的解释和注意事项在注释中都有详细介绍,这里便不再赘述。

HTML5 Canvas这里便介绍完毕,读者千万别以为就已经掌握了Canvas,Canvas是HTML5新增的元素,可以干的事情还有很多。本章只介绍了2D环境下的绘制图形,以后的章节才是Canvas的真正应用。

到此为止便结束了HTML之旅,但是HTML的内容远不止于此。本章介绍了HTML5标签、CSS、JavaScript、Canvas这些内容,这些中的每项自成一本书都没有问题,这里只是讲述了之后开发中需要的部分。

读者在日后的开发中除了本章介绍的基础理论知识外,肯定还会需要更多知识来填补不足。只阅读这些是远远不够的,这里也仅是WebGL的起步而已,接下来便进入WebGL的世界。


第1章介绍的都是HTML5的开发技术,相信读者已经对HTML5有了一定的认识。本章将向读者简要介绍最近在移动端大放异彩的WebGL 2.0,掌握了这部分内容后,读者可以在更广阔的领域开发自己的3D项目。

随着OpenGL ES版本的发展,WebGL的版本也由原先的WebGL 1.0升级为WebGL 2.0。WebGL 2.0是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 3.0结合在一起。通过增加OpenGL ES 3.0的一个JavaScript绑定,WebGL 2.0可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。

WebGL 2.0标准已出现在Mozilla Firefox、Apple Safari及开发者预览版Google Chrome等浏览器中,这项技术支持Web开发人员借助系统显示芯片在浏览器中展示各种3D模型和场景。随着HTML5的兴起,WebGL 2.0的前景不可估量。

WebGL 2.0和3D图形规范OpenGL、通用计算规范OpenCL都来自Khronos Group,同样免费开放。WebGL 2.0标准工作组的成员包括AMD、爱立信、Google、Mozilla、英伟达以及Opera等,这些成员与Khronos公司通力合作,创建了一种多平台环境可用的WebGL 2.0标准。

WebGL 2.0完美地解决了现有的Web交互式三维动画的3个问题。


说明 

同样可以用于网页3D渲染的技术还有Adobe Flash Player 11、微软Silverlight 3.0等,但它们都是私有、不透明的。因此,作者认为采用开放、免费策略的WebGL 2.0在当下这个时代将更有发展前途。


WebGL目前有两个版本的标准,具体情况如下。


说明 

从上述内容可以看出,随着WebGL 2.0的完善,它开始逐渐取代WebGL 1.0,因此本章也是基于OpenGL ES 3.0来介绍WebGL 2.0的。好在OpenGL ES 3.0与OpenGL ES 2.0是兼容的,大部分知识可以直接使用,只是着色语言的一些语法细节有变化,读者不用担心。


随着HTML5的兴起,大量优秀的网页涌现出来。作为HTML5官方的Web 3D解决方案,WebGL 2.0立刻受到无数开发人员的追捧。由于其以网页形式进行展示,所以可以不受平台的限制,这也省去了在各种平台上移植的步骤。

随着微信平台兼容性的快速发展,进一步降低WebGL 2.0的推广成本。微信平台中,只需要单击项目所在链接即可运行,操作步骤十分简便。也省去了传统游戏安装客户端的麻烦,同时保证了项目代码不被泄露。相信在不久的将来,WebGL 2.0将会凸显出更大的优势和能力。

2.1.1节介绍了WebGL 2.0的基本知识,相信读者已经对其有了一定的了解。随着HTML5标准的不断完善,为HTML 5 Canvas提供硬件3D加速渲染的WebGL 2.0已经被越来越多的开发人员所接受。市面上采用WebGL 2.0的网络游戏如雨后春笋般涌现出来。下面的几幅图(见图2-1、图2-2)就是作者看到的使用WebGL 2.0技术制作的精美网页截图。

▲图2-1 纹理贴图立方体

▲图2-2 行星动画

从图2-1、图2-2中可以看出,使用WebGL 2.0技术渲染出的3D场景与直接使用OpenGL ES技术在移动设备上开发出的场景效果基本是一致的。读者通过对前面章节的学习,再结合本章内容便可在Web端开发出与移动端一样绚丽流畅的3D场景。

2.1节简单介绍了3D绘图标准WebGL 2.0,相信读者已经对WebGL 2.0的发展历程和作用有了一定的了解。上面的介绍偏重基础,读者无法深入学习具体编程技巧。为了使读者能够保持学习热情,在实践中提升编程能力,本章将给出一个WebGL 2.0的基础案例并对相关的运行步骤进行详细介绍。

由于WebGL 2.0应用程序是以浏览器为平台进行工作的,因此一般情况下开发完毕后都需要将应用部署到Web服务器上以供浏览器访问。在具体开发各个案例之前,本节先简要介绍一下如何在Tomcat上部署WebGL 2.0应用,具体步骤如下。

(1)登录Tomcat的官方网站下载Tomcat的压缩包(如“apache-tomcat-6.0.14.zip”),然后解压缩到本地磁盘。解压完成后对环境变量中的JAVA_HOME进行配置。

(2)找到解压后apache-tomcat-6.0.14目录下bin子目录中的startup.bat文件,双击此文件启动Tomcat服务器,如图2-3所示。

▲图2-3 打开Tomcat服务器


提示 

Tomcat的配置过程难度较小。本书篇幅有限,对于Tomcat的配置过程不再赘述。不熟悉的读者可以参考其他的书籍或资料。


(3)将开发完毕的WebGL 2.0案例(如Sample2_1)复制到解压后的apache-tomcat-6.0.14目录下的webapps子目录中,如图2-4所示。

▲图2-4 WebGL 2.0案例位置

(4)查找并记录本机的IP地址,然后打开Firefox等可以支持WebGL 2.0的浏览器,在地址栏中输入指定网址,按下回车键即可。例如运行案例Sample2_1时输入的网址为:

http://10.16.189.15:8080/Sample2_1/Sample2_1.html


说明 

读者只需找到“:8080”前的IP地址并替换为自己机器的IP地址即可在自己的计算机上成功运行本案例。



提示 

作者运行本章案例时使用的都是Tomcat服务器,读者也可以选择其他的Web服务器。作者运行本章案例时使用的是Firefox浏览器,读者也可以使用其他支持WebGL 2.0的浏览器(如UC浏览器、淘宝浏览器等)。


2.2.1节中简单地介绍了WebGL 2.0应用案例的运行步骤,读者可以参考给出的案例进行高效学习。接下来将通过一个旋转正方体的案例向读者介绍如何开发3D场景。具体运行效果如图2-5、图2-6所示。

▲图2-5 初始状态效果图

▲图2-6 绕y轴旋转大约120°的效果图

前面给出了本案例的运行效果图,有兴趣的读者可在自己的设备上运行本案例。下面将通过本案例的详细代码讲解具体开发步骤。

在开发与本案例直接相关的类之前,首先需要介绍在网络端读取着色器(shader)脚本的工具类。此类读取着色器的方法主要分为几步:发送一个打开指定URL的请求,接收文本并进行切分,新建着色器对象并加载。具体代码如下。

代码位置:随书源代码/第2章/Sample2_1/js目录下的LoadShaderUtil.js文件。

1     function shaderObject(typeIn,textIn){     //声明shaderObject类
2       this.type=typeIn;                       //初始化type成员变量
3       this.text=textIn;                       //初始化text成员变量
4     }
5     var shaderStrArray=["a","a"];             //存储着色器数组
6     var shaderNumberCount=0;                  //数组索引值
7     var shaderTypeName=["vertex","fragment"]; //着色器名称数组
8     function processLoadShader(req,index){    //处理着色器脚本内容的回调函数
9       if (req.readyState == 4){               //数据接收
10        var shaderStr = req.responseText;     //获取响应文本
11        //根据不同的数组索引值创建不同的着色器,并存入着色器数组
12        shaderStrArray[shaderNumberCount]=new 
13        shaderObject(shaderTypeName[shaderNumberCount],shaderStr);
14        shaderNumberCount++;                  //数组索引值加1
15        if(shaderNumberCount>1){              //如果两个着色器内容均不为空,则
16          //加载着色器
17          shaderProgArray[index]=loadShaderSerial(gl,shaderStrArray[0], shaderStrArray[1]);
18        }
19    }}
20    function loadShaderFile(url,index){       //从服务器加载着色器脚本的函数
21      var req = new XMLHttpRequest();         //创建XMLHttpRequest对象
22      req.onreadystatechange = function ()    //设置响应回调函数
23      { processLoadShader(req,index) };       //调用processLoadShader处理响应
24      req.open("GET", url, true);             //用GET方式打开指定URL
25      req.responseType = "text";              //设置响应类型
26      req.send(null);                         //发送HTTP请求
27    }

上文已经将网络端读取着色器的工具类介绍完毕,接下来介绍的是用于初始化WebGL 2.0 Canvas的JavaScript脚本文件——GLUtil.js,首先给出的是其中的initWebGLCanvas方法,具体代码如下。

代码位置:随书源代码/第2章/Sample2_1/js目录下的GLUtil.js文件。

1    function initWebGLCanvas(canvasName) {             //初始化WebGL Canvas的方法
2      canvas = document.getElementById(canvasName);    //获取Canvas对象
3      var context = canvas.getContext('webgl2', { antialias: true }); //获取GL上下文
4      return context;                                  //返回GL上下文对象
5    }


说明 

在渲染WebGL 2.0之前,必须进行Canvas的初始化工作。在本方法中首先通过Canvas的名字找到对应的Canvas。然后获取GL上下文的操作,找到后返回上下文对象。


初始化WebGL 2.0 Canvas的方法已经介绍完毕。一般在较复杂的项目中为了实现更加酷炫的渲染效果需要多套着色器。为了使管理更加便捷,GLUtil.js中还开发了对着色器进行管理的方法,具体代码如下。

代码位置:随书源代码/第2章/Sample2_1/js目录下的GLUtil.js文件。

1     function loadSingleShader(ctx, shaderScript){      //加载单个着色器的方法
2       if (shaderScript.type == "vertex")               //若为顶点着色器
3         var shaderType = ctx.VERTEX_SHADER;            //顶点着色器类型
4       else if (shaderScript.type == "fragment")        //若为片元着色器
5         var shaderType = ctx.FRAGMENT_SHADER;          //片元着色器类型
6       else {                                           //否则打印错误信息
7         console.log("*** Error: shader script of undefined type '"+shaderScript.type+"'");
8         return null;
9       }
10      var shader = ctx.createShader(shaderType);       //根据类型创建着色器程序
11      ctx.shaderSource(shader, shaderScript.text);     //加载着色器脚本
12      ctx.compileShader(shader);                       //编译着色器
13      var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);//检查编译状态
14      if (!compiled && !ctx.isContextLost()){          //若编译出错
15        var error = ctx.getShaderInfoLog(shader);      //获取错误信息
16        console.log("*** Error compiling shader '"+shaderId+"':"+error);//打印错误信息
17        ctx.deleteShader(shader);                      //删除着色器程序
18        return null;                                   //返回空
19      }
20      return shader;                                   //返回着色器程序
21    }
22    function loadShaderSerial(gl, vshader, fshader){   //加载链接顶点、片元着色器的方法
23      var vertexShader = loadSingleShader(gl, vshader);//加载顶点着色器
24      var fragmentShader = loadSingleShader(gl, fshader);  //加载片元着色器
25      var program = gl.createProgram();                //创建着色器程序
26      gl.attachShader (program, vertexShader);         //将顶点着色器添加到着色器程序中
27      gl.attachShader (program, fragmentShader);       //将片元着色器添加到着色器程序中
28      gl.linkProgram(program);                         //链接着色器程序
29      var linked = gl.getProgramParameter(program, gl.LINK_STATUS);//检查链接是否成功
30      if (!linked && !gl.isContextLost()){             //若链接不成功
31        var error = gl.getProgramInfoLog (program);    //获取错误信息
32        console.log("Error in program linking:"+error);//打印错误信息
33        gl.deleteProgram(program);                     //删除着色器程序
34        gl.deleteProgram(fragmentShader);              //删除片元着色器
35        gl.deleteProgram(vertexShader);                //删除顶点着色器
36        return null;                                   //返回空
37      }                                                //返回着色器程序
38      gl.useProgram(program);                          //指明使用的着色器编号
39      gl.enable(gl.DEPTH_TEST);                        //打开深度检测
40      return program;                                  //返回着色器程序
41    }

上文已经详细介绍了着色器的操作、管理工具类和初始化上下文的相关方法,接下来将介绍经常使用的MatrixState工具类。此类的作用是对各种变换矩阵进行管理。在执行各种变换时,本类对矩阵进行计算,其具体代码如下。

代码位置:随书源代码/第2章/Sample2_1/js目录下的MatrixState.js文件。

1     function MatrixState(){
2       this.mProjMatrix = new Array(16);            //投影矩阵
3       this.mVMatrix = new Array(16);               //摄像机矩阵
4       this.currMatrix=new Array(16);               //基本变换矩阵
5       this.mStack=new Array(100);                  //矩阵栈
6       this.setInitStack=function(){                //初始化矩阵的方法
7         this.currMatrix=new Array(16);             //创建存储矩阵元素的数组
8         setIdentityM(this.currMatrix,0);           //将元素填充为单位阵的元素值
9       }
10      this.pushMatrix=function(){                  //保护变换矩阵,当前矩阵入栈
11        this.mStack.push(this.currMatrix.slice(0));
12      }
13      this.popMatrix=function(){                   //恢复变换矩阵,当前矩阵出栈
14        this.currMatrix=this.mStack.pop();
15      }
16      this.translate=function(x,y,z){              //平移变换
17        translateM(this.currMatrix, 0, x, y, z);   //将平移变换记录进矩阵
18      }
19      this.rotate=function(angle,x,y,z)    {       //旋转变换
20        rotateM(this.currMatrix,0,angle,x,y,z);    //将旋转变换记录进矩阵
21      }
22      ……//此处省略了部分方法,读者可参见随书源代码
23    }


提示 

此类中还有对投影矩阵、摄像机矩阵及变换矩阵操作的相关方法。本书篇幅有限,不再赘述,有兴趣的读者可自行查阅随书源代码。


上文已经将项目开发中常用的几个工具类全部介绍完毕。下面介绍与本案例直接相关的三角形绘制脚本Triangle.js。此脚本中包含三角形顶点坐标信息和顶点颜色信息,在绘制时将这些信息传入渲染管线中。具体代码如下。

代码位置:随书源代码/第2章/Sample2_1/js目录下的Triangle.js文件。

1     function Triangle(                                    //声明绘制物体对象所属类
2       gl,                                                 //GL上下文
3       programIn                                           //着色器程序id
4     ){
5         this.vertexData= [3.0,0.0,0.0,  0.0,0.0,0.0,  0.0,3.0,0.0];   
          //三角形顶点的xyz坐标
6         this.vcount=this.vertexData.length/3;             //得到顶点数量
7         this.vertexBuffer=gl.createBuffer();              //创建顶点坐标数据缓冲
8         gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexBuffer); //绑定顶点坐标数据缓冲
9         //将顶点坐标数据送入缓冲
10        gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(this.vertexData),gl.STATIC_DRAW);
11        this.colorsData=[1.0,1.0,1.0,1.0,  0.0,0.0,1.0,1.0,  0.0,1.0,0.0,1.0];  
          //初始化顶点颜色数据
12        this.colorBuffer=gl.createBuffer();               //创建颜色数据缓冲
13        gl.bindBuffer(gl.ARRAY_BUFFER,this.colorBuffer);  //绑定颜色数据缓冲
14        //将颜色数据送入缓冲
15        gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(this.colorsData),gl.STATIC_DRAW);
16        this.program=programIn;                           //初始化着色器程序id
17        this.drawSelf=function(ms) {                      //绘制三角形的方法
18          gl.useProgram(this.program);                    //指定使用某套着色器程序
19          //获取总变换矩阵引用id
20          var uMVPMatrixHandle=gl.getUniformLocation(this.program, "uMVPMatrix");
21          //将总变换矩阵送入渲染管线
22          gl.uniformMatrix4fv(uMVPMatrixHandle,false,new Float32Array(ms.getFinalMatrix()));
23          //启用顶点坐标数据
24          gl.enableVertexAttribArray(gl.getAttribLocation(this.program, "aPosition"));
25          gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);  //绑定顶点坐标数据缓冲
26          //给管线指定顶点坐标数据
27          gl.vertexAttribPointer(gl.getAttribLocation(this.program,"aPosition"),  
            3,gl.FLOAT,false,0, 0);
28          //启用颜色坐标数据
29          gl.enableVertexAttribArray(gl.getAttribLocation(this.program, "aColor"));
30          gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer);   //绑定颜色数据缓冲
31          //给管线指定颜色数据
32          gl.vertexAttribPointer(gl.getAttribLocation(this.program,"aColor"),  
            4,gl.FLOAT,false,0, 0);
33          gl.drawArrays(gl.TRIANGLES, 0, this.vcount);        //用顶点法绘制物体
34    }}

上文已经详细介绍了三角形类的相关代码。可能读者看到绘制三角形方法中的uMVPMatrix、aPosition等变量会感到疑惑,实际上这些变量是着色器中定义的相关变量。接下来将会对本案例中与着色器相关的代码进行简要介绍,首先来看顶点着色器的相关代码。

代码位置:随书源代码/第2章/Sample2_1/shader目录下的vtrtex.bns文件。

1    #version 300 es                                  //使用WebGL2.0着色器
2    uniform mat4 uMVPMatrix;                         //总变换矩阵
3    layout (location = 0) in vec3 aPosition;         //顶点位置
4    layout (location = 1) in vec4 aColor;            //顶点颜色
5    out  vec4 vColor;                                //传递给片元着色器的变量
6    void main(){
7       gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制的顶点位置
8       vColor = aColor;                              //将接收的颜色传递给片元着色器
9    }


第1~9行为顶点着色器的相关代码。顶点着色器的主要作用是执行顶点变换、纹理坐标变换等与顶点相关的操作。此顶点着色器只计算了绘制点的位置并将接收到的颜色数据传入片元着色器。


前面已经详细介绍了顶点着色器的相关代码。可以看到顶点着色器需要传值给片元着色器,下面来对片元着色器的相关代码进行简要介绍。

代码位置:随书源代码/第2章/Sample2_1/shader目录下的fragment.bns文件。

1    #version 300 es                         //使用WebGL2.0着色器
2    precision mediump float;                //使用默认精度
3    in vec4 vColor;                         //接收从顶点着色器传过来的参数
4    out vec4 fragColor;                     //输出到片元颜色
5    void main(){
6       fragColor = vColor;                  //给此片元颜色赋值
7    }

第1~7行为片元着色器的相关代码。片元着色器的作用为执行纹理访问、颜色汇总和雾效等操作。此片元着色器的作用是将接收到的颜色数据作为此顶点的颜色。


说明 

可能有些读者这时对着色器的认识还是一头雾水。其实不必担心,后面的章节中会对着色语言以及着色器的逻辑和作用进行详细讲解。读者只需要对以上代码有基本的认识即可。


所有基础开发工作都已经结束,接下来将详细介绍呈现3D场景的网页的相关代码。此网页中的代码主要作用为初始化上下文及相关参数,为绘制工作做好准备,并且使用setInterval()函数对绘制方法进行定时调用。具体代码如下。

代码位置:随书源代码/第2章/Sample2_1目录下的Sample2_1.html文件。

1     <html>
2         <head>
3         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4         <title>Triangle</title> <!--标题-->
5         <script type="text/javascript" src="js/Matrix.js"></script>
6         ……//此处省略了导入其他JavaScript脚本文件的代码,读者可自行查阅随书源代码
7         <script>
8             var gl;                              //GL上下文
9             var ms=new MatrixState();             //变换矩阵管理类对象
10            var ooTri;                           //要绘制的三角形
11            var shaderProgArray=new Array();     //着色器程序列表,集中管理
12            var currentAngle;                    //旋转角度
13            var incAngle;                        //旋转角度增量
14            var canvas;                          //图形容器
15            function start(){                    //初始化的方法
16              gl = initWebGLCanvas("bncanvas");  //获取GL上下文
17              if (!gl){                          //若获取GL上下文失败
18                alert("创建GLES上下文失败,不支持WebGL2.0!");    //显示错误提示信息
19                return;
20              }
21              gl.viewport(0, 0, canvas.width, canvas.height); //设置视口大小
22              gl.clearColor(0.0,0.0,0.0,1.0);            //设置屏幕背景色RGBA
23              ms.setInitStack();                         //初始化变换矩阵
24              ms.setCamera(0,0,-5,0,0,0,0,1,0);          //设置摄像机
25              ms.setProjectFrustum(-1.5,1.5,-1,1,1,100); //设置投影参数
26              gl.enable(gl.DEPTH_TEST);                  //开启深度检测
27              loadShaderFile("shader/vtrtex.bns",0);     //加载顶点着色器程序
28              loadShaderFile("shader/fragment.bns",0);   //加载片元着色器程序
29              if(shaderProgArray[0]){                    //如果着色器已加载完毕
30                ooTri=new Triangle(gl,shaderProgArray[0]);    //则创建三角形绘制对象
31              }else{
32                //休息10ms后再创建三角形绘制对象
33                setTimeout(function(){ooTri=new Triangle(gl,shaderProgArray[0]);},10); 
34              }
35              currentAngle = 0;                      //初始化旋转角度
36              incAngle = 0.4;                        //初始化角度步进值
37              setInterval("drawFrame();",16.6);      //定时绘制画面
38            }
39            function drawFrame(){                    //绘制一帧画面的方法
40              if(!ooTri){                            //如果三角形没有加载成功
41                console.log("加载未完成!");           //则提示信息
42                return;
43              }
44              //清除着色缓冲与深度缓冲
45              gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
46              ms.pushMatrix();                       //保护现场
47              ms.rotate(currentAngle,0,1,0);         //执行旋转
48              ooTri.drawSelf(ms);                    //绘制物体
49              ms.popMatrix();                        //恢复现场
50              currentAngle += incAngle;              //修改旋转角度
51              if (currentAngle > 360){currentAngle -= 360; } //保证角度范围不超过360°
52            }
53        </script>
54        </head>
55        <body onload="start();">
56        <canvas height="800" width="1200" id="bncanvas">
57            若看到这个文字,则说明浏览器不支持WebGL!
58        </canvas>
59        </body>
60    </html>

项目中的Matrix.js文件是作者针对项目而开发的一个工具文件。此文件已经进行了加密操作,所以此处不进行深入介绍。MatrixState类中对矩阵执行操作的各种方法就是基于此文件进行开发的。

2.2节已经通过三角形的案例为读者介绍了如何使用WebGL 2.0进行3D场景的开发,相信读者已经对开发步骤有了初步的了解,但是要想真正地掌握WebGL 2.0,必须要了解着色器和渲染管线的相关知识,本节将向读者详细介绍这方面的内容。

渲染管线有时也称为渲染流水线,一般是由显示芯片(GPU)内部处理图形信号的并行处理单元组成。这些并行处理单元之间是相互独立的,不同型号的硬件上独立处理单元的数量也有很大的差异。一般越高端的硬件,独立处理单元的数量也就越多。

WebGL 2.0中渲染管线实质上指的是一系列的绘制过程。向程序中输入待渲染3D物体的相关描述信息数据,经过渲染管线处理后,输出的是一帧想要的图像。WebGL 2.0中的渲染管线如图2-7所示。

▲图2-7 WebGL 2.0渲染管线

1.基本处理

该阶段设定3D空间中物体的顶点坐标、顶点对应的颜色、顶点的纹理坐标等属性,并且指定绘制方式,如点绘制、线段绘制或者三角形绘制等。

2.顶点缓冲对象

对于在整个场景中顶点基本数据不变的情况,这部分在程序中是可选的。可以在初始化阶段将顶点数据经过基本处理后送入顶点缓冲对象,这样在绘制每一帧想要的图像时就省去了输入/输出顶点数据的麻烦,直接从顶点缓冲对象中获得顶点数据即可。相比于每次绘制时单独将顶点数据送入GPU的方式,它可以一定程度上节省GPU的I/O带宽,提高渲染效率。

3.顶点着色器

顶点着色器是一个可编程的处理单元,功能为执行顶点的变换、光照、材质的应用与计算等与顶点相关的操作,每个顶点执行一次。其工作过程为首先将顶点的原始几何信息及其他属性传送到顶点着色器中,顶点着色器处理后产生相应的纹理坐标、颜色、点位置等后继流程需要的各项顶点属性信息,然后将其传递给图元装配阶段。

开发人员可以在开发过程中根据实际需求自行开发顶点变换、光照等功能,这大大增加了程序的灵活性。但凡事有利皆有弊,增加灵活性的同时也增加了开发的难度。在WebGL 2.0中顶点着色器的工作原理如图2-8所示。

▲图2-8 WebGL 2.0顶点着色器工作原理

输出变量在顶点着色器赋值后并不是直接将值传递到后继片元着色器对应的输入变量中,在此存在两种情况。

▲图2-9 易变变量的工作原理


说明 

有一定数学知识的读者可能会想到一个问题,对每个片元进行一次插值计算将会非常耗时,严重影响性能。幸运的是,WebGL 2.0的设计者也考虑到了这个问题,这些插值操作都是由GPU中的专用硬件来实现的,因此速度很快,不影响性能。


4.图元装配

在这个阶段主要有两个任务,一个是图元组装,另一个是图元处理。所谓图元组装是指顶点数据根据设置的绘制方式被结合成完整的图元。例如,在点绘制方式下每个图元仅需要一个单独的顶点,在此方式下每个顶点为一个图元;在线段绘制方式每个图元则需要两个顶点,在此方式下每两个顶点构成一个图元;在三角形绘制方式下需要3个顶点构成一个图元。

▲图2-10 剪裁三角形3个顶点生成6个新的顶点

图元处理最重要的工作是剪裁,其任务是消除位于半空间(half-space)之外的部分几何图元,这个半空间是由一个剪裁平面定义的。例如,点剪裁就是简单地接受或者拒绝顶点,线段或多边形剪裁可能需要增加额外的顶点,这具体取决于直线或多边形与剪裁平面之间的位置关系,如图2-10所示。


说明 

图2-10给出了一个三角形图元(图中为点划线绘制)被4个剪裁平面剪裁的情况。4个剪裁平面分别为:上面、左侧面、右侧面、后面。


要进行剪裁是因为随着观察位置、角度的不同,不能总看到(这里可以简单地理解为显示到设备屏幕上)特定3D物体上某个图元的全部。例如,当观察一个正四面体但它离某个三角形面很近时,可能只能看到此面的一部分,这时在屏幕上显示的就不再是三角形了,而是经过裁剪后形成的多边形,如图2-11所示。

▲图2-11 从不同角度、距离观察正四面体

剪裁时,若图元完全位于视景体以及自定义剪裁平面的内部,则将图元传递到后续步骤进行处理;如果其完全位于视景体或者自定义剪裁平面的外部,则丢弃该图元;如果其有一部分位于内部,另一部分位于外部,则需要剪裁该图元。


提示 

关于视景体剪裁的问题会在介绍投影的部分进行详细介绍,这里简单了解即可。


5.光栅化

虽然虚拟3D世界中的几何信息是三维的,但由于目前用于显示的设备都是二维的,因此在真正执行光栅化工作之前,需要将虚拟3D世界中的物体投影到视平面上。需要注意的是,由于观察位置的不同,同一个3D场景中的物体投影到视平面上时可能会产生不同的效果,如图2-12所示。

▲图2-12 光栅化阶段投影到视口

另外,由于在虚拟3D世界中物体的几何信息一般采用连续的量来表示,因此投影的平面结果也是用连续量来表示的。但目前显示设备屏幕都是离散化的(由一个个的像素组成),因此还需要将投影结果离散化,将其分解为一个个离散化的小单元,这些小单元一般称为片元,具体效果如图2-13所示。

▲图2-13 投影后图元离散化

其实每个片元都对应于帧缓冲中的一个像素,之所以不直接称为像素是因为3D空间中的物体是可以相互遮挡的。一个3D场景最终显示到屏幕上虽然是一个整体,但每个3D物体的每个图元都是独立处理的。这就可能出现以下情况,系统先处理的是位于离观察点较远的图元,其光栅化成为一组片元,暂时送入帧缓冲的对应位置。但在后面继续处理离观察点较近的图元时也光栅化出了一组片元,两组片元又对应到帧缓冲中同一个位置,这时距离近的片元将覆盖距离远的片元(如何检测覆盖是在深度检测阶段完成的)。因此某个片元就不一定能成为最终屏幕上的像素,这样称为像素就不准确了,可以将其理解为候选像素。


提示 

每个片元包含对应的顶点坐标、顶点颜色、顶点纹理坐标以及顶点深度等信息,这些信息是系统根据投影前此片元对应3D空间中的位置及与此片元相关的图元中各顶点信息进行插值计算而生成的。


6.片元着色器

片元着色器是处理片元值及相关数据的可编程单元,可以执行纹理采样、颜色汇总、计算雾颜色等操作,每个片元执行一次。片元着色器的主要功能为通过重复执行(每个片元一次),将3D物体中的图元光栅化后每个片元产生的颜色等属性计算出来并送入后继阶段,如剪裁测试、深度测试及模板测试等。

WebGL 2.0中的片元着色器与顶点着色器类似,需要开发人员用着色器语言编程。这在提高灵活性的同时也增加了开发的难度。其基本工作原理如图2-14所示。

▲图2-14 片元着色器工作原理


提示 

原来在WebGL 1.0中片元着色器的内建输出变量gl_FragColor在WebGL 2.0中不存在了,如果需要输出颜色值,则需要声明out(类型为vec4)变量,用声明的变量替代gl_FragColor。在开发中,应尽量减少片元着色器的运算量,可以将一些复杂运算放在顶点着色器中执行。


7.剪裁测试

如果程序中启用了剪裁测试,则程序会检查每个片元在帧缓冲中的对应位置。若对应位置在剪裁窗口中则将此片元送入下一阶段,否则丢弃此片元。

8.深度测试和模板测试

9.颜色缓冲混合

若程序中开启了Alpha混合,则根据混合因子会将上一阶段送来的片元与帧缓冲中对应位置的片元进行Alpha混合;否则送入的片元将覆盖帧缓冲中对应位置的片元。

10.抖动

抖动是一种简单的操作,允许使用少量的颜色模拟出更宽的颜色显示范围,从而使颜色视觉效果更加丰富。例如,可以使用白色以及黑色模拟出一种过渡的灰色。

但使用抖动也是有缺点的,那就是会损失一部分分辨率,因此对于主流原生颜色已经很丰富的显示设备来说,一般是不需要启用抖动的。


提示 

一些系统虽然在API方面支持开启抖动,但这仅仅是为了API的兼容,可能根本不会执行事实上的抖动操作。


11.帧缓冲

WebGL 2.0中的物体绘制并不是直接在屏幕上进行的,而是预先在帧缓冲中进行绘制,每绘制完一帧将绘制结果交换到屏幕上。因此,在每次绘制新帧时都需要清除缓冲中的相关数据,否则有可能产生不正确的绘制结果。

同时需要了解的是为了应对不同方面的需要,帧缓冲是由一套组件组成的,主要包括颜色缓冲、深度缓冲以及模板缓冲,各组件的具体用途如下所示。


提示 

本节只是对渲染管线中的每一个模块进行了简单的介绍,更为具体的内容会在后继章节进行更为详细的讨论,读者只要在概念上有个整体的把握即可。



前面向读者介绍了WebGL 2.0的渲染管线,同时也给出了一个非常简单的旋转三角形案例。到目前为止,读者可能还是不太清楚虚拟3D世界中的立体物体是如何搭建出来的。其实这与现实世界搭建建筑物并没有本质区别,请读者观察图2-15和图2-16中国家大剧院远景和近景的照片。

▲图2-15 国家大剧院的远景

▲图2-16 国家大剧院的近景

从两幅照片可以对比出,现实世界中的某些建筑物远看是平滑的曲面,近看则是由一个个的小平面组成的。3D虚拟世界中的物体也是如此,任何立体物体都是由多个小平面搭建而成的。这些小平面切分得越小,越细致,搭建出来的物体就越平滑。

当然WebGL 2.0的虚拟世界与现实世界还是有区别的,现实世界中可以用任意形状的多边形来搭建建筑物,例如,图2-15中的国家大剧院就是用四边形搭建的,而WebGL 2.0中仅允许采用三角形来搭建物体。这从构造能力上来说并没有区别,因为任何多边形都可以拆分为多个三角形,只需开发时稍微注意一下即可。

图2-17更加具体地说明了在WebGL 2.0中如何采用三角形来构建立体物体。

▲图2-17 用三角形搭建立体物体


说明 

从图2-17中可以看出用三角形可以搭建出任意形状的立体物体,这里仅给出了几个简单的例子,后继章节中还有很多其他形状的立体物体。


了解了WebGL 2.0中立体物体的搭建方式后,下面就需要了解WebGL 2.0中的坐标系了。WebGL 2.0采用的是三维笛卡儿坐标系,如图2-18所示。

▲图2-18 WebGL 2.0中的坐标系

从图2-18中可以看出,WebGL 2.0采用的是右手标架坐标系。一般来说,初始情况下y轴平行于屏幕的竖边,x轴平行于屏幕的横边,z轴垂直于屏幕平面。

提示 

空间解析几何中有左手标架和右手标架两种坐标系标架。本书并非讨论空间解析几何的专门书籍,因此关于标架的问题不予详述,需要的读者可以参考空间解析几何的书籍或资料。


通过对本章的学习,读者应该对WebGL 2.0的基本情况有了大概的了解。本章对市面上基于WebGL 2.0的应用和游戏进行了介绍,使读者感受到画面的精美和渲染能力的强大,这为以后自行开发酷炫的应用和游戏打下了坚实的基础。


相关图书

TypeScript全栈开发
TypeScript全栈开发
Java EE企业级应用开发实战(Spring Boot+Vue+Element)
Java EE企业级应用开发实战(Spring Boot+Vue+Element)
Vue.js全平台前端实战
Vue.js全平台前端实战
Flutter内核源码剖析
Flutter内核源码剖析
智能前端技术与实践
智能前端技术与实践
从0到1:ES6快速上手
从0到1:ES6快速上手

相关文章

相关课程