这里先讲一个需求,有一个别系须要实现一个模块,用户管理,模块的功能很大略,便是查询、删除。
基于这个需求,熏风哥会利用几代不同的前端技能分别予以实现,让读者感想熏染个中的变革和奥秘。
界面大概是这个样子。

非常老土,非常大略,这都不是重点,重点是能解释问题就行。

第一代:单文件模式

jsp能放前端吗前端技巧及开辟模式的演进带你懂得前端技巧的宿世此生 Webpack

作甚单文件模式,阐明一下便是一个模块所有的代码都集中在一个文件中,实现上面说的需求,目录大概是这个样子的。

然后看「user.html」详细里面的内容。

&lt;!DOCTYPE html><html lang=\"大众en\"大众><head> <meta charset=\"大众UTF-8\公众> <title>用户管理</title> <style> .bg{ background-image: url(\公众../img/bg.jpg\"大众); } .text-center{ text-align: center; } .condition-box{ margin-bottom: 10px; } table{ width:90%; } .table-header{ background-color: #dddddd; } .delete{ text-decoration: none; } </style></head><body class=\公众bg\"大众> <div class=\"大众text-center\公众> <h3>用户添加</h3> </div> <div class=\"大众text-center\"大众> <!-- 查询条件 --> <div class=\"大众condition-box\公众> 用户姓名:<input id=\"大众name\"大众 type=\公众text\公众> <button id=\公众search\公众 onclick=\"大众search()\"大众>查询</button> </div> <!-- 用户列表 --> <table align=\公众center\公众 border=\"大众1\"大众 cellpadding=\公众0\公众 cellspacing=\"大众0\"大众> <tr class=\公众table-header\"大众> <td>id</td> <td>姓名</td> <td>性别</td> <td>年事</td> <td>联系电话</td> <td>创建韶光</td> <td>操作</td> </tr> <tr> <td>1</td> <td>张三</td> <td>男</td> <td>22</td> <td>123456789</td> <td>2018-08-08</td> <td><a class=\"大众delete\"大众 href=\公众javascript:void(0);\"大众 onclick=\公众deleteUser(this,1)\"大众>删除</a></td> </tr> <tr id=\公众5\公众> <td>2</td> <td>李四</td> <td>女</td> <td>18</td> <td>987654321</td> <td>2018-07-18</td> <td><a class=\"大众delete\"大众 href=\"大众javascript:void(0);\公众 onclick=\公众deleteUser(this,2)\"大众>删除</a></td> </tr> </table> </div></body><script src=\公众../js/jquery-2.1.1.min.js\"大众></script><script type=\"大众text/javascript\"大众> function deleteUser(e,id){ // 调用掌握器删除方法 // 后端逻辑是,掌握器调用删除业务方法后,返回到user.html页面,即当前页面 location.href = \"大众/userDelete?id=\公众 + id; } function search(){ var name = $(\公众#name\"大众).val(); // 调用掌握器搜索方法 // 后端逻辑是,掌握器调用删除业务方法后,返回到user.html页面,即当前页面 location.href = \"大众/userList?name=\"大众 + name; }</script></html>

我们会创造,所有的样式声明,js代码以及html代码都会集中在一个文件中。
这样一个功能如果较为繁芜,页面代码看起来会非常繁芜,久而久之就会变得不易掩护。

当然有一些优化的办法。
便是目录划分更友好一些,剥离css和js脚本,采取外部引入的办法,这种办法也是后来采取的比较多的办法,像下面这样,看起来就清爽多了。

<!DOCTYPE html><html lang=\公众en\公众><head> <meta charset=\"大众UTF-8\"大众> <title>用户管理</title> <!-- 用户样式 --> <link type=\公众text/css\公众 rel=\公众stylesheet\公众 href=\"大众../css/user.css\公众 /></head><body class=\"大众bg\公众> <div class=\"大众text-center\"大众> <h3>用户添加</h3> </div> <div class=\公众text-center\公众> <!-- 查询条件 --> <div class=\公众condition-box\"大众> 用户姓名:<input id=\"大众name\公众 type=\"大众text\"大众> <button id=\公众search\"大众 onclick=\"大众search()\"大众>查询</button> </div> <!-- 用户列表 --> <table align=\"大众center\"大众 border=\"大众1\"大众 cellpadding=\"大众0\"大众 cellspacing=\"大众0\"大众> <tr class=\公众table-header\"大众> <td>id</td> <td>姓名</td> <td>性别</td> <td>年事</td> <td>联系电话</td> <td>创建韶光</td> <td>操作</td> </tr> <tr> <td>1</td> <td>张三</td> <td>男</td> <td>22</td> <td>123456789</td> <td>2018-08-08</td> <td><a class=\"大众delete\"大众 href=\"大众javascript:void(0);\公众 onclick=\"大众deleteUser(this,1)\"大众>删除</a></td> </tr> <tr id=\"大众5\"大众> <td>2</td> <td>李四</td> <td>女</td> <td>18</td> <td>987654321</td> <td>2018-07-18</td> <td><a class=\"大众delete\公众 href=\"大众javascript:void(0);\"大众 onclick=\公众deleteUser(this,2)\公众>删除</a></td> </tr> </table> </div></body><script src=\"大众../js/jquery-2.1.1.min.js\公众></script><script src=\"大众../js/user.js\"大众></script></html>

以上两种形式,实质上没有什么差异,以是就放在一起解释,以上办法的优点便是大略粗暴,代码开拓的速率较高。

与后真个交互都是后端建立一个Controller或Servlet 这么一个掌握器,要求到达掌握器,处理完逻辑,然后掌握器中跳转到一个页面,页面进行数据渲染展示。
每次交互过程目标跳转页面的内容都须要全部刷新加载,纵然多次交互跳转的是同一个页面。

这种有什么问题吗?我们来看一下,在用户管理中的用户列表页我们有个查询功能,我们输入一个姓名,点击查询,如果采取上面的办法,想想看,点一下查询,到掌握器,后端实行完SQL拿到数据后,又会跳转到用户列表页,我点5次查询,全体列表页就会加载5次,而且全体页面只有用户表格这个部分是变革的,其他部分是没有变革的,这样资源(背景图、jquery库、css)每次便是重复加载,带来的问题便是一、体验不好,二、资源重复加载,给web做事器带来一定的要求压力。

这里补充多说一点内容,便是jsp这个东西,虽然现在用的不多,但还是说一下,之前熏风哥口试问过很多口试者,前端都会什么技能,口试者张口就来,jsp .... 什么什么,这里熏风哥想说,jsp不属于前端技能,为什么 ?

由于jsp本身实行前是须要编译的,编程成class文件,是在做事端实行的,而真正的前端技能一定是在浏览器或干系前端技能实行引擎上(类Chrome V8)阐明实行的。
像jsp里写的css、html、js这些东西属于前端技能的范畴,这些都是由浏览器阐明实行的,很多人被jsp这种表象迷惑了,看到jsp里面写的都是页面展现干系的代码,认为jsp便是前端技能。

回到上面的问题,我们再来看如何办理上面的问题,这便是第二代技能。

第一代代表技能:html、css、javascript、jquery

第二代:SPA

单页Web运用(single page web application,SPA),简称SPA,由于ajax技能的兴起,使得局部加载变得盛行,单页运用页得到了广大开拓者和用户的青睐。

大略理解单页运用,便是全体运用加载都在一个页面当中,做的便是局部更换,比如点击一个菜单,系统全体头部,底部,菜单部分都不变革,只变革中间区域的模块内容。

再比如上面说到的查询需求,点击查询后,用户列表整体内容不变,通过ajax要求,数据回来后,通过js仅仅修正表格部分的数据内容。

这样就办理了上面说的一、体验的问题,二、资源重复加载的问题。

大部分情形下,我们只须要在整体页面中引入须要的所有资源,模块中就不须要在引入资源,只处理模块自身的内容和业务即可。

这种办法与后真个交互都是便是建立一个Controller或Servlet 这么一个掌握器,要求到达掌握器,处理完逻辑,然后返回局部页面片段或者json数据,页面进行渲染展示。
每次交互过程只刷新局部,整体页面不做刷新。

这里的数据渲染,一种是通过jquery或js的办法,字符串拼接,然后设置到对应的dom中,像这样。

页面Dom

<!-- 用户列表 --><table id=\"大众userList\公众 align=\"大众center\"大众 border=\公众1\公众 cellpadding=\"大众0\"大众 cellspacing=\公众0\"大众></table>

Ajax加载渲染

function search(){ var name = $(\公众#name\公众).val(); // 调用掌握器搜索方法,返回json数据 $.get('/userList?name=' + name,{},function(data){ var userList = data.userList; var row = ''; row += '<tr class=\"大众table-header\"大众>'; row += ' <td>id</td>'; row += ' <td>姓名</td>'; row += ' <td>性别</td>'; row += ' <td>年事</td>'; row += ' <td>联系电话</td>'; row += ' <td>创建韶光</td>'; row += ' <td>操作</td> '; row += ' </tr>'; for(var i = 0 ; i < userList.length; i++){ var user = userList[i]; row += '<tr>'; row += ' <td>' + user.id + '</td>'; row += ' <td>' + user.name +'</td>'; row += ' <td>' + user.sex + '</td>'; row += ' <td>' + user.age +' '</td>'; row += ' <td>' + user.phone + '</td>'; row += ' <td>' + user.createDate + '</td>'; row += ' <td><a class=\"大众delete\公众 href=\"大众javascript:void(0);\公众 onclick=\公众deleteUser(this,1)\公众>删除</a></td>'; row += '</tr>'; } $(\"大众#userList\"大众).html(row); },'json');}

另一种办法模板引擎

<!-- 定义模板 --><script id=\"大众userListTpl\"大众 type=\"大众text/html\"大众> <tr class=\公众table-header\公众> <td>id</td> <td>姓名</td> <td>性别</td> <td>年事</td> <td>联系电话</td> <td>创建韶光</td> <td>操作</td> </tr> {{each list as user i}} <tr> <td>{{user.id}}</td> <td>{{user.name}}</td> <td>{{user.sex}}</td> <td>{{user.age}}</td> <td>{{user.phone}}</td> <td>{{user.createDate}}</td> <td><a class=\公众delete\公众 href=\公众javascript:void(0);\"大众 onclick=\"大众deleteUser(this,{{user.id}})\"大众>删除</a></td> </tr> {{/each}}</script>

利用

function search(){ var name = $(\"大众#name\公众).val(); // 调用掌握器搜索方法,返回json数据 $.get('/userList?name=' + name,{},function(data){ var userList = data.userList; var html = template('userListTpl', userList); document.getElementById('userList').innerHTML = html; },'json');}

繁芜页面建议利用模板引擎的办法,代码构造更清晰,更随意马虎掩护。

这种办法的优点,显而易见可以办理第一代技能的问题,那它有问题吗 ? 显然有,一、毁坏浏览器的退却撤退、提高功能(异步加载,地址栏不发生变革,所以是无法退却撤退提高),当然有一些办理办法,下面再说 ,二、SEO不友好。

以是比较常见的做法是,后端管理系统一样平常会整体采取SPA办法,包括现在的很多系统也是,有强SEO需求的仍旧会采取上面第一代办法,然后结合一点点ajax的内容,这便是第二代前真个开拓模式。

局部加载的实现办法:

1、ajax 局部要求加载

2、前端hash路由,也是现在的主流办法,这种办法可以办理浏览器的提高、退却撤退问题,通过地址栏hash值的变革,但历史页面状态无法保持,回退的页面数据仍须要重新加载、初始化,但随着前端数据持久化的逐步盛行,回退历史页面状态的保存也逐渐不是问题。

3、iframe、frameset 也可以实现,但是不建议。

第二代代表技能:ajax、artTemplate

第三代:模块化

随着系统功能越来越多,代码文件也越来越多,相互之间的依赖调用关系变得非常繁芜。
这时候两个问题变得十分突出,一是js中的命名冲突问题,二是资源的加载问题。

先看js的命名问题,看一个大略的js文件

function deleteUser(e,id){ // 调用掌握器删除方法 // 后端逻辑是,掌握器调用删除业务方法后,返回到user.html页面,即当前页面 location.href = \公众/userDelete?id=\公众 + id;}function search(){ var name = $(\"大众#name\"大众).val(); // 调用掌握器搜索方法 // 后端逻辑是,掌握器调用删除业务方法后,返回到user.html页面,即当前页面 location.href = \公众/userList?name=\"大众 + name;}

这是上面user模块的js文件,user.js,有两个方法,这个js会被在user.html中引入

但是一个轻微繁芜点的系统或功能,不可能只引入这么几个外部js,常常有几十个乃至上百个js须要引入,还有我们自己封装的组件,通用方法等。
这样的大量引入,如果都是user.js 这种全局命名形式,很随意马虎就发生命名上的冲突,便是你定了一个search函数,另一个开拓者或者插件里面也定义了一个search方法,这就会带来莫名奇妙的BUG和问题。

在来看一下资源加载的问题,同样是用户模块,引入了比如说50个js文件,但是有40个文件是点击搜索时才须要利用,加载列表时不须要,如果每次加载列表都去加载全部的js文件,那将须要多大的带宽资源和带来多大的要求压力(这里先不考虑CDN等优化办法)。
能不能让资源在真正须要的时候再去加载 ?

那么前端模块化技能便是重点办理以上两个问题。
我们的代码构培养会变成这个样子。

定义模块

define(function(require, exports, module) { var $ = require('jquery'); var tpl = require('template'); var user = {} // 初始化 user.init = function(){ user.deleteUser(); user.search(); } user.deleteUser = function() { $(\"大众.delete\公众).click(function(){ $.get('/userDelete?id=' + id,{},function(data){ user.reloadData(); },'json'); }); }; user.search = function() { $(\公众#search\"大众).click(function () { var name = $(\"大众#name\公众).val(); // 调用掌握器搜索方法,返回json数据 $.get('/userList?name=' + name,{},function(data){ var userList = data.userList; var html = template('userListTpl', userList); document.getElementById('userList').innerHTML = html; },'json'); }); }; exports user;});

利用模块

完全页面代码

<!DOCTYPE html><html lang=\公众en\"大众><head> <meta charset=\公众UTF-8\公众> <title>用户管理</title> <!-- 用户样式 --> <link type=\公众text/css\"大众 rel=\"大众stylesheet\"大众 href=\"大众../css/user.css\"大众 /></head><body class=\"大众bg\"大众> <div class=\公众text-center\"大众> <h3>用户添加</h3> </div> <div class=\"大众text-center\公众> <!-- 查询条件 --> <div class=\"大众condition-box\"大众> 用户姓名:<input id=\"大众name\"大众 type=\"大众text\"大众> <button id=\公众search\"大众>查询</button> </div> <!-- 用户列表 --> <table id=\"大众userList\"大众 align=\"大众center\"大众 border=\公众1\"大众 cellpadding=\公众0\公众 cellspacing=\公众0\公众> </table> </div></body><script src=\公众../js/jquery-2.1.1.min.js\公众></script><script src=\"大众../js/sea.js\"大众></script><script> seajs.use(['./js/user', 'jquery'], function(user, $) { user.init(); });</script><!-- 定义模板 --><script id=\公众userListTpl\"大众 type=\公众text/html\"大众> <tr class=\公众table-header\"大众> <td>id</td> <td>姓名</td> <td>性别</td> <td>年事</td> <td>联系电话</td> <td>创建韶光</td> <td>操作</td> </tr> {{each list as user i}} <tr> <td>{{user.id}}</td> <td>{{user.name}}</td> <td>{{user.sex}}</td> <td>{{user.age}}</td> <td>{{user.phone}}</td> <td>{{user.createDate}}</td> <td><a class=\"大众delete\"大众 href=\"大众javascript:void(0);\"大众 onclick=\"大众deleteUser(this,{{user.id}})\公众>删除</a></td> </tr> {{/each}}</script></html>

第三代代表技能:seajs、requirejs、kissy

第四代:前端MVC

MVC开始是存在于桌面程序中的,作者意图办理桌面端GUI的开拓耦合问题,后来被结合后端技能,整体又组成了一个MVC模式以及纯前真个MVC模式。
但思想是同等的,便是包含 掌握器、模型、视图三个部分。

当一个别系的模块越来越多之后,模块内部的代码掩护便是个大问题,为了让模块代码变得清晰,更易掩护,相互之间没有紧密的耦合关系,技能先驱者们想了很多办理办法,MVC便是个中一种,像还有MVP模式,以及后面将提到的MVVM。

第四代代表技能:Extjs、backbone.js

Extjs不是UI框架吗?,实际上它不但有UI控件,Extjs4开始有了MVC模式,熏风哥之前所在公司利用的便是Extjs,充分利用了个中的MVC模式。
虽说现在收费了,用的人不怎么多了,但在当年还是有一席之地的。

如何将一个前端模块利用MVC的办法就行构建,以Extjs的为例构建用户管理便是如下。

UserController 注册用户管理的交互事宜和方法定义UserModel 数据模型,配置Store利用UserStore 异步要求,卖力交互后台数据UserGrid 表格视图,卖力展示Store要求回来的数据,绑定渲染

将各层分离,使代码整体构造更清晰,耦合度更低,可掩护性更强,觉得很繁芜?没错,这样本来一个大略的模块开拓起来就会变得看起来繁芜,须要分离,须要遵照一定的规范,但长远看这么做是有好处的,代码的可掩护性和可读性会有不小的提升。

第五代: MVVM

这里就不在提MVP这种模式了,没有太盛行起来,直接看MVVM模式。
拆解一下,实际上是 M-V-VM(即模型-视图-视图模型)三个部分 ,M和V还是原来的M和V,唯一不同的是VM这个东西,通过VM(ViewModel)完备将M和V分离,是M和V的连接纽带。
实现了双向数据绑定,大略理解一下便是,模型发生变革,视图会自动更新,视图数据发生变革,模型会自动感知也发生变革,当然这是直不雅观的利用感想熏染,底层是有比较繁芜的实现逻辑支撑。

对开拓者来说,就可以从以前的dom操作中解放出来,想想以前的操作模式,吸收到后台的数据,jquery开干,选择dom,拿到数据,拼接字符串,添补到dom中。
视图数据变革了,js 每次须要主动重新取值,有了MVVM这都不须要了,做好了双向绑定。
只要将数据绑定到M,V自动更新,V层表单或其他视图组件状态发生变革,M自动更新,没有了中间的DOM操作和掌握。
统统都变得大略。
相互之间也没有耦合,自己干自己的事情。

比较前端模板引擎,它又少了模板定义这个部分,也是大略不少,省了不少事情。

利用MVVM后,代码会变成这样。

定义

new Vue({ el: '#app', data: { name:'', userList:[] }, methods:{ deleteUser:function(){ }, search:function(){ var _this = this; $.get('/userList?name=' + name,{},function(data){ var userList = data.userList; // 赋值,视图自动更新 _this.userList = userList; },'json'); } }})

利用

<!DOCTYPE html><html lang=\公众en\"大众><head> <meta charset=\"大众UTF-8\公众> <title>用户管理</title> <!-- 用户样式 --> <link type=\"大众text/css\"大众 rel=\"大众stylesheet\公众 href=\"大众../css/user.css\公众 /></head><body class=\"大众bg\"大众> <div class=\公众text-center\"大众> <h3>用户添加</h3> </div> <div class=\公众text-center\公众> <!-- 查询条件 --> <div class=\公众condition-box\"大众> 用户姓名:<input v-model=\公众name\"大众 type=\"大众text\公众> <button v-on:click=\"大众search()\公众>查询</button> </div> <!-- 用户列表 --> <table id=\公众userList\公众 align=\"大众center\"大众 border=\"大众1\"大众 cellpadding=\"大众0\"大众 cellspacing=\"大众0\公众> <tr class=\公众table-header\"大众> <td>id</td> <td>姓名</td> <td>性别</td> <td>年事</td> <td>联系电话</td> <td>创建韶光</td> <td>操作</td> </tr> <tr v-for=\"大众user in userList\"大众> <td>{{user.id}}</td> <td>{{user.name}}</td> <td>{{user.sex}}</td> <td>{{user.age}}</td> <td>{{user.phone}}</td> <td>{{user.createDate}}</td> <td><a class=\"大众delete\"大众 href=\公众javascript:void(0);\"大众 onclick=\"大众deleteUser(this,{{user.id}})\"大众>删除</a></td> </tr> </table> </div></body><script src=\"大众../js/jquery-2.1.1.min.js\"大众></script><script src=\公众../js/vue.js\"大众></script><script src=\"大众../js/user.js\"大众></script></html>

第五代代表技能: Angularjs、Vue

第六代:nodejs 为根本的大前端

关于nodejs引用网上的一句阐明 “Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
”,大略的说 Node.js 便是运行在做事真个 JavaScript。
What ?js 能运行在做事端了 ?对的。

先说下为什么涌现了nodejs这个东西,nodejs作者的初衷是设计一个高性能的Web做事器,让前端开拓职员通过javascript也可以进行做事真个开拓,不可否认,事宜驱动 + 非壅塞 + Chrome v8 引擎,nodejs的性能表现确实精良。

发展至今,纯利用nodejs作为后端开拓的企业,显然不多。
但是却在其余两个方面大放异彩。

一、开拓时,冲破前后端协作的壁垒,纵然在后端没有按时供应接口的情形下,前端依旧可以按照自己的节奏完成开拓任务。
是大前端开拓的基石。

二、生产环境中,借助其高性能,更多作为一层网关或代理,转发要求到真正的后端做事上。

随着nodejs的盛行,前端变得更加独立,产生了以vue和react为代表的两大阵营,结合其他插件模块,前端也有模块依赖了,也可以管理依赖了,前端也须要打包编译了,对,没错,前端须要学的东西也越来越多了,体系也越来越弘大了,这是真正完备的前后端分离,大前端来了。

第六代代表技能:nodejs、Vue、React、Webpack

通过以上几代技能的演进,前端技能发展一贯在朝着解耦、可掩护、高性能的目标不懈的努力着,致力于良好的用户体验,未来还会涌现哪些NB的技能,让我们拭目以待吧。

熏风哥对以上几种办法都经历过,体验过,现在每种办法肯定都有企业在用或者组合利用,技能这个东西本身便是为办理问题而存在的,不能为了技能而技能,为了追求潮流而不管不顾,立足企业的痛点和需求,结合企业的实际情形,选择得当的技能办理问题才是王道。

来源:风象南