#
摘要: 作者:shuke 来源:PHP蓝皮书 很多书讲到类总喜欢拿小汽车来做例子,但是有些例子实在是又臭又烂误人子弟,骗人钱财,毁人前程,弱智低级到瞎编一个什么 set_color()函数来教人。实在是白白糟踏了好东西。今天在phpx.com又看到一个受害者,忍不住花了两个小时写了这个教程。 闲话少说,我们来正经的,我们的小...
阅读全文
在了解过世界最大的PHP站点,Facebook的后台技术后,
今天我们来了解一个百万级PHP站点的网站架构:Poppen.de。Poppen.de是德国的一个社交网站,相对Facebook、Flickr来说
是一个很小的网站,但它有一个很好的架构,融合了很多技术,如
Nigix、MySql、CouchDB、Erlang、Memcached、RabbitMQ、PHP、Graphite、Red5以及Tsung。
51CTO推荐阅读:大型B2C网站高性能可伸缩架构技术探秘
Poppen.de目前有200万注册用户数、2万并发用户数、每天20万条私有消息、每天25万登录次数。而项目团队有11个开发人员,两个设计,两个系统管理员。该站点的商业模式采用免费增值模式,用户可以使用搜索用户、给好友发送消息、上载图片和视频等功能。
如果用户想享受不受限制发送消息和上载图片,那么就得根据需要支付不同类型的会员服务,视频聊天及网站其他服务也采用同样的策略。
Nginx
Poppen.de
所有的服务都是基于Nginx服务上的。前端有两台Nginx服务器在高峰期提供每分钟15万次请求的负载,每个机器已经有四年寿命,并且只有一个CPU
和3GB
RAM。Poppen.de拥有三台独立的图像服务器,由三台Nginx服务器为*.bilder.poppen.de提供每分钟8万次请求服务。
Nginx
架构中一个很酷的设计就是有很多请求是由Memcached处理的,因此请求从缓存中获取内容而不需要直接访问PHP机器。比如,用户信息页(user
profile)是网站需要密集处理的内容,如果把用户信息页全部缓存到Memcached上,那么请求直接从Memcached上获取内容。
Poppen.de的Memcached每分钟可以处理8000次请求。
架构中有三个Nginx图像服务器提供本地图像缓存,用户上载图
像到一个中央文件服务器。当向这三个Nginx之一中请求图像时,如果服务器本地中没有存在该图像,则从中央文件服务器下载到该服务器上作缓存并提供服
务。这种负载均衡的分布式图像服务器架构设计可以减轻主要存储设备的负载。
PHP-FPM
该网站运行在PHP- FPM上。共有28台双CPU、6GB内存的PHP机器,每个机器上运行100个PHP-FPM的工作线程。使用启用了APC的PHP5.3.x。 PHP5.3可以降低CPU和内存使用率的30%以上。
51CTO推荐阅读:Nginx + PHP-FPM + APC=绝妙的组合
程序代码是基于Symfony1.2框架之上开发的。一是可以使用外部资源,二是
能够提高项目开发进度,同时在一个著名的框架上可以让新开发人员更容易加入到团队中来。虽然没有任何事情都是十全十美的,但可以从Symfony框架中得
到很多好处,让团队可以更多的精力放在Poppen.de的业务开发上去。
网站性能优化使用XHProf,这是Facebook开源出来的一个类库。这个框架非常容易个性化和配置,能够可以缓存大部分高代价的服务器计算。
MySQL
MySQL是网站主要的RDBMS。网站又几个MySql服务器:一台4CPU、32GB的服务器存储用户相关信息,如基本信息、照片描述信息等。
这台机器已经使用了4
年,下一步计划会使用共享集群来替换它。目前仍基于这个系统上进行设计,以简化数据访问代码。根据用户ID进行数据分区,因为网站中大部分信息都是以用户
为中心的,如照片、视频、消息等。
推荐专题:MySQL数据库入门与精通教程
有三台服务器按主-从-从配置架构提供用户论坛服务。一台从服务器负责网站自定义消息存储,到现在有 2.5亿条消息。另外四台机器为主-从配置关系。另外由4台机器配置成NDB族群专门服务于密集型写操作数据,如用户访问统计信息。
数据表设计尽量避免关联操作,尽可能缓存最多的数据。当然,数据库的结构化规范已经完全被破坏掉了。因此,为了更容易搜索,数据库设计创建了数据挖
掘表。大部分表是MyISAM型表,可以提供快速查找。现在的问题是越来越多的表已经全表锁住了。Poppen.de正考虑往XtraDB存储引擎上迁
移。
Memcached
网站架构中Memcached应用相当多,超过45GB的高速缓存和51个节点。缓存了Session会话、视图缓存以及函数执行缓存等。架构中有
一个系统 当记录被修改时可以自动地把数据更新到缓存中去。未来改善缓存更新的可能方案是使用新的Redis Hash API或者MongoDB。
RabbitMQ
在
2009年中开始在架构中使用RabbitMQ。这是一个很好的消息解决方案,便于部署和集中到这个架构中去,在LVS后运行了两台RabbitMQ服务
器。在上个月,已经把更多的东西集成到该队列中,意味着同一时刻有28台PHP服务器每天要处理50万次请求。发送日志、邮件通知、系统消息、图像上载等
更多的东西到这个队列中。
应用PHP-FPM中的fastcgi_finish_request()函数集成队列消息,可以把消息异步发 送到队列中。当系统需要给用户发送HTML或JSON格式响应时,就调用这个函数,这样用户就没有必要等到PHP脚本清理。
这个系统可以改善架构资源管理。例如,在高峰期服务每分钟可以处理1000次登录请求。这表示有1000并发更新用户表保存用户的登录时间。由于使
用了队列机制,可以
按相反的顺序来运行这些查询。如果需要提高处理速度,只需要增加更多的队列处理者即可,甚至可以增加更多的服务器到这集群中去,而不需要修改任何配置和部
署新节点。
CouchDB
日志存储CouchDB运行在一台机器上。在这台机器上可以根据模块/行为进行日志查询
/分组,或者根据错误类型等等。这对定位问题非常有用。在使用日志聚合服务CouchDB之前,不得不逐台登录到PHP服务器上设法日志分析定位问题,这
是非常麻烦的。而现在把所有的日志集中到队列中保存到CouchDB中,可以集中进行问题检查和分析。
Graphite
网站使用Graphite采集网站实时信息并统计。从请求每个模块/行为到Memcached的命中和未命中、RabbitMQ状态监控以及
Unix负载等等。Graphite服务平均每分钟有4800次更新操作。实践已经证实要监测网站发发生什么是非常有用的,它的简单文本协议和绘图功能可
以方便地即插即 用的方式用于任何需要监控的系统上。
一件很酷的事情是使用Graphite同时监控了网站的两个版本。一月份部署了Symfony框架新 版本,以前代码作为一个备份部署。这就意味着网站可能会面临性能问题。因此可以使用Graphite来对两个版本在线进行对比。
发现新版本上的Unix负载表较高,于是使用XHProf对两个版本进行性能分析,找出问题所在。
Red5
网站为用户也提供了两种类型的视频服务,一种是用户自己上载的视频,另外一种是视频聊天,用户视频互动和分享。到2009年年中,每月为用户提供17TB的流量服务。
Tsung
Tsung
是一个Erlang编写的分布式基准分析工具。在Poppen.de网站中主要用于HTTP基准分析、MySQL与其他存储系统(XtraDB)的对比分
析。用一个系统记录了主要的MySQL服务器的流量,再转换成Tsung的基准会话。然后对该流量进行回放,由Tsung产生数以千计的并发用户访问实验
室的服务器。这样就可以在实验环境中与真实场景非常接近。
社交网
现在,传统的互联网正在迈向一个一个全新的时代 ---- 社交服务网时代( Social Networking Service
),从“人与机器”的时代迈向“人与人”的时代。互联网社交服务网站的发展验证了“六度分隔理论”( Six Degrees of
Separation
),即“人际关系脉络方面你必然可以通过不超出六位中间人间接与世上任意先生女士相识”。个体的社交圈会不断地扩大和重叠并在最终形成大的社交网络。无论
是国外的 Facebook 、 MySpace 、 Twitter
,还是国内的开心网、人人网等一头扎进社交网,他们认定社交网必然掀起新一轮的互联网革命。
社交网其中一个的显著特点是支持巨大用户数,例如 Facebook 支持超过 3 亿的用户, Facebook
数据中心运行着超过万台的服务器,为这些遍布全球的用户提供信息通讯服务。另外,任何两个社交网用户都可能交互,也就是必须支持任何两个数据库用户的数据
关联操作。这种情况下,对于服务端的数据库管理提出了极大的挑战。
关系数据库与 NoSQL 数据库
关系数据库使用者遵循一些数据库范式,这些范式是数据库设计中的一系列原理和技术,其目的是为了减少数据库中数据冗余,并增进数据的一致性。结构化查询语言 SQL ,大量使用多表连接操作, SQL 的通用性为数据库使用者带来很多方便。
随着越来越多如 Web 服务之类承受大规模工作负荷的应用的发行,其对可伸缩性的需求,首先有可能会改变得非常迅速,其次会变得无比庞大。
关系数据库的确能伸缩自如,但通常只能单台服务器节点上进行。 例如采用表分区技术,一个表格可以由多个物理文件组成,虽然表格的容量增大了,但该表格仍然只能由一数据库引擎管理。
一旦单节点的能力抵达上限,你就得通过多服务器节点来往外扩展来分发负载。这时候关系数据库的复杂性就开始影响其潜在的扩展规模了。 RDBMS
支持分区视图 (Partition View) 技术,也就是支持联邦数据库 (Federated Databases) 概念【图 1
】。一个分区视图可以由多个分布在不同的数据库节点服务器上的表格组合而成,数据库用户只看到是该视图,不关心多个物理表格。通过数据水平分割技术,分区
视图把负载分担到多个数据库节点服务器上。扩容时,该方法除了需改动视图定义外,分区视图成为分布式数据库系统的中心,存在单点故障问题。另外,跨数据库
节点之间多表格间连接操作的支持出现极大困难。
图 1. IBM 联邦数据库的体系结构
当试图扩展数据库系统到成百上千个节点,而不是几个,将导致不堪复杂性之重负,这一特点使得 RDBMS 在大型分布式系统平台市场里的生存能力被大幅削减。
为了能向客户提供的一个伸缩自如的空间去存放应用数据,供应商实际上只有一种真正的选择。他们不得不实现一种新型的关注于可扩性的数据库系统,而牺
牲掉关系数据库所带来的其他好处。 NoSQL 是非关系型数据存储的广义定义。它打破了长久以来关系型数据库与 ACID 理论大一统的局面。
NoSQL 数据存储不需要固定的表结构,通常也不存在连接操作。在超大型数据存取上具备关系型数据库无法比拟的性能优势。该术语在 2009
年初得到了广泛认同。其中 key-value 数据模型是解决大型数据库系统扩充问题的一种可行的解决方案。
Berkeley DB Key-Value数据模型
Berkeley DB 是一种支持 key-value 数据模型的嵌入式数据库存储引擎。不支持 Client/Server
网络访问方式,程序通过进程内的 API 访问数据库。不支持 SQL
或者其他的数据库查询语言,不支持表结构和数据列。访问数据库的程序自主决定数据如何储存在记录里,一条记录由一个称为键 key 的数据块和一个称为值
value 的数据块组成。 Berkeley DB
不对记录里的数据进行任何包装。应用程序可通过一回调函数来定义不同键之间的大小关系。记录和它的键都可以达到 4G 字节的长度。尽管架构很简单,
Berkeley DB 却支持很多高级的数据库特性,比如 ACID 数据库事务处理, 细粒度锁, XA 接口,热备份以及同步复制。
Berkley DB 为不同用户提供多种功能集( Feature Set ) : 支持单个写线程的数据存储( Data Store
);支持多并发写线程的并发数据存储( Concurrent Data Store ) ; 支持 ACID 和灾难恢复的事务数据存储(
Transactional Data Store );和通过复制支持容错的高可靠数据存储( High Availability )。
实际上,一个关系数据库系统由两个独立的部分组成,一是存储引擎,二是关系引擎。存储引擎负责记录存储,索引和事务处理。关系引擎基于存储引擎提供
的服务,根据表格、视图的数据结构 (Schema) 和已建立的索引等信息, 负责分析 SQL 查询,制定查询执行计划。 Berkeley DB
是一种存储引擎。例如 MySQL 数据库可采用 MyISAM 、 InnoDB 、 Berkeley DB 等存储引擎【图 2 】。
图 2 : MySQL 使用的多种存储引擎
Berkeley DB 支持平衡树( BTree )、哈希( Hash )、队列( Queue )和记录( Record
)等数据集存储、索引方式。 Berkeley DB 支持根据 key-value 中的 key 创建集群索引( Clustered Index
)。这样记录集的物理次序就根据 key 的大小来排列。如果要查询结果记录集的键值为给定的一个范围,该特性对于支持这种类型的快速查询起了很大作用。
Berkeley DB 的一个 key-value 记录集称为一个数据库,一个数据库存储在一单独文件中。 Berkeley DB
通过创建辅助数据库( Secondary Database )允许对记录集建立非集群索引( Non-Clustered Index
)。非集群索引适用于结果为一条记录的查询,该记录的键值为给定的一个值。例如社交网用户数据集:
User
如果以 UID 作为主数据库的键,其他字段作为主数据库的值。可再创建一辅助数据库,以 E-mail 作为辅助数据库的键,辅助数据库的值为 E-mail 所对应的 UID ,也就是指向主数据库记录的指针。
若在一个 key-value 数据库查询,一般可根据查询条件创建成一键值,引擎返回一游标( Cursor ),该游标指向等于或大于该键值的结果数据集。
不难看出 Berkeley DB 使用的索引技术与 SQL Server, Oracle 等高端数据库系统是一样的。
其中在 RDBMS 中经常使用的表格连接操作,在 Berkeley DB 中不再支持,需要应用程序去实现两个数据集的连接操作。这是 key-value 数据模型与关系数据模型典型的区别。
基于 key-value 数据模型,可把一个 value 数据块扩充成多个列,来支持列数据模型。
Berkeley DB 除了作为 MySQL 的存储引擎之外,还应用在 OpenLDAP 、 MemCache 等知名软件。
与 Berkeley DB 类似的数据库引擎还有 Tokyo Cabinet/ Tyrant 等。
社交网数据库系统 Cassandra DB
以 Facebook 用户数据集为例子,不大可能把 3
亿条这巨大的数据集存放在同一表格中、同一个文件或由同一台计算机处理,这要求系统能支持数据分区,把数据集分割在多台节点计算机中,每台计算机分担一部
分负载,当用户增加到一定程度时,系统能允许加入新的节点计算机,并且尽可能地减少数据迁移。
2007 年 10 月 30 日, Amazon 的 CTO Werner Vogels 发表了一文章,讨论了一种基于 key-value
数据模型存储系统 Dynamo 。 Dynamo 系统支撑了不少 Amazon 自有的面向电子商务等关键性应用。 Dynamo
上采用的存储引擎是 Berkeley DB 事务数据存储( Transactional Data Store )。 Dynamo 系统主要为存储
1M 左右甚至更小的内容,如购物车、推荐列表等。 Dynamo 设计上有如下一些特点:
通过数据分区复制来支持高可靠性与高可伸缩性
始终可写
一致性与写入速度的折衷,不要求同步写入所有副本
对称,完全去中心化,人工管理工作很小。
Cassandra DB 最初由 Facebook 开发,后转变成了开源项目。它是一个为网络社交云计算设计的数据库。 Cassandra
的主要特点就是它不是一个数据库,而是由一堆数据库节点共同构成的一个分布 式网络服务,对 Cassandra
的一个写操作,会被复制到其他节点上去,对 Cassandra 的读操作,也会被路由到某个节点上面去读取。对于一个 Cassandra
群集来说,扩展性能 是比较简单的事情,只管在群集里面添加节点就可以了。
Cassandra 的用户包括 Facebook 、 Twitter 和 Digg 等。 Digg 工程副总裁 约翰 • 奎因 (John
Quinn)说 :“ Cassandra
采用了完全分散的模式,每个节点都一样,不会出现单一点的故障。其容错率也非常高,数据可以被复制到数据中心的多个节点中。 Cassandra
还非常具有弹性,随着新设备的加入,其读写吞吐量将呈线性增加。”
Cassandra 以 Amazon 专有的完全分布式的 Dynamo 为基础,结合了 Google BigTable 基于列族( Column Family )的数据模型。 P2P 去中心化的存储。很多方面都可以称之为 Dynamo 2.0 。
图 3 为 Cassandra 、 Dynamo 、 key-value 之间的关系及在社交网上的应用。箭头表示依赖关系。
图 3 : Cassandra, Dynamo, key-value 关系图
分布式存储系统 Amazon Dynamo 原理
Dynamo 采用 Consistent Hashing 算法来实现数据分区。
Consistent Hashing 基本原理是:首先求出服务器(节点)的哈希值,并将其配置到 0 ~ 2^32
的圆上。然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过
2^32 仍然找不到服务器,就会保存到第一台服务器上。【图 4 】
图 4 :数据分割到 4 个节点数据库
如果添加一台服务器。只有在圈上,增加服务器的地点逆时针方向的第一台服务器上的部分数据需要迁移到新的节点数据库【图 4 】。
图 5 :添加 Node5 后需要迁移的数据
数据分区后,数据块被复制到 N 个节点上。复制时因为更新产生的一致性问题的维护采取类似拜占庭容错 Quorum 协议( Byzantine
Fault-tolerance Quorum )的机制以及去中心化的复制同步协议。当一个存储节点被认为是拜占庭节点时 , 它的行为可能任意偏移
, 表现在 : 拒绝响应请求、发送错误消息、存储错误信息等。 Quorum 协议中除了 N 之外还有两个关键参数: R 与 W 。 R
代表一次成功的读取操作中最小参与节点数量, W 代表一次成功的写操作中最小参与节点数量。 R 和 W 直接影响性能、一致性。 R 和 W
值过小则影响一致性,过大则影响效率,这两个值要平衡。如果 W 设置 为 1 ,则一个实例中只要有一个节点可写就写成功,不会影响写效率;如果 R
设置为 1 ,只要有一个节点可读,就读成功,不会影响读效率。 (N,R,W) 的典型配置是 (3,2,2) ,同时考虑了一致性和效率。
Facebook 数据库查询语言 : FQL
Facebook 为开发者提供一套和 SQL 风格一致的数据库查询语言,称为 Facebook Query Language (FQL) 。 FQL 是一种基于列的数据查询语言。提供丰富的条件查询,甚至包括子查询。
例如,以下 FQL 查询已安装 Facebook 应用程序的用户 $app_user 的好友 ID 集合:
SELECT uid FROM user WHERE is_app_user = 1 AND uid IN (SELECT uid2 FROM friend WHERE uid1 = $app_user)
与 SQL 重要区别是 FQL 不支持
· 多表连接: JOIN 操作
· 结果集记录个数限制: LIMIT
· 分组统计: GROUP BY 操作
· 排序: ORDER BY 操作
随着技术发展,一部分基于列结构的 NoSQL 数据库开始支持分组、排序等复杂数据统计分析功能。
例子:查询好友信息
例如一个 Facebook 应用程序从以下两个数据集中查找一用户的好友数据集信息 :
User
Friend_List
注 Friend_UID 是一指向 User ( UID )的外键。
RDBMS 应用程序可使用数据集连接操作实现:
SELECT f.UID, u.Friend_UID, u.First_Name, u.Last_Name, u.Icon
FROM Friend_List f, User u
WHERE f.Friend_UID = u.UID AND f.UID=@Input_UID
在社交网数据库系统中,由于 User 数据分布在多台服务器中,其连接操作和外键约束实际上不能支持。
在 Facebook 中查找一用户的好友信息,得分 A)B) 两步操作实现:
A)
SELECT Friend_UID
INTO @Out_Record_Set
FROM Friend_List f
WHERE f.UID=@Input_UID
B)
FOR EACH (Friend_UID in @Out_Record_Set)
SELECT u.Friend_UID, u.First_Name, u.Last_Name, u.Icon
FROM User u
WHERE u.UID = Friend_UID
No-SQL: Not Only SQL
对于那些关系复杂的数据处理和分析统计, SQL 值得花钱。但是当数据库结构非常简单时, SQL 可能没有太大用处。如果能用普通文件存储代替数据库系统部分功能的话,应该优选普通文件存储。
考虑社交网,能够不受限制的扩展比更丰富的功能更加重要。建立大规模社交网成本的压力让很多社交网开发人员努力去寻找更高性价比的解决方案。研究表
明基于普通廉价硬件的分布式存储解决方案甚至比现在的高端数据库更加可靠。当支持 SQL 的 RDBMS 不能解决所有问题的时候, NoSQL
不是简单的 No SQL ,其本质是 No Relational ,这时候 NoSQL 就成为 Not Only SQL 。
就像猫和狗、该隐和亚伯一样,程序员和美工也是对死对头。 程序员和美工就像来自不同星球的两种完全不同的人,他们脑袋所关心的事情也完全不同。
程序员希望网站运行起来完美,而美工希望网站看起来漂亮。 这次,我们将站在程序员的角度看看:程序员对美工的5个经典牢骚。
牢骚1: “为什么美工设计所有东西都喜欢用Flash?!”
网站只需要很简单的按钮和一些文本就行了,但是美工却坚持要使
用flash,就算加载的时间都是原来的三倍也不管。
问题
对
于有些美工来说,单纯使用web技术(HTML、CSS、JavaScript)来建网页的话,就好像把他的创新带进了死胡同。这些技术限制了他们的创造
性,不得不依靠程序员来实现他们的想法。
Flash给了美工无限创作的可能,使得他们(特别是熟悉ActionScript的美工)能够掌控最终的产品。美工可以用Flash来选择任何
typography、tilt、skew元素,还可以增加动画和创造用HTML无法达到的特殊效果。
解决方案
程序
员要首先问问自己:“这个问题最好的技术解决方案是什么?”,是单纯的web技术还是Flash。心态一定要开放,这很重要。然后决定到底哪种技术是最好
的解决方案,跟美工坐下来好好沟通,就项目需要用到的技术和设计列份清单。
比如说,研究页面是否需要迅速加载,是否需要使用特定的字体
来满足营销目的,是否需要动画等。回答完这些问题后,你就可以很好地权衡是否需要使用Flash。
如果可以,让美工也了解下JavaScript
框架,如Dojo和jQuery ,也是一个不错的主意。他们可能没有意识到用AJAX和DHTML可以达到一些特殊效果。
牢骚2:
“美工到底有没有听说过HTML CSS啊?!”
美工用Photoshop很好地完成设计,可是这和网站上实现的方式却有很大不同。
问题
有些美工完全忽视最基本的web技术,导致设计无法实现或相当难在web上实现,排版对图片的依赖性过大,造成用户体验
欠佳。
解决方案
CSS
作为网站设计的语言,作为参与网站制作的美工没有理由不了解下CSS的基础知识。就像我不知道庞大的印刷机是如何运作的,但是我得了解套印、半色调、绿红
黄黑四种标准颜色。如果想要让我设计的作品能达到最佳效果,我得了解印刷的基本知识。网页的设计也是一样的道理。美工无需知道服务器是如何运作的,但是得
对行高、填充、背景图像以及网站制作过程中的其他因素要有一定的了解。
牢骚3:
“美工给我发的PSD文件里面有5万个未命名图层也没有用任何文件夹分开!”
下载完50MB的PS文件后,等了五分钟总算打开了,开始
找个简单的按钮背景,却被这毫无顺序的图层给弄晕了。
问题
程序员需要有序地组织文档,否则会造成程序的失效。对于美
工来说,只要图片在Photoshop窗口上看起来不错就可以了,但是,对于程序员来说,他是面向对象编程的,代码需要有逻辑性。因此,这种毫无顺序的图
层对程序员来说简直就如噩梦一般。
解决方案
其
实,不单单是程序员对这些无组织的PSD文件感到头疼。作为一个创意总监,我也时常退回那些无序的PSD文件,让美工重新组织和整理好图层。出现这个问
题,要尽快告诉美工,明确告知他你需要一个清楚明了的文件。如果不能跟他说(或者美工就是顽固不化),要查找对象的图层,只需在视窗中按住Ctrl键并点
击对象就可以了,并用移动工具移动(快捷键是“V”)。光标所在的所有图层和图层组的背景菜单都会显示出来。选择你需要的图层,如果图层调色板是打开的,
会突出显示正确的图层。
我强烈建议美工学学Photoshop的智能对象(Smart
Objects)功能。它可以把对象的各个图层(比如,包含按钮的图层)收集到主PS文件内置的一个独立文件里。
智能对象的使用也非常简单,有下面几个优点:
*
创建了一个“面向对象”的PS文件,并且重复的元素都有统一的标识。
* 无需图层技术,输出的内容可以直接在web上使用。
* 它减少了PSD文件中图层的数量,因此图层组织起来更容易。
牢骚4: “美工没有针对实际的图形做调整!”
我们使用的是内容管理系统,用户在客户端完全控制所使用的内容。美工设计的模板经常标题只能显示一行,而文本内容只能有一段。
美工希望
模块有个均衡的高和列宽,但是程序员又无法知道这个模块需要填充多少内容。
问题
在网站最后提交之前,使用虚拟内容来
建站,这一方法可以说是历史悠久。但是,由于不是真正的内容,可能会导致美工最终做出的设计不是很让人满意。
解决方案
美
工设计的作品是静态的,但是实际网页的内容是动态的。美工需要认识到这一点,并考虑到一切所有可能出现的情形。这也是让美工制作静态页面的一个主要缺陷,
毕竟内容不是真实的。 我觉得限定下显示标题等元素区域的高度是有必要的。这将有助于你在最后的设计中确认它们需要占用多少空间。
牢
骚5: “美工让我来猜他作品的风格!”
美工没做任何解释把作品交给程序员,让程序员自己选择字体、行高、颜色、宽度、填充、边框等。
问题
跟在Photoshop里建模板不一样,网站开发不是在一个所见即所得的环境下完成的,相反,程序员是通过指定值来决定
尺寸、颜色、版式等。
解决方案
这突出显示了“设计”和“开发”的不同之处。即使美工使用预先设定网格的模板,程序员
还是不太满意。让美工创建一个比较可行的风格指示,显得尤为重要。这个风格指示就作为美工设计的蓝图以减少双方的困惑。
特别牢骚:
“我不需要美工来告诉我怎么编程!”
有的美工希望程序员按照他的方式来做事,也不管这种方式是否可取。
问题
美工来告诉程序员该如何如何写代码就跟程序员教美工如何设计一样,让人觉得难受。但是美工和程序员之间的界限还是很小的,有时候一个人包揽了两
个角色。
如果你一定要清楚地界定一个项目的责任者,那么任何对你决定的猜疑都会让你无法忍受。
别人可以使用的技术在你看来就不行,而让你解释决定又会占用你宝贵的时间,那么你就是要美工完全信任你的决定。
解决方案
听
听美工的看法,你可能无法想得非常周到。我就有好多次是在与美工讨论后,美工提出了我没有想到的解决方案。
无论如何要记住你和美工的共同目的是尽可能创作最好的产品。保持一个开放的心态和冷静的头脑,是不会错的。
EB程序设计的几个阶段与层次(程序设计方面)
它们体现了WEB程序开发的不同技术阶段
也体现了WEB程序员技术水平的进化
后台程序设计方面:
阶段一:入门阶段
在这个阶段,仅实现了基本功能,整个系统用混杂代码完成,可重用性差,无法体现团队合作开发,程序文件的组织混乱,没有明显的层次结构。
阶段二:后台初级阶段
在这个阶段,后台采用了模板技术,也引入了面向对象数据库技术,程序文件的组织较为清晰。
阶段三:后台中级阶段
在这个阶段,开发人员的水平有所提高,引入了MVC模式,使用了第三方的MVC应用程序框架,使得WEB应用程序的开发与桌面程序的开发站到了同一起跑线上。对数据表的设计有一定的认识,并能根据实际应用合理的使用范式。
阶段四:后台中级阶段
在这个阶段,开发人员的水平有所提高,引入了MVC模式,使用了第三方的MVC应用程序框架,使得WEB应用程序的开发与桌面程序的开发站到了同一起跑线上。对系统优化与系统安全有一定的认识,并能在系统开发中考虑到这些因素。
阶段五:后台高级阶段
在这个阶段,开发人员经过多年的经验积累,已具体自己的一套体系与类库,这个阶段将采用自己的MVC框架来实现WEB应用程序。对大并发量下的系统部署与实施有一定的认识。
如果你正在学习jQuery,也许这些资料对你会有所帮助,这里收集和整理了jq常用的功能函 数,熟悉和使用这些功能函数,
能够帮助我们快速完成各种功能, 而且会让我们的代码异常简洁提高工作效率.
Attribute:
$(”p”).css(”attname”,”value”);
//设置……单个属性值(例:”color”,”#FF0000″)
$("p").css({ “margin-left”: “10px”,
“background-color”: “blue” })//设置……多个属性值
$("p”).addClass(css中定义的样式类
型); 给某个元素添加样式
$(”img”).attr({src:”test.jpg”,alt:”test Image”});
给某个元素添加属性/值,参数是map
$(”img”).attr(”src”,”test.jpg”); 给某个元素添加属性/值
$(”img”).attr(”title”,
function() { return this.src }); 给某个元素添加属性/值
$(”元素名称”).html();
获得该元素内的内容(元素,文本等)
$(”元素名称”).html(”<b>new stuff</b>”);
给某元素设置内容
$(”元素名称”).removeAttr(”属性名称”) 给某元素删除指定的属性以及该属性的值
$(”元素名
称”).removeClass(”class”) 给某元素删除指定的样式
$(”元素名称”).text(); 获得该元素的文本
$(”
元素名称”).text(value); 设置该元素的文本值为value
$(”元素名称”).toggleClass(class)
当元素存在参数中的样式的时候取消,如果不存在就设置此样式
$(”input元素名称”).val(); 获取input元素的值
$(”input
元素名称”).val(value); 设置input元素的值为value
Manipulation:
$(” 元素名称”).after(content); 在匹配元素后面添加内容
$(”元素名
称”).append(content); 将content作为元素的内容插入到该元素的后面
$(”元素名
称”).appendTo(content); 在content后接元素
$(” 元素名称”).before(content);
与after方法相反
$(”元素名称”).clone(布尔表达式) 当布尔表达式为真时,克隆元素(无参时,当作true处理)
$(”
元素名称”).empty() 将该元素的内容设置为空
$(”元素 名称”).insertAfter(content);
将该元素插入到content之后
$(”元素名 称”).insertBefore(content); 将该元素插入到content之前
$(”
元 素”).prepend(content); 将content作为该元素的一部分,放到该元素的最前面
$(”元
素”).prependTo(content); 将该元素作为content的一部分,放content的最前面
$(”元
素”).remove(); 删除所有的指定元素
$(”元素”).remove(”exp”); 删除所有含有exp的元素
$(”元
素”).wrap(”html”); 用html来包围该元素
$(”元素”).wrap(element); 用element来包围该元素
Traversing:
add(expr)
add(html)
add(elements)
children(expr)
contains(str)
end()
filter(expression)
filter(filter)
find(expr)
is(expr)
next(expr)
not(el)
not(expr)
not(elems)
parent(expr)
parents(expr)
prev(expr)
siblings(expr)
Core:
$(html).appendTo(”body”) 相当于在body中写了一段html代码
$(elems)
获得DOM上的某个元素
$(function(){……..}); 执行一个函数
$(”div >
p”).css(”border”, “1px solid gray”); 查找所有div的子节点p,添加样式
$(”input:radio”,
document.forms[0]) 在当前页面的第一个表单中查找所有的单选按钮
$.extend(prop)
prop是一个jquery对象,
举例:
jQuery.extend({
min: function(a, b) {
return a < b ? a : b; },
max: function(a, b) { return a > b ? a
: b; }
});
jQuery( expression, [context] ) —$( expression,
[context]); 在默认情况下,$()查询的是当前HTML文档中的DOM元素。
each( callback )
以每一个匹配的元素作为上下文来执行一个函数
举例:1
$(”span”).click(function){
$(”li”).each(function(){
$(this).toggleClass(”example”);
});
});
举例:2
$(”button”).click(function
() {
$(”div”).each(function (index, domEle) {
// domEle == this
$(domEle).css(”backgroundColor”, “yellow”);
if
($(this).is(”#stop”)) {
$(”span”).text(”Stopped at div index #” +
index);
return false;
}
});
});
jQuery Event:
ready(fn);
$(document).ready()注意在body中没有onload事件,否则该函数不能执行。在每个页面中可以有很多个函数被加载执行,按照fn
的顺序来执行。
bind( type, [data], fn )
为每一个匹配元素的特定事件(像click)绑定一个或多个事件处理器函数。可能的事件属性有:blur, focus, load, resize,
scroll, unload, click, dblclick, mousedown, mouseup, mousemove,
mouseover, mouseout, mouseenter, mouseleave, change, select, submit,
keydown, keypress, keyup, error
one( type, [data], fn )
为每一个匹配元素的特定事件(像click)绑定一个或多个事件处理器函数。在每个对象上,这个事件处理函数只会被执行一次。其他规则与bind()函数
相同。
trigger( type, [data] ) 在每一个匹配的元素上触发某类事件。
triggerHandler(
type, [data] ) 这一特定方法会触发一个元素上特定的事件(指定一个事件类型),同时取消浏览器对此事件的默认行动
unbind(
[type], [data] ) 反绑定,从每一个匹配的元素中删除绑定的事件。
$(”p”).unbind()
移除所有段落上的所有绑定的事件
$(”p”).unbind( “click” ) 移除所有段落上的click事件
hover(
over, out ) over,out都是方法,
当鼠标移动到一个匹配的元素上面时,会触发指定的第一个函数。当鼠标移出这个元素时,会触发指定的第二个函数。
$(”p”).hover(function(){
$(this).addClass(”over”);
},
function(){
$(this).addClass(”out”);
}
);
toggle( fn, fn )
如果点击了一个匹配的元素,则触发指定的第一个函数,当再次点击同一元素时,则触发指定的第二个函数。
$(”p”).toggle(function(){
$(this).addClass(”selected”);
},
function(){
$(this).removeClass(”selected”);
}
);
元素事件列表说明
注:不带参数的函数,其参数为可选的 fn。jQuery不支持form元素的reset事件。
事件 描述 支持元素或对象
blur(
) 元素失去焦点 a, input, textarea, button, select, label, map, area
change(
) 用户改变域的内容 input, textarea, select
click( ) 鼠标点击某个对象 几乎所有元素
dblclick(
) 鼠标双击某个对象 几乎所有元素
error( ) 当加载文档或图像时发生某个错误 window, img
focus( )
元素获得焦点 a, input, textarea, button, select, label, map, area
keydown(
) 某个键盘的键被按下 几乎所有元素
keypress( ) 某个键盘的键被按下或按住 几乎所有元素
keyup( )
某个键盘的键被松开 几乎所有元素
load( fn ) 某个页面或图像被完成加载 window, img
mousedown(
fn ) 某个鼠标按键被按下 几乎所有元素
mousemove( fn ) 鼠标被移动 几乎所有元素
mouseout( fn )
鼠标从某元素移开 几乎所有元素
mouseover( fn ) 鼠标被移到某元素之上 几乎所有元素
mouseup( fn )
某个鼠标按键被松开 几乎所有元素
resize( fn ) 窗口或框架被调整尺寸 window, iframe, frame
scroll(
fn ) 滚动文档的可视部分时 window
select( ) 文本被选定 document, input, textarea
submit(
) 提交按钮被点击 form
unload( fn ) 用户退出页面 window
JQuery Ajax 方法说明:
load(
url, [data], [callback] ) 装入一个远程HTML内容到一个DOM结点。
$(”#feeds”).load(”feeds.html”);
将feeds.html文件载入到id为feeds的div中
$(”#feeds”).load(”feeds.php”, {limit:
25}, function(){
alert(”The last 25 entries in the feed have been
loaded”);
});
jQuery.get( url, [data], [callback] ) 使用GET请求一个页面。
$.get(”test.cgi”, { name: “John”, time: “2pm” }, function(data){
alert(”Data
Loaded: ” + data);
});
jQuery.getJSON( url, [data], [callback] )
使用GET请求JSON数据。
$.getJSON(”test.js”, { name: “John”, time: “2pm” },
function(json){
alert(”JSON Data: ” + json.users[3].name);
});
jQuery.getScript(
url, [callback] ) 使用GET请求javascript文件并执行。
$.getScript(”test.js”,
function(){
alert(”Script loaded and executed.”);
});
jQuery.post(
url, [data], [callback], [type] ) 使用POST请求一个页面。
ajaxComplete(
callback ) 当一个AJAX请求结束后,执行一个函数。这是一个Ajax事件
$(”#msg”).ajaxComplete(function(request,
settings){
$(this).append(”<li>Request
Complete.</li>”);
});
ajaxError( callback )
当一个AJAX请求失败后,执行一个函数。这是一个Ajax事件
$(”#msg”).ajaxError(function(request,
settings){
$(this).append(”<li>Error requesting page ” +
settings.url + “</li>”);
});
ajaxSend( callback )
在一个AJAX请求发送时,执行一个函数。这是一个Ajax事件
$(”#msg”).ajaxSend(function(evt,
request, settings){
$(this).append(”<li<Starting request at ” +
settings.url
+ “</li<”);
});
ajaxStart( callback )
在一个AJAX请求开始但还没有激活时,执行一个函数。这是一个Ajax事件
当AJAX请求开始(并还没有激活时)显示loading信息
$(”#loading”).ajaxStart(function(){
$(this).show();
});
ajaxStop( callback )
当所有的AJAX都停止时,执行一个函数。这是一个Ajax事件
当所有AJAX请求都停止时,隐藏loading信息。
$(”#loading”).ajaxStop(function(){
$(this).hide();
});
ajaxSuccess( callback )
当一个AJAX请求成功完成后,执行一个函数。这是一个Ajax事件
当AJAX请求成功完成时,显示信息。
$(”#msg”).ajaxSuccess(function(evt,
request, settings){
$(this).append(”<li>Successful
Request!</li>”);
});
jQuery.ajaxSetup( options )
为所有的AJAX请求进行全局设置。查看$.ajax函数取得所有选项信息。
设置默认的全局AJAX请求选项。
$.ajaxSetup({
url: “/xmlhttp/”,
global: false,
type: “POST”
});
$.ajax({
data: myData });
serialize( ) 以名称和值的方式连接一组input元素。实现了正确表单元素序列
function
showValues() {
var str = $(”form”).serialize();
$(”#results”).text(str);
}
$(”:checkbox, :radio”).click(showValues);
$(”select”).change(showValues);
showValues();
serializeArray( )
连接所有的表单和表单元素(类似于.serialize()方法),但是返回一个JSON数据格式。
从form中取得一组值,显示出来
function
showValues() {
var fields = $(”:input”).serializeArray();
alert(fields);
$(”#results”).empty();
jQuery.each(fields, function(i, field){
$(”#results”).append(field.value
+ ” “);
});
}
$(”:checkbox, :radio”).click(showValues);
$(”select”).change(showValues);
showValues();
JQuery Effects 方法说明
show(
) 显示隐藏的匹配元素。
show( speed, [callback] )
以优雅的动画显示所有匹配的元素,并在显示完成后可选地触发一个回调函数。
hide( ) 隐藏所有的匹配元素。
hide(
speed, [callback] ) 以优雅的动画隐藏所有匹配的元素,并在显示完成后可选地触发一个回调函数
toggle( )
切换元素的可见状态。如果元素是可见的,切换为隐藏的;如果元素是隐藏的,切换为可见的。
slideDown( speed,
[callback] )
通过高度变化(向下增大)来动态地显示所有匹配的元素,在显示完成后可选地触发一个回调函数。这个动画效果只调整元素的高度,可以使匹配的元素以
“滑
动”的方式显示出来。
slideUp( speed, [callback] )
通过高度变化(向上减小)来动态地隐藏所有匹配的元素,在隐藏完成后可选地触发一个回调函数。这个动画效果只调整元素的高度,可以使匹配的元素以”滑动”
的方式隐藏起来。
slideToggle( speed, [callback] )
通过高度变化来切换所有匹配元素的可见性,并在切换完成后可选地触发一个回调函数。
这个动画效果只调整元素的高度,可以使匹配的元素以”滑动”的方式隐藏或显示。
fadeIn( speed, [callback] )
通过不透明度的变化来实现所有匹配元素的淡入效果,并在动画完成后可选地触发一个回调函数。 这个动画只调整元素的不透明度,也就是说所有匹配的元素的
高
度和宽度不会发生变化。
fadeOut( speed, [callback] )
通过不透明度的变化来实现所有匹配元素的淡出效果,并在动画完成后可选地触发一个回调函数。 这个动画只调整元素的不透明度,也就是说所有匹配的元素的
高度和宽度不会发生变化。
fadeTo( speed, opacity, [callback] )
把所有匹配元素的不透明度以渐进方式调整到指定的不透明度,并在动画完成后可选地触发一个回调函数。 这个动画只调整元素的不透明度,也就是说所
有匹配的元素的高度和宽度不会发生变化。
stop( ) 停止所有匹配元素当前正在运行的动画。如果有动画处于队列当中,他们就会立即开始。
queue(
) 取得第一个匹配元素的动画序列的引用(返回一个内容为函数的数组)
queue( callback )
在每一个匹配元素的事件序列的末尾添加一个可执行函数,作为此元素的事件函数
queue( queue )
以一个新的动画序列代替所有匹配元素的原动画序列
dequeue( ) 执行并移除动画序列前端的动画
animate(
params, [duration], [easing], [callback] ) 用于创建自定义动画的函数。
animate(
params, options ) 创建自定义动画的另一个方法。作用同上。
JQuery Traversing 方法说明
eq(
index ) 从匹配的元素集合中取得一个指定位置的元素,index从0开始
filter( expr )
返回与指定表达式匹配的元素集合,可以使用”,”号分割多个expr,用于实现多个条件筛选
filter( fn )
利用一个特殊的函数来作为筛选条件移除集合中不匹配的元素。
is( expr )
用一个表达式来检查当前选择的元素集合,如果其中至少有一个元素符合这个给定的
表达式就返回true。
map( callback )
将jQuery对象中的一组元素利用callback方法转换其值,然后添加到一个jQuery数组中。
not( expr )
从匹配的元素集合中删除与指定的表达式匹配的元素。
slice( start, [end] )
从匹配元素集合中取得一个子集,和内建的数组的slice方法相同。
add( expr ) 把与表达式匹配的元素添加到jQuery对象中。
children( [expr] ) 取得一个包含匹配的元素集合中每一个元素的所有子元素的元素集合。可选的过滤器
将使这个方法
只匹配符合的元素(只包括元素节点,不包括文本节点)。
contents( )
取得一个包含匹配的元素集合中每一个元素的所有子孙节点的集合(只包括元素节点,不
包括文本节点),如果元素为iframe,则取得其中的文档
元素
find( expr ) 搜索所有与指定表达式匹配的元素。
next( [expr] )
取得一个包含匹配的元素集合中每一个元素紧邻的后面同辈元素的元素集合。
nextAll( [expr] )
取得一个包含匹配的元素集合中每一个元素所有的后面同辈元素的元素集合
parent( [expr] )
取得一个包含着所有匹配元素的唯一父元素的元素集合。
parents( [expr] )
取得一个包含着所有匹配元素的唯一祖先元素的元素集合(不包含根元素)。
prev( [expr] )
取得一个包含匹配的元素集合中每一个元素紧邻的前一个同辈元素的元素集合。
prevAll( [expr] )
取得一个包含匹配的元素集合中每一个元素的之前所有同辈元素的元素集合。
siblings( [expr] )
取得一个包含匹配的元素集合中每一个元素的所有同辈元素的元素集合。
andSelf( ) 将前一个匹配的元素集合添加到当前的集合中
取
得所有div元素和其中的p元素,添加border类属性。取得所有div元素中的p元素,
添加background类属性
$(”div”).find(”p”).andSelf().addClass(”border”);
$(”div”).find(”p”).addClass(”background”);
end( )
结束当前的操作,回到当前操作的前一个操作
找到所有p元素其中的span元素集合,然后返回p元素集合,添加css属性
$(”p”).find(”span”).end().css(”border”,
“2px red solid”);
JQuery Selectors 方法说明
基本选择器
$(”#myDiv”) 匹配唯一的具有此id值的元素
$(”div”)
匹配指定名称的所有元素
$(”.myClass”) 匹配具有此class样式值的所有元素
$(”*”) 匹配所有元素
$(”div,span,p.myClass”)
联合所有匹配的选择器
层叠选择器
$(”form input”) 后代选择器,选择ancestor的所有子孙节点
$(”#main
> *”) 子选择器,选择parent的所有子节点
$(”label + input”) 临选择器,选择prev的下一个临节点
$(”#prev
~ div”) 同胞选择器,选择prev的所有同胞节点
基本过滤选择器
$(”tr:first”) 匹配第一个选择的元素
$(”tr:last”) 匹配最后一个选择的元素
$(”input:not(:checked) +
span”)从原元素集合中过滤掉匹配selector的所有元素(这里有是一个临选择器)
$(”tr:even”)
匹配集合中偶数位置的所有元素(从0开始)
$(”tr:odd”) 匹配集合中奇数位置的所有元素(从0开始)
$(”td:eq(2)”)
匹配集合中指定位置的元素(从0开始)
$(”td:gt(4)”) 匹配集合中指定位置之后的所有元素(从0开始)
$(”td:gl(4)”)
匹配集合中指定位置之前的所有元素(从0开始)
$(”:header”) 匹配所有标题
$(”div:animated”)
匹配所有正在运行动画的所有元素
内容过滤选择器
$(”div:contains('John')”)
匹配含有指定文本的所有元素
$(”td:empty”) 匹配所有空元素(只含有文本的元素不算空元素)
$(”div:has(p)”)
从原元素集合中再次匹配所有至少含有一个selector的所有元素
$(”td:parent”)
匹配所有不为空的元素(含有文本的元素也算)
$(”div:hidden”) 匹配所有隐藏的元素,也包括表单的隐藏域
$(”div:visible”)
匹配所有可见的元素
属性过滤选择器
$(”div[id]”) 匹配所有具有指定属性的元素
$(”input[name='newsletter']”)
匹配所有具有指定属性值的元素
$(”input[name!='newsletter']”) 匹配所有不具有指定属性值的元素
$(”input[name^='news']”)
匹配所有指定属性值以value开头的元素
$(”input[name$='letter']”)
匹配所有指定属性值以value结尾的元素
$(”input[name*='man']”) 匹配所有指定属性值含有value字符的元素
$(”input[id][name$='man']”)
匹配同时符合多个选择器的所有元素
子元素过滤选择器
$(”ul li:nth-child(2)”),
$(”ul
li:nth-child(odd)”), 匹配父元素的第n个子元素
$(”ul li:nth-child(3n + 1)”)
$(”div
span:first-child”) 匹配父元素的第1个子元素
$(”div span:last-child”)
匹配父元素的最后1个子元素
$(”div button:only-child”) 匹配父元素的唯一1个子元素
表单元素选
择器
$(”:input”) 匹配所有的表单输入元素,包括所有类型的input, textarea, select 和 button
$(”:text”)
匹配所有类型为text的input元素
$(”:password”) 匹配所有类型为password的input元素
$(”:radio”)
匹配所有类型为radio的input元素
$(”:checkbox”) 匹配所有类型为checkbox的input元素
$(”:submit”)
匹配所有类型为submit的input元素
$(”:image”) 匹配所有类型为image的input元素
$(”:reset”)
匹配所有类型为reset的input元素
$(”:button”) 匹配所有类型为button的input元素
$(”:file”)
匹配所有类型为file的input元素
$(”:hidden”) 匹配所有类型为hidden的input元素或表单的隐藏域
表
单元素过滤选择器
$(”:enabled”) 匹配所有可操作的表单元素
$(”:disabled”)
匹配所有不可操作的表单元素
$(”:checked”) 匹配所有已点选的元素
$(”select
option:selected”) 匹配所有已选择的元素
JQuery CSS 方法说明
css( name )
访问第一个匹配元素的样式属性。
css( properties ) 把一个”名/值对”对象设置为所有匹配元素的样式属性。
$(”p”).hover(function
() {
$(this).css({ backgroundColor:”yellow”, fontWeight:”bolder”
});
}, function () {
var cssObj = {
backgroundColor: “#ddd”,
fontWeight: “”,
color: “#0028f4”
}
$(this).css(cssObj);
});
css( name, value ) 在所有匹配的元素中,设置一个样式属性的值。
offset( )
取得匹配的第一个元素相对于当前可视窗口的位置。返回的对象有2个属性,
top和left,属性值为整数。这个函数只能用于可见元素。
var
p = $(”p:last”);
var offset = p.offset();
p.html( “left: ” +
offset.left + “, top: ” + offset.top );
width( ) 取得当前第一匹配的元素的宽度值,
width(
val ) 为每个匹配的元素设置指定的宽度值。
height( ) 取得当前第一匹配的元素的高度值,
height( val )
为每个匹配的元素设置指定的高度值。
JQuery Utilities 方法说明
jQuery.browser
.msie 表示ie
jQuery.browser.version 读取用户浏览器的版本信息
jQuery.boxModel
检测用户浏览器针对当前页的显示是否基于w3c CSS的盒模型
jQuery.isFunction( obj )
检测传递的参数是否为function
function stub() { }
var objs = [
function
() {},
{ x:15, y:20 },
null,
stub,
“function”
];
jQuery.each(objs,
function (i) {
var isFunc = jQuery.isFunction(objs[i]);
$(”span:eq(
” + i + “)”).text(isFunc);
});
jQuery.trim( str )
清除字符串两端的空格,使用正则表达式来清除给定字符两端的空格
jQuery.each( object, callback )
一个通用的迭代器,可以用来无缝迭代对象和数组
jQuery.extend( target, object1, [objectN] )
扩展一个对象,修改原来的对象并返回,这是一个强大的实现继承的工具,这种继承是采用传值的方法来实现的,而不是JavaScript中的原型链方式。
合
并settings和options对象,返回修改后的settings对象
var settings = { validate:
false, limit: 5, name: “foo” };
var options = { validate: true,
name: “bar” };
jQuery.extend(settings, options);
合并defaults和
options对象,defaults对象并没有被修改。options对象中的值代替了defaults对象的值传递给了empty。
var
empty = {}
var defaults = { validate: false, limit: 5, name: “foo”
};
var options = { validate: true, name: “bar” };
var settings =
$.extend(empty, defaults, options);
jQuery.grep( array, callback,
[invert] ) 通过一个筛选函数来去除数组中的项
$.grep( [0,1,2], function(n,i){
return
n > 0;
});
jQuery.makeArray( obj )
将一个类似数组的对象转化为一个真正的数组将选取的div元素集合转化为一个数组
var arr =
jQuery.makeArray(document.getElementsByTagName(”div”));
arr.reverse();
// use an Array method on list of dom elements
$(arr).appendTo(document.body);
jQuery.map( array, callback ) 使用某个方法修改一个数组中的项,然后返回一个新的数组
jQuery.inArray(
value, array ) 返回value在数组中的位置,如果没有找到,则返回-1
jQuery.unique( array )
删除数组中的所有重复元素,返回整理后的数组
原文出处:http://www.jigwang.com
先说问题在smarty模板文件中 要加载一个外部的地图api 下面看到的是加载后的地图样式 . 在模板文件中加载了外部的include head模板文件 就是这段文件和aip代码冲突.但现在一直不知原因该怎么解决高手,大侠们给看看给点解决办法的和意见哈 先叩谢了!
01 {include file="header.html"} <!-- 加载一个模板文件 -->
02 <!--主体内容开始-->
03 <div class="main" style="padding-top:26px;width:960px;">
04 <div style="width:955px;height:450px;">
05 <!--左边主体开始-->
06 <div style="width:610px;height:438px;margin-top:5px;margin-left:5px;">
07
08
09 <div id="container" style="margin: 0 auto;width: 300px;background: #fff;padding: 0;text-align: left; font-size: 12px;line-height: 1.6;
10 color: #000;">
11
12 <script language="javascript" src="http://api.51ditu.com/js/maps.js"></script>
13
14 <div id="maps" style="position:relative; height:500px; border:black solid 1px;">
15 <div align="center" style="margin:12px;"> </div>
16 </div>
17 {literal}
18 <script language="javascript">
19 var maps = new LTMaps( "maps" );
20
21 maps.cityNameAndZoom( "合肥" ,5);
22 var c = new LTSmallMapControl();
23 maps.addControl(c);
24
25 </script>
26
27 <script type="text/javascript">
28
29 google_ad_client = "pub-7484199396608517";
30 /* 728x90, */
31 google_ad_slot = "4536659261";
32 google_ad_width = 728;
33 google_ad_height = 90;
34
35 </script>
36 {/literal}
37 </div>
38 </div>
39
40 </div>
41 <!--左边主体结束-->
42
43 <!--右边主体开始-->
44 <div style="overflow: hidden; padding-left: 10px;">
45
46
47 </div>
48 </div>
49 <!--主体内容结束-->
50
51 <!-- bottom部分开始 -->
52 <!-- {include file="foot.html"} --> <!-- 加载一个模板文件 -->
php基础学习已经差不多了,但是为检验自己的学习掌握情况,把php基础知识回顾复习了一下
第一个PHP程序
<?php
echo "Hello World!";
?>
1 注释
1.1多行
/*
xxxx
*/
1.2单行
//xxxxx
2.赋值
$a = 'test';
2.1 检查变量是否已声明
isset($a)
2.2 释放变量
unset($a);
2.3 静态变量
static $a;
静态变量可在一个函数几次调用中保持数值,而不会被系统释放,但只能在声明它的函数集中访问到,只能在第一次声明时初始化。
3. 基本类型
3.1 数字类型
3.1.1整数(integer,关键字int)
.整数可用8进制 10进制 16进制 表示
$a=123; //10进制
$b=0123; //8进制
$c=0x123; //16进制
.由于操作系统不同整数精度变化很大,但32位是最常见的
3.1.2浮点(float,关键字float,64位浮点数,精度14位)
.PHP中float和double是等同的
.使用浮点数切记:他们只是近似值
如:2.5在内部常被表示为2.499999999
又如:
if(0.7+0.1>=0.8){
echo 'a';
}else{
echo 'b';
}
返回值为b,这取决于浮点数的确切实现方式,推荐做法是避免使用浮点值做比较
3.2 字符串
.用单引号或双引号包围
如:echo "Hello"; echo 'Hello';
.双引号中的变量会被解释,单引号中的则不会
如:var $name = 'jano';
echo "my name is $name.";//显示 my name is jano
echo 'my name is $name'; //显示 my name is $name
.双引号中的变量可用{}包围来区分变量和后面的字母
如:var $n = "my name is {$name}Yu";//如果没有{}就无法区分变量和字符
.heredoc
$a = <<< HTM
skjdfjsd
lksdfjsdlf
HTML; //后面的表示必须顶在最前面
.获取字符串中的某个字符
$a = 'Hello';
echo $a{1}; // 显示e
echo $a[1]; // 显示e
推荐使用第一种写法可以和数组区分开
3.3 布尔值
true false
4.常用函数
. nl2br 吧字符串中的换行符转化成<br />
如:echo nl2br($a);
.var_dump
显示变量类型和值,如:var_dump($a);
.print_r
var_dump加强版,打印对象类型和内容,数组则打出所有元素,类对象则打印所有成员
如:$a = array(1,2,3,4,5);
print_r($a);
5.数组
数组用array方法声明
例:
$a = array('a','b','c');
$a = array('a','b',array(1,2,3));
.默认从索引0开始赋值
如:$a[]='a'; //$a[0]='a';
$a[]='b'; //$a[1]='b';
.使用字符串值做索引
如:
$a = array('car'=>'Ferrari','Number'=>21,'City'=>'CQ');
echo $a['car'];
.遍历并更改数组元素值
foreach($array as $key=>&$value){// &$value
//...
}
6.特殊类型和值
.NULL 区分大小写,表示无值,从没赋值,用unset清除
.资源
7.强制类型转换
(int)$a
(float)$a
(string)$a
(bool)$a
(array)$a
(object)$a
.特殊的
(int)"0123";//返回123,没有把8进制0123转换为10进制数字
(int)"123 mu tou ren";//返回123
(int)"mu tou ren 123";//返回0,因为转换只从第一个字符开始读,发现非数字立即停止
.转换为布尔值
非空非零则为true(包括正数和负数),0为false
包含0个元素的数组为false
NULL为false
转换为整数
.浮点转换为整型
小数点后的数字舍弃,如果超过证书有效位,结果可能是0或者最小负数
.布尔转换为整型
true为1
false为0
.字符串转换为整型
对字符串左侧第一位进行判断。如果第一位是数字,则会从第一位开始将读取到数字转换成整数。如果第一位不是数字结果为0.
.PHP没有提供其他类型转换为整数的方法
转换为浮点数
.整数转换为浮点数
结果不变
.布尔转换为浮点数
true为1
false为0
.字符串转换成浮点数
与整数类似
.PHP没有提供其他类型转换为浮点数的方法
转换为字符串
将非字符串转换为字符串的方法是在变量前使用“(string)”强制转换。
规则如下:
1.整型或浮点型:结果为其值
2.布尔型:true转换为'1' , false转换为空字符串
3.对象或数组:如果被转换的变量是对象或数组,则转换结果将为字符串对象或字符串数组,需要根据实际情况进行分析。
4.资源类型:返回资源标识号
8.类型判断与获取
.转换成数组
在变量前用“(array)”强制转换。将变量转换成员变量数据类型相同的数组,数组中只有一个元素。
如:
$a=1;
print_r((array)$a);
结果:
Array
(
[0]=> 1
)
.转换为对象
在变量前用“(object)”强制转换。将生成一个新对象,其中名为scalar的成员变量将包含原变量的值。如:
$a=1;
$o = (object)$a;
echo $o->scalar;
使用函数进行数据转换
bool settype(var, string type)
type值: boolean,integer,float,string,array,object,null
.判断类型函数
is_integer 如:is_integer($a); //返回true或false
is_float
is_double
is_real
is_int
is_long
is_numeric
is_string
is_bool
is_array
is_object
is_null
is_resource
is_scalar 是否为一个标量
.类型获取
gettype($a);
9.变量和常量
.常量
define('NUM_USR','0');
$u = NUM_USR;
.引用
$a=0;
$b = &$a;
$b++;
echo $a;//显示1,因为$b是$a的引用,$b改变就表示$a改变
10.操作符
10.1 数学操作符
+ - * / %(取余)
10.2 比较运算符
==
=== 值相同,类型相同
!=
<> 和!=一样都是不等于
!== 值相同,类型不同
<
>
<=
>=
10.3 逻辑运算符
and && 与
or || 或
xor 异或,若一个为true,但不是两个都为true,则结果为true
! 非
10.4 按位操作
& 按位与
| 按位或
^ 按位异或
~ 按位非
<< 左移位
>> 右移位
10.5 三元操作符
表示问号前面的表达式是否为true,是则返回冒号前面的值,不是则返回冒号后面的值
如:
$c = $a > $b ? 1:2;
echo $a>$b ? "hello":"no";
.下面两个语句是等价的
$a = ($b != 'china') ? true : false;
$a = $b != 'china';
10.6 其他操作符
++ 自增
-- 自减
@ 忽略特定函数的调用失败报错,如:
$u=@file(xxx);
. 字符串连接操作,如:$a = 'hello'.'world'; $a = 'hello'.$a;
11.7 特殊的逻辑运算符表达式
$a = 0;
$b = 100;
echo $a || $b;//$a转换为bool值为true时,echo $a,否则echo $b,不管$b表达式是否为true,此表达式会始终显示100
echo $a && $b;//将什么都不显示,因为整个表达式$a && $b返回false
$a = 1;
$b = 0;
echo $a && $b;//将什么都不显示,因为整个表达式$a && $b返回false
echo $a && $b;//始终显示$a
$a = 1;
$b = 0;
$a && $b=12;
echo
$b;//显示12,$a是否为true,为true就会执行$b=12,系统首先读取&&,知道这是个与,于是开始执行&&
amp;前面的语句,发现返回true就再
执行&&后面的语句,发现返回false就不会再执行&&后面的语句了,因为&&逻辑,只要有一个
false 整个表达式就变成false
11.控制结构
11.1 if语句
if(){
//...
}elseif{
//...
}else{
if(){
}
}
11.2 switch语句
switch(){
case expr:
//...
break;
case expr2:
//...
break;
default:
//...
break;
}
如:
switch($a){
case 'go':
//...
break;
case 'come':
//...
break;
default:
//...
break;
}
11.3 while循环
while(){
//...
}
11.4 for循环
for(expr1;expr2;expr3){
//...
}
表达式计算顺序
expr1 当第一次遇到for循环时执行一次。执行完,开始循环迭代
expr2 每次迭代前计算它。如果结果为true就执行代码块
expr3 在每次迭代后计算(执行)它,结果被忽略
expr2 迭代重新开始
11.5 foreach循环
foreach($arrays as $item){
echo $item;
}
11.6 中断循环
break 终止当前循环,后面可以接整数参数,表示跳出多少层循环。
如:break 2;
continue 跳过本次循环进入下次循环,后面可以接整数参数,表示跳过几次循环
如:continue 2;
12 函数
function 函数名(){
//block
}
12.1用return 可停止函数运行
如:
function aa(){
return;
}
12.2参数
引用传递
function aaa(&$xxx){
}
12.3默认值
function aaa($a,$b = 'xxx'){}
12.4可变数量的参数
function xxx(){}
.func_num_args()多少个参数
.func_get_arg()给定的索引位置返回参数
.func_get_args()在数组中返回所有参数
如:
function a(){
$all_params = func_get_args();
}
12.5返回值
function xxx(){
return 值;
}
若想返回多个值,可把结果组成数组并返回
函数支持嵌套,如:函数a中定义了函数b,那么只有在函数a被调用了一次后,函数b的定义才会生效,PHP没有闭包
函数名字大小写不敏感
引用
1.变量引用
$b=&$a;
这样操作$b就是操作$a
2.函数引用
用来实现对函数返回结果的引用
如:
function $func(){
static $var = 0;
return $var;
}
$a=&func();
$a=1;
$b=&func();
echo $b;
结果为:
1
$a的复制对函数的返回值造成了影响,导致$b的值被赋成了$a的值
3.引用释放
$a=1;
$b=&a;
echo $b;
unset($b);//变量$b被释放,但$a被保留
echo $a;
使用unset释放引用后不会小鼠引用中的值
12.6变量范围
脚本内变量为脚本的全局变量,函数内要使用需要用global
如:
$a = 1;
$b = 2;
function a(){
global $a,$b;
echo $a+$b;
}
通过这种访问在函数推出时会记忆变量的任何改动,和引用差不多
12.7 超级全局变量
$GLOBALS 包含正在执行的脚本内部全局可用的所有变量的引用
$_SERVER
$_GET
$_POST
$REQUEST
$_SESSION
$_COOKIE
$_ENV 保存PHP语言引擎所在进程的环境变量。数组的键是变量名
$php_errormsg 执行当前脚本时生成的最新错误信息,只在发生错误的代码范围内可用,php.ini中的track_errors配置要打开
12.8函数范围的可用性
不管在定义前定义后调用,都可用。
12.9 把函数作为变量
function a($msg){}
function b($msg){}
function c($msg){}
$g = 'a';
$g(msg);
13.包含文件
inclue require
如:include('a.php');require('a.php');
inclue是在调用include语句时加载文件
require是在脚本开始加载文件
区别:
1.require不管语句是否执行都会加载,include相反
如:
$a=1;
if($a==2)require('a.inc'); //条件不成立但也加载了,但没有被调用
2.文件不存在时错误处理方式不同
require抛出知名错误并终止脚本,include只有警告信息
13.1 路径
如果没指明明确路径,PHP会在当前目录中查找包含的文件,然后查找php.ini文件中的include_path设置中列出的目录,在unix下分割字符是冒号,在window下是分号
如:
include_path=".:/a/f/"
include_path=".;c:\a\f"
13.2 包含文件返回值
a.php
<?php
return pi();
?>
b.php
<?php
$k=include('a.php');
?>
13.3 防止重复载入
require_once();
include_once();
13.4 自动载入
在php.ini的auto_prepend_file和auto_append_file 在每次执行脚本之前和之后要包含的文件
PHP Code one:
1 //php获取ip的算法
2 $iipp=$_SERVER["REMOTE_ADDR"];
3 echo $iipp;
PHP Code two:
1 //php获取ip的算法
2 $user_IP = ($_SERVER["HTTP_VIA"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : $_SERVER["REMOTE_ADDR"];
3 $user_IP = ($user_IP) ? $user_IP : $_SERVER["REMOTE_ADDR"];
4
5 echo $user_IP;
1 function get_real_ip(){
2 $ip=false;
3 if(!empty($_SERVER["HTTP_CLIENT_IP"])){
4 $ip = $_SERVER["HTTP_CLIENT_IP"];
5 }
6 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7 $ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
8 if ($ip) { array_unshift($ips, $ip); $ip = FALSE; }
9 for ($i = 0; $i < count($ips); $i++) {
10 if (!eregi ("^(10│172.16│192.168).", $ips[$i])) {
11 $ip = $ips[$i];
12 break;
13 }
14 }
15 }
16 return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
17 }
18
19 echo get_real_ip();
PHP Code three:
1 //php获取ip的算法
2 if ($HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"])
3 {
4 $ip = $HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"];
5 }
6 elseif ($HTTP_SERVER_VARS["HTTP_CLIENT_IP"])
7 {
8 $ip = $HTTP_SERVER_VARS["HTTP_CLIENT_IP"];
9 }
10 elseif ($HTTP_SERVER_VARS["REMOTE_ADDR"])
11 {
12 $ip = $HTTP_SERVER_VARS["REMOTE_ADDR"];
13 }
14 elseif (getenv("HTTP_X_FORWARDED_FOR"))
15 {
16 $ip = getenv("HTTP_X_FORWARDED_FOR");
17 }
18 elseif (getenv("HTTP_CLIENT_IP"))
19 {
20 $ip = getenv("HTTP_CLIENT_IP");
21 }
22 elseif (getenv("REMOTE_ADDR"))
23 {
24 $ip = getenv("REMOTE_ADDR");
25 }
26 else
27 {
28 $ip = "Unknown";
29 }
30 echo "你的IP:".$ip ;
PHP Code four:
1 //php获取ip的算法
2 if(getenv('HTTP_CLIENT_IP')) {
3 $onlineip = getenv('HTTP_CLIENT_IP');
4 } elseif(getenv('HTTP_X_FORWARDED_FOR')) {
5 $onlineip = getenv('HTTP_X_FORWARDED_FOR');
6 } elseif(getenv('REMOTE_ADDR')) {
7 $onlineip = getenv('REMOTE_ADDR');
8 } else {
9 $onlineip = $HTTP_SERVER_VARS['REMOTE_ADDR'];
10 }
11 echo $onlineip;
PHP星期几获取代码:
1 date("l");
2 //data就可以获取英文的星期比如Sunday
3 date("w");
4 //这个可以获取数字星期比如123,注意0是星期日
获取中文星期几:
1 $weekarray=array("日","一","二","三","四","五","六");
2 //先定义一个数组
3 echo "星期".$weekarray[date("w")];
获取指定日期是:
1 $weekarray=array("日","一","二","三","四","五","六");
2 echo "星期".$weekarray[date("w","2011-11-11")];
因为date函数非常强大,他完全可以胜任一切这样的工作我附个手册里的表吧 方便随时查阅
1 a - "am" 或是 "pm"
2 A - "AM" 或是 "PM"
3 d - 几日,二位数字,若不足二位则前面补零; 如: "01" 至 "31"
4 D - 星期几,三个英文字母; 如: "Fri"
5 F - 月份,英文全名; 如: "January"
6 h - 12 小时制的小时; 如: "01" 至 "12"
7 H - 24 小时制的小时; 如: "00" 至 "23"
8 g - 12 小时制的小时,不足二位不补零; 如: "1" 至 12"
9 G - 24 小时制的小时,不足二位不补零; 如: "0" 至 "23"
10 i - 分钟; 如: "00" 至 "59"
11 j - 几日,二位数字,若不足二位不补零; 如: "1" 至 "31"
12 l - 星期几,英文全名; 如: "Friday"
13 m - 月份,二位数字,若不足二位则在前面补零; 如: "01" 至 "12"
14 n - 月份,二位数字,若不足二位则不补零; 如: "1" 至 "12"
15 M - 月份,三个英文字母; 如: "Jan"
16 s - 秒; 如: "00" 至 "59"
17 S - 字尾加英文序数,二个英文字母; 如: "th","nd"
18 t - 指定月份的天数; 如: "28" 至 "31"
19 U - 总秒数
20 w - 数字型的星期几,如: "0" (星期日) 至 "6" (星期六)
21 Y - 年,四位数字; 如: "1999"
22 y - 年,二位数字; 如: "99"
23 z - 一年中的第几天; 如: "0" 至 "365"