web前端发展简史.docx
- 文档编号:4757187
- 上传时间:2022-12-08
- 格式:DOCX
- 页数:21
- 大小:29.53KB
web前端发展简史.docx
《web前端发展简史.docx》由会员分享,可在线阅读,更多相关《web前端发展简史.docx(21页珍藏版)》请在冰豆网上搜索。
web前端发展简史
Web前端开展简史
有人说“前端开发〞是IT界最容易被误解的岗位,这不是空穴来风。
如果你还认为前端只是从美工那里拿到切图,JS和CSS一番乱炖,难搞的功能就去网上信手拈来,CtrlC+CtrlV的话,那就正中了这份误解的下怀。
经过十几年的开展,web前端早已脱离了原来边缘化的形态,扮演了移动互联网开发链条中最关键的角色,是应用或产品能否打动用户的踹门砖。
那么什么是前端开发,其又包含了哪些内容?
前端开发的定义
从狭义的定义来看,“前端开发〞是指围绕HTML、JavaScript、CSS这样一套体系的开发技术,它的运行宿主是浏览器。
从广义的定义来看,其应该包括:
●专门为手持终端设计的类似WML这样的类HTML语言,以及类似WMLScript的类JavaScript语言。
●VML和SVG等基于XML的描述图形的语言。
●附属于XML体系的XML,XPath,DTD等技术。
●用于支撑后端的ASP,JSP,ASP.net,PHP,Nodejs等语言或者技术。
●被第三方程序打包的一种类似浏览器的宿主环境,比方AdobeAIR和使用HyBird方式的一些开发技术,如PhoneGap。
●AdobeFlash,Flex,MicrosoftSilverlight,JavaApplet,JavaFx等RIA开发技术。
本文主要从“web前端〞,也即狭义前端的角度出发,以人类科技进步划时代的方式,将前端开发划分为几个重要的时代,带着大家领略一下前端这十几年来的开展历程。
石器时代
最早期的Web界面根本都是在互联网上使用,人们浏览某些内容,填写几个表单并且提交。
当时的界面以浏览为主,根本都是HTML代码,我们来看一个最简单的HTML文件:
主标题
段落内容
为了执行一些动作或进行一定的业务处理,有时候会穿插一些JavaScript,如作为客户端校验这样的根底功能。
代码的组织比拟简单,而且CSS的运用也是比拟少的。
譬如:
下面这个文档将带有一段JavaScript代码,用于拼接两个输入框中的字符串,并且弹出窗口显示。
functiongreet(){
varfirstName=document.getElementById("firstNameInput").value;
varlastName=document.getElementById("lastNameInput").value;
alert("Hello,"+firstName+"."+lastName);
}
由于静态界面不能实现保存数据等功能,出现了很多效劳端技术,早期的有CGI〔CommonGatewayInterface,多数用C语言或者Perl实现的〕,ASP〔使用VBScript或者JScript〕,JSP〔使用Java〕,PHP等等,Python和Ruby等语言也常被用于这类用途。
有了这类技术,在HTML中就可以使用表单的post功能提交数据了,比方:
FirstName:
LastName:
在这个阶段,由于客户端和效劳端的职责未作明确的划分,比方生成一个字符串,可以由前端的JavaScript做,也可以由效劳端语言做。
所以通常在一个界面里,会有两种语言混杂在一起,用<%和%>标记的局部会在效劳端执行,输出结果,甚至经常有把数据库连接的代码跟页面代码混杂在一起的情况,给维护带来了很大的问题。
Helloworld!
<%response.write("Helloworldfromserver!
")%>
青铜时代
青铜时代的典型标志是出现了组件化的萌芽,着眼点主要在文件的划分上。
后端组件化比拟常见的做法是,把某一类后端功能单独做成片段,然后其他需要的地方来include进来,典型的有:
ASP里面数据库连接的地方,把数据源连接的局部写成conn.asp,然后其他每个需要操作数据库的asp文件包含它。
浏览器端那么通常针对JavaScript脚本文件,把某一类的Javascript代码写到单独的js文件中,界面根据需要,引用不同的js文件;针对界面组件,那么通常利用frameset和iframe这两个标签。
某一大块有独立功能的界面写到一个HTML文件,然后在主界面里面把它当作一个frame来载入,一般的B/S系统集成菜单的方式都是这样的。
是不是觉得很熟悉?
对的,现在大多公司的内部系统正是这个时代的产物。
此外,还出现了一些基于特定浏览器的客户端组件技术,比方IE浏览器的HTC〔HTMLComponent〕。
这种技术最初是为了对已有的常用元素附加行为的,后来有些场合也用它来实现控件。
微软ASP.NET的一些版本里,使用这种技术提供了树形列表,日历,选项卡等功能。
HTC的优点是允许用户自行扩展HTML标签,可以在自己的命名空间里定义元素,然后,使用HTML,JavaScript和CSS来实现它的布局、行为和观感。
这种技术因为是微软的私有技术,所以逐渐变得不那么流行。
Firefox浏览器布其后尘,也推出过一种叫XUL的技术,也同样没有流行起来。
铁器时代
这个时代的彗星是Ajax的出现以及JS根底框架的兴起。
AJAX
AJAX其实是一系列已有技术的组合,早在这个名词出现之前,这些技术的使用就已经比拟广泛了,GMail因为恰当地应用了这些技术,获得了很好的用户体验。
由于Ajax的出现,规模更大,效果更好的Web程序逐渐出现,在这些程序中,JavaScript代码的数量迅速增加。
出于代码组织的需要,“JavaScript框架〞这个概念逐步形成,当时的主流是Prototype和Mootools,两者各有千秋,提供了各自方式的面向对象组织思路。
JavaScript根底框架
Prototype框架主要是为JavaScript代码提供了一种组织方式,对一些原生的JavaScript类型提供了一些扩展,比方数组、字符串,又额外提供了一些实用的数据结构,如:
枚举,Hash等,除此之外,还对dom操作,事件,表单和Ajax做了一些封装。
Mootools框架的思路跟Prototype很接近,它对JavaScript类型扩展的方式别具一格,所以在这类框架中,经常被称作“最优雅的〞对象扩展体系。
从这两个框架的所提供的功能来看,它们的定位是核心库,在使用的时候一般需要配合一些外围的库来完成。
倚天不出,谁与争锋?
除以上两者以外,还有YUI,jQuery等,JavaScript根底框架在这个时代算得上是百花齐放,但是时间已经证明,真正的王者是jQuery。
jQuery与其他的根底框架都有所不同,它着眼于简化DOM相关的代码。
例如:
●DOM的选取
jQuery提供了一系列选择器用于选取界面元素,在其他一些框架中也有类似功能,但一般没有它简洁而强大。
$("*")//选取所有元素
$("#lastname")//选取id为lastname的元素
$(".intro")//选取所有class="intro"的元素
$("p")//选取所有<p>元素
$(".intro.demo")//选取所有class="intro"且class="demo"的元素
●链式表达式
在jQuery中,可以使用链式表达式来连续操作DOM,如果不使用链式表达式,可能需要这么写:
varneat=$("p.neat");
neat.addClass("ohmy");
neat.show("slow");
但是有了链式表达式,一行代码就可以搞定:
$("p.neat").addClass("ohmy").show("slow");
除此之外,jQuery还提供了一些动画方面的特效代码,也有大量的外围库,比方jQueryUI这样的控件库,jQuerymobile这样的移动开发库等。
农业时代
这个时代的标志性事件是模块加载标准〔AMD以及CMD〕的出现。
铁器时代出现的根底框架提供了代码的组织能力,但是未能提供代码的动态加载能力。
动态加载JavaScript为什么重要呢?
因为随着Ajax的普及,jQuery等辅助库的出现,Web上可以做很复杂的功能,因此,单页面应用程序〔SPA,SinglePageApplication〕也逐渐多了起来。
单个的界面想要做很多功能,需要写的代码是会比拟多的,但是,并非所有的功能都需要在界面加载的时候就全部引入,如果能够在需要的时候才加载那些代码,就把加载的压力分担了,在这个背景下,出现了一些用于动态加载JavaScript的框架,也出现了一些定义这类可被动态加载代码的标准。
AMD
在这些框架里,知名度最高的是RequireJS,遵循了AMD〔AsynchronousModuleDefinition〕的标准。
比方下面这段,定义了一个动态的匿名模块,它依赖math模块:
define(["math"],function(math){
return{
addTen:
function(x){
returnmath.add(x,10);
}
};
});
假设上面的代码存放于adder.js中,当需要使用这个模块的时候,通过如下代码来引入adder:
require(["adder"],function(adder){
//使用这个adder
});
RequireJS除了提供异步加载方式,也可以使用同步方式加载模块代码。
AMD标准除了使用在前端浏览器环境中,也可以运行于NodeJS等效劳端环境,但是NodeJS内置的模块机制是基于CMD标准定义的。
CMD
值得一提的是,在浏览器端,除了RequireJS以外,国内的牛人淘宝玉伯开发了SeaJS异步模块加载器,其遵循CMD标准,目前已经有超过300家大型web应用或站点采用,SeaJS同样简单易学:
//所有模块都通过define来定义
define(function(require,exports,module){
//通过require引入依赖
var$=require('jquery');
varSpinning=require('./spinning');
//通过exports对外提供接口
exports.doSomething=...
//或者通过module.exports提供整个接口
module.exports=...
});
工业时代
“这是一个最好的时代,也是一个最坏的时代。
〞前端自动化和MV*框架真正让前端迎来了春天,但是这个时代框架插件众多、体系繁复,让前端新手无所适从。
在这个时代,Web端功能日益复杂,人们不得不开始考虑这样一些问题:
●如何更好地模块化开发
●业务数据如何组织
●界面和业务数据之间通过何种方式进行交互
在这种背景下,前端MVC、MVP、MVVM框架如雨后春笋,我们暂且把这些框架都统称为MV*框架。
这些框架的出现,正是为了解决上述这些问题,具体的实现思路各有不同,主流的有Backbone,AngularJS,Ember三大剑客,本文主要选用Backbone和AngularJS来讲述以下场景。
数据模型
在这些MV*框架里,定义数据模型的方式与以往有些差异,主要在于数据的get和set更加有意义了,比方说,可以把某个实体的get和set绑定到RESTful的效劳上,这样,对某个实体的读写可以更新到数据库中。
另外一个特点是,它们一般都提供一个事件,用于监控数据的变化,这个机制使得数据绑定成为可能。
在一些框架中,数据模型需要在原生的JavaScript类型上做一层封装,比方Backbone的方式是这样:
varTodo=Backbone.Model.extend({
//Defaultattributesforthetodoitem.
defaults:
function(){
return{
title:
"emptytodo...",
order:
Todos.nextOrder(),
done:
false
};
},
//Ensurethateachtodocreatedhas`title`.
initialize:
function(){
if(!
this.get("title")){
this.set({
"title":
this.defaults().title
});
}
},
//Togglethe'done'stateofthistodoitem.
toggle:
function(){
this.save({
done:
!
this.get("done")
});
}
});
上述例子中,defaults方法用于提供模型的默认值,initialize方法用于做一些初始化工作,这两个都是约定的方法,toggle是自定义的,用于保存todo的选中状态。
除了对象,Backbone也支持集合类型,集合类型在定义的时候要通过model属性指定其中的元素类型。
//Thecollectionoftodosisbackedby*localStorage*insteadofaremoteserver.
varTodoList=Backbone.Collection.extend({
//Referencetothiscollection'smodel.
model:
Todo,
//Saveallofthetodoitemsunderthe'"todos-backbone"'namespace.
localStorage:
newBackbone.LocalStorage("todos-backbone"),
//Filterdownthelistofalltodoitemsthatarefinished.
done:
function(){
returnthis.filter(function(todo){
returntodo.get('done');
});
},
//Filterdownthelisttoonlytodoitemsthatarestillnotfinished.
remaining:
function(){
returnthis.without.apply(this,this.done());
},
//WekeeptheTodosinsequentialorder,despitebeingsavedbyunordered
//GUIDinthedatabase.Thisgeneratesthenextordernumberfornewitems.
nextOrder:
function(){
if(!
this.length)
return1;
returnthis.last().get('order')+1;
},
//Todosaresortedbytheiroriginalinsertionorder.
comparator:
function(todo){
returntodo.get('order');
}
});
数据模型也可以包含一些方法,比方自身的校验,或者跟后端的通讯、数据的存取等等,在上面两个例子中,也都有表达。
AngularJS的模型定义方式与Backbone不同,可以不需要经过一层封装,直接使用原生的JavaScript简单数据、对象、数组,相对来说比拟简便。
控制器
在Backbone中,是没有独立的控制器的,它的一些控制的职责都放在了视图里,所以其实这是一种MVP〔ModelViewPresentation〕模式,而AngularJS有很清晰的控制器层。
还是以这个todo为例,在AngularJS中,会有一些约定的注入,比方$scope,它是控制器、模型和视图之间的桥梁。
在控制器定义的时候,将$scope作为参数,然后,就可以在控制器里面为它添加模型的支持。
functionTodoCtrl($scope){
$scope.todos=[{
text:
'learnangular',
done:
true
},{
text:
'buildanangularapp',
done:
false
}];
$scope.addTodo=function(){
$scope.todos.push({
text:
$scope.todoText,
done:
false
});
$scope.todoText='';
};
$scope.remaining=function(){
varcount=0;
angular.forEach($scope.todos,function(todo){
count+=todo.done?
0:
1;
});
returncount;
};
$scope.archive=function(){
varoldTodos=$scope.todos;
$scope.todos=[];
angular.forEach(oldTodos,function(todo){
if(!
todo.done)
$scope.todos.push(todo);
});
};
}
本例中为$scope添加了todos这个数组,addTodo,remaining和archive三个方法,然后,可以在视图中对他们进行绑定。
视图
在这些主流的MV*框架中,一般都提供了定义视图的功能。
在Backbone中,是这样定义视图的:
//TheDOMelementforatodoitem...
varTodoView=Backbone.View.extend({
//...isalisttag.
tagName:
"li",
//Cachethetemplatefunctionforasingleitem.
template:
_.template($('#item-template').html()),
//TheDOMeventsspecifictoanitem.
events:
{
"click.toggle":
"toggleDone",
"dblclick.view":
"edit",
"clicka.destroy":
"clear",
"keypress.edit":
"updateOnEnter",
"blur.edit":
"close"
},
//TheTodoViewlistensforchangestoitsmodel,re-rendering.Sincethere's
//aone-to-onecorrespondencebetweena**Todo**anda**TodoView**inthis
//app,wesetadirectreferenceonthemodelforconvenience.
initialize:
function(){
this.listenTo(this.model,'change',this.render);
this.listenTo(this.model,'destroy',this.remove);
},
//Re-renderthetitlesofthetodoitem.
render:
function(){
this.$el.html(this.template(this.model.toJSON()));
this.$el.toggleClass('done',this.model.get('done'));
this.input=this.$('.edit');
returnthis;
},
//......
//Removetheitem,destroythemodel.
clear:
function(){
this.model.destroy();
}
});
上面这个例子是一个典型的“部件〞视图,它对于界面上的已有元素没有依赖。
也有那么一些视图,需要依赖于界面上的已有元素,比方下面这个,它通过el属性,指定了HTML中id为todoapp的元素,并且还在initialize方法中引用了另外一些元素,通常,需要直接放置到界面的顶层试图会采用这种方式,而“部件〞视图一般由主视图来创立、布局。
//Ouroverall**AppView**isthetop-levelpieceofUI.
varAppView=Backbone.View.extend({
//Insteadofgeneratinganewelement,bindtotheexistingskeletonof
//theAppalreadypresentintheHTML.
el:
$("#todoapp"),
//Ourtemplateforthelineofstatisticsatthebottomoftheapp.
statsTemplate:
_.template($('#stats-template').html()),
//Delegatedeventsforcreatingnewitems,andclearingcompletedones.
events:
{
"keypress#new-todo":
"createOnEnter",
"click#clear-completed":
"clearCompleted",
"click#toggle-all":
"toggleAllComplet
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- web 前端 发展 简史