一转眼已一年多不专注前端方面的开发工作,这一年前端方面的技术又是新天地,偶然接到内部团队邀请我给他们做一个前端的讲座,希望能帮助他们快速、且深刻了解前端这个行业以及行业内的知识,这可真有点让我为难,由于不爱写PPT,遂成此文。
乱花渐欲迷人眼
2015年前端界可谓热闹非凡
- Google的
Angularjs2
正式版迟迟未出,牵动着无数前端工程师的心。 - Facebook的
Reactjs
像一记猛药,让前端工程师High得不能自已。 - 同时Facebook的
ReactNative
让众多iOS
,Android
工程师畏惧。 - Web Components 也要跟前面两位一争高下。
- 国内的
Vue.js
这颗新星也是袅袅升起。
微信也在最近强势推出应用号
,种种迹象表明,Web前端,特别是移动端的Web前端开发将迎来另一番天地。
2015年
- Ecma国际大会宣布正式批准
ECMA-262第6版
,即ECMAScript 2015
。ECMAScript6对Web开发的影响 - 随着HTML5的标准在14年10月由W3C发布为正式推荐标准,15年HTML5的发展也是飞速向前,2015年有80%的App基于HTML5
Flash
在HTML5的冲击下,各大厂商和浏览器商都陆续声明不再使用这一技术。参考Nodejs
和io.js
正式合并。
多年前的JQuery
,Extjs
,Dojo
,Requirejs
,Seajs
如火如荼,现如今也是不温不火,技术迭代如此之快,一不小心就迷失了。
万变不离其中
不论这个行业发展有多迷人,新出的技术又是多么的牛逼,三板斧CSS+HTML+Javascript
永远是铁打的基石,当然随着行业发展,三板斧本身也是在发展中,所以对前端新技术的追求基本上都是在这三者身上,像如日中天的HTML5,CSS3以及JS语言本身的发展。还有浏览器
以及Webview
这两个也非常重要,他们就好比后端工程师要熟悉Unix环境
一个道理。当然大部分前端工程师在还不需要过多去琢磨这两者。
其他的各种吊炸天的技术框架都是浅尝,尝多了发现他们要解决的核心问题是
- 前后端分离
- Web工程化
- Web性能
再抽象就是两个问题
- 工程化
- 产品性能
因为前后端分离的目的是为了提升开发效率和维护效率这应该属于工程的范畴,而引入工程化的概念核心目的就是提升效率,为达目的过程中会去解耦合,减依赖,管理依赖,组件化,即插即用等概念。
当然这类问题不仅仅是前端,很大程度上后端很多技术做很多工作都是致力于去解决这两类问题。
所以当你对这三板斧非常熟悉的时候,就能很好的去驾驭前端的乱花渐欲迷人眼
,否则就是空谈。
桃园三结义
大哥HTML:网页的骨架
二哥CSS:网页多彩的源泉
三弟Javascript:灵魂,没有他只是一副空皮囊
下面就简单的来介绍这三个好兄弟
大哥HTML
超文本标记语言(英文:HyperText Markup Language,HTML)是为“网页创建和其它可在网页浏览器中看到的信息”设计的一种标记语言。HTML被用来结构化信息——例如标题、段落和列表等等,也可用来在一定程度上描述文档的外观和语义。1982年由蒂姆·伯纳斯-李创建,由IETF用简化的SGML(标准通用标记语言)语法进行进一步发展的HTML,后来成为国际标准,由万维网联盟(W3C)维护。
1980年起源于一个物理学家的项目,当时只有少量的标签,直到1993年的时候还是大学生马克·安德森在他的Mosaic浏览器加入<img>
标记,至此HTML添加了越来越多的标签。更加丰富起来。
HTML到底是什么
HTML就是标记语言,换句话说就是 普通 文本,只不过 浏览器 赋予了它神奇力量。
就像
Markdown
一样,也是标记语言,他会被Markdown编辑器赋予优美的样式,同时在特定网页或者编辑器上打开的时候展示出来而已。
浏览器如何解析HTML
当我们在浏览器地址栏输入网址按下Enter
时候,浏览器会发出一个HTTP
请求,然后DNS解析找到对应的服务器IP地址,等一系列过程,最终这个请求会响应带有标记语言的文档,可能是.html
后缀,也可能是其他,反正在Respoonse
的头部会是content-type:text/html; charset=UTF-8
这个过程还可以很细化,也有很多策略。感兴趣戳这里
然后浏览器会解析该特定文本内的
内容,第一句话是类似<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
这句话是告诉浏览器该文档使用的HTML
是哪个版本,浏览器会用对应的方式来渲染,这就是过去IE等浏览器会有诸如
- 标准模式
- 怪异模式
- 准标准模式
- …
现代浏览器都采用HTML5的标准头部<!DOCTYPE html><html lang="zh">
就这一步省去了好多浏览器兼容的麻烦。当然了,互联网产品目前Web前端在PC端的兼容性少很多了,我们可以很大胆的说不兼容IE8及以下,传统的企业Web产品就不评论,很多还在支持陈旧的IE6等,这类不与时俱进的暂不讨论。
然后遇到script
标签会再次发起HTTP
下载对应的Javascript
,遇到link
会再次发起http
请求css
文件,最终将这三者水乳交融的产物呈现给大家就是非常nice的页面。
这个过程可能涉及到浏览器重绘和重新渲染。感兴趣戳这里
HTML核心
HTML核心就是各类TAG
俗称标签或者元素,HTML5的标签总览
分类 | 标签 |
---|---|
文档类型宣告 | <!DOCTYPE html> |
根元素元素 | html |
META元素 | head、 title、base、link、meta、style |
部件元素 | body、section、nav、article、aside、h1、 h2、 h3、h4、 h5、 h6、hgroup、header、footer、address |
分组内容元素 | p、hr、br、pre、blockquote、ol、ul、li、dl、dt、dd、figure、figcaption、div |
文本层次语义元素 | a、em、strong、small、cite、q、dfn、abbr、time、code、var、samp、kbd、sub、sups、i、b、mark、ruby、rt、rp、bdo、span |
编辑元素 | ins、del |
嵌入内容元素 | img、iframe、embed、object、param、video、audio、source、canvas、map、area |
表格元素 | table、caption、colgroup、col、tbody、thread、tfoot、tr、td、th |
表单元素 | form、fieldset、legend、label、button、select、datalist、optgroup、option、textarea、keygen、output、progress、meter |
互动元素 | details、summary、command、menu |
脚本元素 | script、noscript |
HTML很多新的标签以及标签属性比如audio
,vedio
,nav
,footer
等元素都能极大的加快开发效率。
参考文章
HTML展现分类
HTML元素按照展现分为块元素(block element)和内联元素(inline element)也叫行内元素。当然还有inline-block
块级元素
一般是其他元素的容器,能容纳其他块元素和行内元素,块元素好比个四方块,里边用来放其他元素,默认情况下
主要特点
- 独占浏览器一行
- 总是在新行上开始
- 高度、行高以及内外边距都是可控制的。
- 宽度默认100%,除非设定宽度。
- 它可以容纳内联元素和其他块元素
常见的块级元素有
div
p
h1~h6
hr
form
- …
行内元素
一般都是基于语义级(semantic)的基本元素。内联元素只能容纳文本或者其他内联元素,常见内联元素有a和span。
主要特点
- 和其他元素都在一行上
- 高,行高及外边距和内边距不可改变
- 宽度就是它的文字或图片的宽度,不可改变
- 内联元素只能容纳文本或者其他内联元素
元素类型可以通过
display
属性指定。
inline-block
inline-block 的元素既具有 block 元素可以设置宽高的特性,同时又具有 inline 元素默认不换行的特性。当然不仅仅是这些特性,比如 inline-block 元素也可以设置 vertical-align 属性。
简而言之:inline-block 后的元素就是一个格式化为行内元素的块容器( Block container )
文档流和浮动
浏览器窗体自上而下分成一行行每行按照从左到右的顺序排放,这就是文档流的排列形式。
- 如果不对元素做任何定位相关的样式,非浮动块级元素会按照从上而下,行内元素从左到右排列,很显然我们需要去改变它们,这就需要利用浮动或者定位
- 浮动块级元素则按规定浮在行的一端。 若当前行容不下, 则另起新行再浮动。
- 内联元素也不会独占一行。 几乎所有元素(包括块级,内联和列表元素)均可生成子行, 用于摆放子元素。
有三种情况将使得元素脱离文档流而存在
- 浮动(IE中浮动元素也存在于文档流)
- 绝对定位
- 固定定位。
浮动元素不占任何正常文档流空间,而浮动元素的定位还是基于正常的文档流,然后从文档流中抽出并尽可能远的移动至左侧或者右侧。文字内容会围绕在浮动元素周围。当一个元素从正常文档流中抽出后,仍然在文档流中的其他元素将忽略该元素并填补他原先的空间。
基于文档流,有以下定位模式
- 相对定位,即相对于元素在文档流中位置进行偏移,但保留原占位。
- 绝对定位,即完全脱离文档流,相对于position属性非static值的最近父级元素进行偏移。
- 固定定位,即完全脱离文档流,相对于视区进行偏移。
HTML和CSS以及Javascript的关系
HTML就是web页面的骨架结构,
CSS
层级表赋予其多彩的样式,Javascript
赋予其丰富行为能力,让其能动起来。
二哥CSS
CSS是什么
层叠样式表(英语:Cascading Style Sheets,简写CSS),又称串样式列表、级联样式表、串接样式表、层叠样式表、階層式樣式表,一种用来为结构化文档(如HTML文档或XML应用)添加样式(字体、间距和颜色等)的计算机语言,由W3C定义和维护。目前最新版本是CSS2.1,为W3C的推荐标准。CSS3现在已被大部分现代浏览器支持,而下一版的CSS4仍在开发过程中
CSS核心
CSS核心由多组规则组成,每组规则由selector
,property
,value
即选择器、属性、值三者组成 如:
p.tips { // 选择器
font-size: 12px; // property: value
font-family: sans-serif;
}
这句话的意思就是所有class
为tips
的p
元素,即<p class="tips">Hello</p>
,应用字体为sans-serif
,字体大小为12px
。
其中
class
属性是html元素应用css样式链接属性。
selector
CSS的选择器类型非常多,共分为以下几类
基本选择器
- ID选择器
- 类选择器
- 元素类型选择器
- 万用选择器
- 属性选择器
其中属性选择器又有
代码 | 备注 |
---|---|
[attribute] | 元素有attribute 的属性 |
[attribute="value" ] | 属性attribute 里是value |
[attribute~="value" ] | 属性attribute 里使用空白分开的字符串里其中一个是value |
[attribute|="value"] | 属性attribute 里是value 或者以value- 开头的字符串 |
[attribute^="value"] | 属性attribute 里最前的是value |
[attribute$="value"] | 属性attribute 里最后的是value |
[attribute*="value"] | 属性attribute里有value出现过至少一次 |
基本选择器
#btnSave {
font-size: 14px;
color: #ff8a01;
}
.btnSave {
font-size: 14px;
}
button {
font-size: 14px;
}
* {
font-size: 12px;
}
a[class="button"] {
color: #ff8a01;
}
伪元素选择器
伪元素可以选择不在Document结构中的信息。
:after
或者::after
元素之后[常用]:before
或者::before
元素之前[常用]:first-letter
或::first-letter
[不常用]:first-line
或::first-line
[不常用]
例如
p::after {
content:" ";
background-color:yellow;
color:red;
}
伪类选择器
虚拟类选择器指的是为不同的状态、性质的元素。
主要有以下几类
:link
超链接未被访问[常用]:visited
超链接被访问过[常用]:hover
鼠标(鼠标)在元素上面[常用]:active
鼠标(鼠标)在元素上按着[常用]:focus
焦点在元素上[常用]:target
元素被URL标记(CSS 3新增的类)[不常用]:lang
向带有指定lang属性的元素添加样式。[不常用]
例如
a:hover {
backgroud-color: #ff8a01;
}
组合选择器
A > B
选择A下一层的元素BA ~ B
选择与A同父层的元素BA + B
选择与A相邻的元素B(不能被任何元素相隔)A B
包含选择符
还有常见的逗号
,
逗号作用是将多个选择器应用同一组属性和值,
比如
p, a, span {
font-size: 12px;
}
新的CSS3新支持的选择器可以戳这里
CSS的选择器优先级
当同一元素匹配多个选择器的时候,那么该元素应该应用哪一个样式呢?优先级如下
- 通用选择器(*)
- 元素(类型)选择器
- 类选择器
- 属性选择器
- 伪类
- ID 选择器
- 内联样式
- !important 规则例外
盒子模型
区别就在于计算
width
和height
的时候是否加上了padding
和border
.
CSS支持的属性
CSS支持的属性很多,包括背景、颜色、字体、定位、动画等属性
三弟Javascript
1995年出生的Javascript最初只用在浏览器上做简单的表单验证,能在客户端把不符合规范的逻辑去掉,节省网络请求和用户等待时间一下子就广为流行,与此同时微软推出
JScript
,当时的管理者希望这门语言跟同年出来的的Java
一样火,所以取名为Javascript
,直到今日还真不负所望,几乎跟Java一样火,甚至有过之。
回归正题
Javascript到底是什么
尽管对这门语言我有着比较深入的琢磨,可想了好久还是不知道该如何向未接触过它的人来介绍它,想了想还是分两种人尽量来解释清楚
无编程经验
- 脚本语言,可以运行在服务器端和浏览器端
- 能做网页动画效果
有编程经验
- 类C语言
- 弱类型
- 面向对象
- 无所不能
Javascript语言特色
纯粹的面向对象
javascript一切皆对象,哪怕
console.log(true.toString()); // true
console.log("2".length); // 1
你可以直接创建一个对象
var obj = {
name: "liujiangbei",
sayHi: function(name) {
console.log("Hello, " + name);
}
}
弱类型
console.log([] == ![]); // true
[]==![]
相当于[]==false
(没有异议了吧因为![]就是false)[]==false
又是怎么转化的呢,对于Object类型先转化成基础类型Number
00==false
又将false转化为Number也是为0
概括就是
- 对于基本类型Boolean,Number,String,三者之间做比较时,总是向 Number进行类型转换,然后再比较;
- 如果有Object,那么将Object转化成这三种基本类型(PS:到底转换成哪一种呢?我猜测会转化成Number),再进行基本类型比较;
- 对于null和undefined,只有 x,y分别是它们时才相同,其他都为false。
对于类型相同那么
==
操作符就会直接比较值,不会再进行转换了!
建议总是使用===
而不是用==
函数作用域
var testFn = function() {
var abc = "abc";
if (abc) {
var str = "hello";
}
console.log(str);
}
testFn();
运行完输出hello
。
说明Javascript是函数级作用域名,跟
php
一样,而静态语言如Java
,Golang
,C
,C++
都是块级作用域。
闭包
/*
* 闭包:是指有权访问另一个函数作用域中的变量的【函数!!!】
* 创建闭包的常见方式就是在一个函数内部创建另一个函数(通常是匿名函数)
*/
function createComparisonFun(propertyName){
return function(object1,object2){
//这两行代码是匿名函数的内部代码,却访问了外部函数中的变量propertyName
//即使这个内部函数被返回了,而且是在其他地方被调用了,但它仍然可以访问变量propertyName
//之所以还能访问这个变量,是因为内部函数的作用域链包含外部函数如createComparisonFun()的作用域链
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
};
};
基于prototype继承
多变的上下文对象
上下文this是初阶javascript程序员最容易混淆的地方,总结下来
# 方法调用模式
/**
* 方法调用Function
* 1、当一个function被保存为一个对象的属性时,我们称为method
* 2、this绑定到该对象
*/
var obj = {
val: 0,
getVal: function() {
console.log(this); //{ value: 0, getVal: [Function] },充分体现this指的就是obj这个对象
console.log(this.toString()); //[object Object]
return this.val;
}
};
console.log(obj.getVal());
//prototype只能用在类型上!!!不能用于对象上!!!
# 函数调用模式
/**
* 函数调用模式
* 1、当一个函数并非一个对象的属性时,那么就是当一个函数来调用的
* 2、this指向全局对象(大胆猜想这种方案是错的)
* 3、解决此方法的方案就是定义一个变量存储this对象
*/
var add = function(a, b) {
console.log(this.toString()); //[object global]全局变量啊
return a + b;
};
console.log(add(2, 4));
# 解决函数调用模式中this会指向全局变量的方法
/**
* 解决函数调用模式中this会指向全局变量的方法
*/
var obj = {
val: 4,
getVal: function() {
return this.val;
}
};
obj.double = function() { //方法模式,double是obj对象的方法
var that = this; //this指的就是obj对象
var helper = function() { //函数模式
that.val = that.val * 2;
};
helper();
};
obj.double(); //方法模式调用double
console.log(obj.val); //
# 构造器调用模式
/**
* 构造器调用模式
* 1、如果一个函数前面带上一个new来调用,那么就是构造器调用模式
*/
var Person = function(name) {
console.log(this.constructor);
this.name = name;
};
Person.prototype.getName = function() {
return this.name;
};
var person = new Person('ALLEN');
console.log(person.getName());
# apply/call调用模式
/**
* Apply调用模式(apply/call)
* 1、apply让我们构建一个参数数组传递给调用函数,也允许我们选择this的值
*/
var func = function() {
console.log(Object.prototype.toString.apply(this));
console.log(this.value); //this本来指向全局变量,因为是函数调用模式
};
var obj1 = {
value: 'This is the first object\'s value'
};
var obj2 = {
value: 'This is the second object\'s value'
};
func.apply(obj1); //This is the first object's value
func.apply(obj2); //This is the second object's value
Function也是普通类型
Javascript中function也是一个普通数据类型,支持
- 作为参数传递给另一个函数。
- 作为函数的返回值。
参数传递方式
Javascript中参数的传递是值传递。
对于基本类型string
, boolean
, number
, undefied
, null
一眼就看出是安置传递
function test(num) {
num += 10;
return num;
}
var num = 10;
console.log(num); //10 外部变量并未受到影响
console.log(test(num)); //20
而对于object
, array
, function
var testFn = function(abc) {
if (typeof abc === "object") {
abc.name = "liujiangbei";
abc.age = 26;
}
}
var obj = {
name: "liujb",
age: 25
}
testFn(obj);
console.log(obj) // { name: 'liujiangbei', age: 26 }
乍一看,怎么变了?难道是引用传递?请看下边
function setName(obj) {
obj.name = "James";
obj = new Object();
obj.name = "Leon"
}
var person = new Object();
person.name = "Jeremy";
setName(person);
console.log(person.name);//James
以上代码输出的是James,如果是按引用传递,那么以上代码输出的是Leon。实际上,当执行obj.name =
James的时候,引用所指向的对象的值已经发生了改变,当在对obj进行覆盖的时候,obj的值是一个指向局部对象的引用,而这个引用无法对外部的对象产生影响,并且此对象会在函数执行结束之后销毁。
通俗地理解,传递不是引用,而是引用的副本。
Javascript最佳实践
一个好汉三个帮
HTML是页面的骨架,CSS赋予页面姿彩,JS给页面注入灵魂。但是她们具体是如何协作的呢?比如最常见的功能,点击加载更多。
要实现该功能的主要步骤有
- JS获取用户点击事件
- 夹杂着动画效果
- JS发送http请求到对应的server端
- JS接收HTTP请求返回的数据(json、txt、xml等格式)
- 将数据展现
- …
那么问题来了
JS如何获取用户点击事件?
用户点击的是一个按钮,翻译过来就是HTML元素
,JS是如何跟HTML
他的大哥沟通的呢?这里要接住它们共同的温床(浏览器)提供的一个叫做DOM
的东西
什么是DOM?
Document Object Model的历史可以追溯至1990年代后期微软与Netscape的“浏览器大战”(browser wars),双方为了在JavaScript与JScript一决生死,于是大规模的赋予浏览器强大的功能。微软在网页技术上加入了不少专属事物,既有VBScript、ActiveX、以及微软自家的DHTML格式等,使不少网页使用非微软平台及浏览器无法正常显示。DOM即是当时蕴酿出来的杰作。
The Document Object Model (DOM) is a programming interface for HTML, XML and SVG documents. It provides a structured representation of the document (a tree) and it defines a way that the structure can be accessed from programs so that they can change the document structure, style and content. The DOM provides a representation of the document as a structured group of nodes and objects that have properties and methods. Nodes can also have event handlers attached to them, and once that event is triggered the event handlers get executed. Essentially, it connects web pages to scripts or programming languages.
- 通俗理解,就是浏览器给JS提供了获取HTML元素的功能,获取到的DOM元素跟HTML元素能
对应
起来 - 再通俗一点,DOM元素就是HTML元素(虽不对,但无妨)
HTML DOM
定义了所有HTML元素
的对象和属性,以及访问它们的方法。
DOM节点包括
XML DOM
、HTML DOM
、核心DOM
DOM树如下
DOM具备的属性和能力
HTML DOM节点
HTML DOM方法
HTML DOM访问
HTML DOM Event
其中左边菜单的内容都需要看一看!
JS获取按钮并提前给按钮绑定单击事件的代码如下
var btnLoadMore = document.getElementById("btnLoadMore");
btnLoadMore.addEventListen("click", function(e) {
// do somethings..
});
JS通过获取HTML DOM元素,可以对HTML DOM元素进行属性的访问和更改(CSS样式只是HTML元素的属性之一),同时还可以对元素本身作各种更改。还可以提前监听某DOM元素的各类事件,如
click
dbclick
mouseover
- …
JS如何发起HTTP请求并处理响应数据?
传说中的Ajax
XMLHttpRequest对象
XMLHTTP是一组API函数集,可被JavaScript、JScript、VBScript以及其它web浏览器内嵌的脚本语言调用,通过HTTP在浏览器和web服务器之间收发XML或其它数据。XMLHTTP最大的好处在于可以动态地更新网页,它无需重新从服务器读取整个网页,也不需要安装额外的插件。该技术被许多网站使用,以实现快速响应的动态网页应用。例如:Google的Gmail服务、Google Suggest动态查找界面以及Google Map地理信息服务。
特意查了一下,以前都只知道用这个对象,但是没有分清这到底是javascript对象还是浏览器接口,现在看来很清晰了,这就是一个浏览器接口,用于跟后台交换数据。
发起请求和处理请求数据
var xhr = createXHR();
if (!xhr) {
return "create XMLHttpRequest failed.";
}
xhr.open(obj.method, obj.url, true); //true表示异步
// 监听statechange事件
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
obj.succFn(xhr.responseText);
} else {
obj.failFn(xhr.responseText);
}
} else if (xhr.readyState === 3) {} else {}
};
// send request
if (obj.method.toUpperCase() === 'GET') {
xhr.send(null);
} else if (method.toUpperCase() === 'POST') {
var body = objToBody(obj.data);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(body);
}
XMLHttpRequest状态值
- 0: 请求未初始化 create
- 1: 服务器连接已建立 open
- 2: 请求已接收 send
- 3: 请求处理中 比如数据比较大,这个时候就可以开始提示用户
- 4: 请求已完成,且响应已就绪
动画又是如何实现的?
动画实现的本质在于不断的变化元素的属性,1000ms内变化60次肉眼基本就看不出卡顿,大概一帧16.6s
基于此前端动画的实质都是通过
- Javascript本身或
- CSS3本身带的属性去
更改DOM元素的属性来达到动画的目的。当然了还有一些动画是通过动态的gif
图实现的。
通过JS去改变按钮的颜色
var btnMore = document.getElementById('btnMore');
var colorNum = 0;
setInterval(function(){
btnMore.style.backgroundColor = "#ff8a0" + colorNum;
}, 16);
这部分代码只是伪代码
或者还可以把setInterval
改成setTimeout
里边嵌套setTimeout
两者区别
通过CSS3去改变属性
div {
width: 100px;
height: 100px;
background: yellow;
transition: width 2s;
-moz-transition: width 2s; /* Firefox 4 */
-webkit-transition: width 2s; /* Safari and Chrome */
-o-transition: width 2s; /* Opera */
}
div:hover {
width: 300px;
}
该样式就是当鼠标放到div上的时候,在两秒内宽度增长到300px
建议使用CSS3的动画属性来实现动画,因为CSS3本身对GPU加速做了很多优化,比原生JS使用最质朴的方式实现效果要佳一些。当然这只是相对而言。
如果实现的功能要跟浏览器交互呢?
比如做完某某操作之后要关闭浏览器或者实现后退功能
呢?这个时候又该如何?
BOM对象隆重登场
BOM是browser object model的缩写,简称浏览器对象模型
BOM提供了独立于内容而与浏览器窗口进行交互的对象
由于BOM主要用于管理窗口与窗口之间的通讯,因此其核心对象是window
BOM由一系列相关的对象构成,并且每个对象都提供了很多方法与属性
BOM缺乏标准,JavaScript语法的标准化组织是ECMA,DOM的标准化组织是W3C
BOM最初是Netscape浏览器标准的一部分
通俗理解就是提供JS访问浏览器对象的能力,跟XMLHttpRequest类似。
其中
- frames就是常见的iframe嵌套别的网页的
- history有返回上一页功能
- location获得网页URL
- navigator访问者浏览器信息
- screen屏幕相关信息
至此这三者是如何协作的就大概讲了一下。
H5和CSS3
再来简单的讲讲如日中天的HTML5和CSS3。
CSS3
CSS3的核心在我的理解中就是提供了
- 多样化的css选择器
- 支持动画的能力
说起来虽然容易,但是其实还是很实用,也不是那么容易掌握的。
HTML5
HTML5提供的核心功能非常实用,主要有
- 新的语义化的标签和属性并且淘汰过时和冗余的元素和属性
- Geolocation
- localStorage
- FileApi
- Canvas
- 离线存储Mainfest
- 本地数据库
- 多媒体av
- XMLHttpRequest2
Geolocation
就是网页定位,通过Geolocation提供的功能,使得H5页面可以跟Native功能一样的定位。
/**
* H5定位
*/
geo.h5 = function(opt) {
if (!opt) return;
var timeObj = opt.timeout || {};
//H5定位成功回调函数
var succ = function(pos) {
var d = {
lat: pos.coords.latitude,
lng: pos.coords.longitude,
maptype: opt.maptype || "wgs"
};
if (isFunc(opt.success)) opt.success(d);
};
//h5定位失败回调--失败包括超时、或者用户不允许
var error = function(err) {
var st = "";
switch (err.code) {
case err.TIMEOUT:
st = "timeout";
if (isFunc(timeObj.CB)) timeObj.CB(geoFailObj.timeout);
break;
case err.POSITION_UNAVAILABLE:
if (isFunc(opt.error)) opt.error(geoFailObj.position_unavailable);
st = "position_unavailable";
break;
case err.PERMISSION_DENIED:
if (isFunc(opt.denied)) opt.denied(geoFailObj.permission_denied);
st = 'permission_denied';
break;
case err.UNKNOWN_ERROR:
if (isFunc(opt.error)) opt.error(geoFailObj.unknow_error);
st = "unknow_error";
break;
default:
break;
};
};
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(succ, error, {
enableHighAccuracy: true,
timeout: timeObj.cnt || 5000,
maximumAge: 2000
});
}
};
公司的webapp第一版就是我做的,当时用的就是H5定位,微信的定位接口开放还在这之后。
LocalStorage
LocalStorage经常会使用,说白了就是在本地存储一些字符串,用于在不同的网页之间共享数据,相比cookie没有时间限制,大小限制在每个域4M左右,完全沟通。另外cookies会在每次发出HTTP请求的时候带在header上,不仅影响性能,严重的有些server端会限制cookie的大小。LocalStorage简直就是救命稻草
Canvas
动画工程师和网页游戏工程师的救命稻草。能够通过JS画出流畅和高清的动画效果,不再需要去学习陈旧的flash或者还不成熟的webgl
Avdio和Vedio
一个在网页上放视频一个放音乐,目前市面上吊炸天的H5页面哪个不得来点音乐和视频。
以上几个H5新功能是实际产品中运用过并且表现良好。
开发工具
Sublime text 3
Sublime text 是一款轻量级的全平台文本编辑器,突出的功能就是支持海量插件
Plugins
- 安装
Package Control
Sublime的包管理器[必装] HTML-CSS-JS Prettify
代码格式化工具[必装]Trimmer
移除代码中的空格[必装]Emmet
html代码利器,比如在Mac
输入html:5
然后按ctrl+E
就会出现[必装]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> </body> </html>
JSLint
静态JS代码检测[必装]CssLint
CSS样式检测[必装]MarkdownEditing
Markdown编辑工具MarkdownPreview
Markdown文档预览工具CSS3
写CSS3属性时提示功能DocBlockr
添加XML形式的备注信息
Sublime快捷键
Command+D
选词Command+L
选中一行Command+Shift+P
进入控制中心Command+P
搜索页面和页面中的方法- …
其他编辑器如
都是非常优秀的前端编辑器和IDE
Chrome Devtools
最强大的网页调试工具
Chrome Developer Tools
,诸君一定要好好琢磨
同时Chrome还支持移动端调试,有很多模拟器,包括屏幕类型,等。
调试和调试工具
Charles
主界面
主要设置和注意项目
- 保证手机和电脑在同一局域网内。
- 设置
Charles
的代理端口为8888
或者其他都可以。 - 查看本机IP地址
ifconfig en0
找到IP地址
在iOS手机的设置界面如
设置完了之后点左上角的WiFi返回,然后Charles会弹出是否允许你的手机IP访问的窗口,然后点击允许,这样Charles就能抓包了。
支持的主要功能
- 抓包 – 看HTTP请求的明细,如果是HTTPS需要导入密钥也是可以的,自行折腾。
- DNS反向解析 – 支持从特定域名出发,将请求跳转到特定IP的机器,Pre上线使用以及当时微信支付使用。
- 代理本地文件 – 支持某个请求响应到本地文件。
- Charles是抓包工具,不支持像Chrome那样子实时选中元素。
Fiddler
Filder设置和Charles有类似的地方,请点这里
Mac电脑和iPhone手机
- iPhone手机一部
- Mac电脑一台
请看神图
设置
Safari
的Develop属性可见,然后用USB连接线链接iPhone手机,然后在手机上打开你的站点,然后点击一下Develop->iPhone6->www.baidu.com
就会出现Safari的开发者工具面板
而此时,你的iPhone上的页面就变成了
就像你用Chrome浏览器调试PC端网页一样。
神器weire
有人说了我没有Mac和iPhone怎么办,不用着急,我已经为你准备好一切,请戳这里
工程和性能
洋洋洒洒写了好大一篇,为了本文能够首尾呼应,让我们还是专注到Web最核心的两个问题上
- 工程化
- 产品性能
工程化
前端开发的工程化要解决的几个问题
开发阶段前后端分离
目前国内在前后端协作上主要的几类方式
前端工程师切好页面,交给所谓的后端工程师(其实是业务逻辑处理层并非后端服务)然后这些工程师将HTML标签和样式要么换成对应的web框架所需要的模版,要么就直接输出,再结合html中的样式和js达到想要的效果。
在整个页面出来之前需要双方不停的沟通协作,才能完成。
前后端工程师完全通过resetful接口形式进行对接,前端工程师访问静态页面,然后通过ajax去请求resetful接口解析json,然后展现看起来这种方式前后端分离做得比较干净,但是这种方式弊端也不少
会无端增加比较多的请求,本来原来有很多数据可以直接输出到html页面上,或者使用模版而现在需要通过http请求后再次处理。
前后端工程师在完成静态部分开发工作后,将page放到web项目的views下,第一页数据通过业务逻辑处理层将数据通过模版形式输出到页面,而后在页面中的操作如果有跳页面的话过程如第一页,否则都是通过ajax来交互。
虽然这种方式耦合还是没完全解开。沟通成本上较第一种少性能上较第二种好,“后端工程师”可以专注写他们的逻辑,多数交互都是通过resetful接口进行,少部分需要加载模版和页面的请求另外沟通一下,需要组织哪些数据需要哪些逻辑沟通成本不大,前端工程师也可以focus在前端工作上。性能也不知发起很多无谓的请求。属于在目前的方式下比较理性的方式。
在第三种的基础上,将业务逻辑处理成这部分的工作都交给“前端工程师”来做,这部分工程师需要掌握
Nodejs
开发,HTML5+CSS3+Javascript
常规前端开发,可以简单地理解为全栈工程师,这样前端(主要是指业务逻辑层面目前的API)可以实现大部分功能,只需要跟真正的后端服务去做通信即可。这是最理想的前后端分离方式,目前阿里巴巴有技术团队在尝试,沟通成本低,开发统一,都是Javascript为主,唯一的缺陷就是这类人才太少。
综合看来,目前第三种方案是比较常规的方案。
前端分离
前面讲到前后端分离,其实就是在想各种办法去提升开发效率,而前端本身的一些分离原则则主要是为了后续的维护性着想。
表现和结构分离
意思就是不要再html
中使用内嵌样式<div style="backgroud-color: #ff8a01"></div>
这是一个bad case,因为这会给后续维护带来不便,为什么呢?因为假如这是一个很多地方都用到的样式,那么后续如果相统一变更一些样式的时候需要单独找到这一行,而且在html中夹杂css代码的整体美感也会打折扣。
行为和表现分离
尽量不要用Javascript去控制元素的样式,这会导致用户在修改的时候,通过样式表无法找到对应的属性,这样的话就需要去人肉review你的Javascript代码来更改。
CSS的编程
传统的如果页面有一个统一的桔色按钮,我们都是通过class来控制,让所有的地方的button都是用这一种样式从而来统一控制样式,每当这个时候你都在想这需要一个变量啊,很遗憾CSS本身并不提供这种编程能力。
那么
边应运而生了,他让css代码的维护性也变成可能。
Javascript包管理
传统的Javascript并没有包管理的概念,所有的js文件都是放在服务器上某个文件夹,然后通过人肉引入到html之后,所以的依赖其实是认为在维护。
等包管理器以及模块化管理工具都出现了,以及AMD和CMD规范都出来了。
前端构建
前端构建的工作主要包括
- 压缩代码
- css+js+html代码压缩
- 图片压缩
- 字体压缩
- 代码编译如less,sass之类的或者typescript+coffeescript
- 合并代码
- 环境替换
主流的构建工具
gulp基于流式的构建工具,构建过程中支持效率快,同时
grunt老牌的构建工具,
fis百度fex团队出品,文档比较齐全且是中文,国内很多人在使用。
推荐使用gulp,本人写的对static项目进行的构建库static-gulp,配对的还有对web项目进行的views-gulp 这两个项目目前可用。
性能
web产品的性能集中体现在三个方面
- 网络开销方面
- 浏览器渲染DOM
- 代码执行效率
传统前端优化大部分的工作还是集中在网络开销上边,比如 Yahoo 第一条规则就是减少网络请求。而后起之秀们如Reactjs
,Angularjs2
,WebComponents
等都加入了虚拟DOM
的概念,试图让Webapp具备媲美原生native应用的体验。而代码执行效率方面有大量的最佳实践,无时无刻不在进行中,但是这个方面除非前人犯错,否则对一个产品很难一下子明显优化,另一方面硬件设备在不断变好。
大家好才是真的好
传统的对web性能优化的点还非常受用,大概分为
网络方面
减少请求个数
- 代码合并
- 图片sprite
- 字体合并
- icon少用图片,多用矢量图组合字体
减少请求过程中传输的
- 代码压缩
- 图片压缩
- 字体压缩
- 启用gzip
- 减少cookie大小
提升响应速度
- 使用CDN
- 添加expire
- 添加Etag
- Ajax缓存
- Ajax用GET
请求策略
- 组件预加载(提前加载)
- 延迟加载(纯粹的懒加载,条件加载)
在网页全部加在之前,把图片等资源通过指定src或者backgroud或者
这两个策略在做SPA的时候经常用到。
网络方面还有诸如避免404,减少DNS查询,浏览器HTTP请求并发限制等
内容和代码经验方面
- 减少DOM元素数量
- 样式表放页面顶部
- JS放页面底部
- 少用滤镜和阴影毛玻璃等效果
- 保证所有组件都小于25K
- 不要使用html缩放图片
体验方面
- 使用touch事件
- 触碰区域尽量足够大
- 尽量使用CSS3动画
- 使用GPU加速
- …
代码最佳实践
- http://coderlmn.github.io/code-standards/
- https://yuguo.us/weblog/15-best-javascript-practice/
- https://leohxj.gitbooks.io/front-end-database/content/preference/javascript-best-practise.html
天下武功唯快不破
推荐书籍和框架
- 《Javascript高级程序设计》值得多次回味的书籍。
- 《JavaScript语言精粹》
- 《Javascript DOM编程艺术》
- 《CSS权威指南(第三版)》
HTML暂时就不需要推荐书籍了,跟他最相近的就是DOM编程艺术了,其余的属性和相关的方法查看网页即可
写在最后
洋洋洒洒写了好几千字,一时间竟不知道该说点啥了,前端是一个涉及面非常广的工种,不像后端程序环境运行在比较统一的*nix系统,专注到项目本身的工程、性能、可维护等方面即可。而前端不仅仅程序执行环境多样化,工程、性能同样是要抓,更多的还要关注交互、展示等体验甚至要求对美感都有要求。更重要的是前端工程师必须要有一个追求极致的心态,不妥协否则优秀无从谈起。