我1998年开始学习Java,那时候学校里老师可能听说过Java,但是同学基本上都不知道Java。校图书馆进第一批Java的书,后面的借阅记录上都是我的名字。当时几乎所有男同学都在学C++、PB、VB、Delphi,女生很多在学ASP。所以很多同学问我学的是什么,Java是干什么的。
大学毕业以后,开始用Java做的第一个实际项目是对日外包,是2001年。日方有一套很老的系统,想用Java重构一下,要求用JSP。我下班就跑去西单图书大厦,发现那里的书都还是Servlet的, 没有JSP的!
还好,当时的公司同时进行的一项业务就是代理BEA的Weblogic(BEA是三个从SUN出来的人创建的,后来被Oracle收购)。Weblogic的产品文档里包含非常全面的JSP介绍,所以起初对JSP的学习都是从Weblogic开始的。
那时候还没听说过什么Struts。自己在SUN的官网发现了WAF的文档,全称是Web Application Framework,算是最早MVC模式的介绍。这个WAF不算是框架,只是介绍了MVC模式应该是个什么样子,如何用Servlet+JSP实现MVC模式。SUN的官网提供了少量的样例代码,剩下的都是我们根据文档自己搭建和实践。
在项目的中后期(02年下半年吧),有一次坐班车,听到后面座位上两个人在说话。一个人问:你知道Struts吗?另外一个人说:不知道。问的那个人说:就是S T R U T S这几个字母,开发Java的。我偷偷记在心里,然后第二天上网查了一下(当时没有智能机,家里也没有WIFI),才算开启了Apache这扇大门。后来在ASF上又学习了Cocoon、pluto、turbine等等很多框架。
大概02年底,对日外包项目顺利完成了,我公司开始接国内的项目。第一个国内项目是东北一所大学的科研经费审批项目。记得去给人家部署和演示的时候特别有意思。我们用了半天时间在服务器上部署好,然后去给客户演示。打开浏览器,输入ip+端口,开始操作。操作了十几分钟,所有的客户没有说一个字。越演示心里越没底,不知道客户啥反应。大概又过了几分钟,客户的主任发话了:你们的软件呢?
我们的软件呢?我给你演示了半天,这不就是我们的软件吗?最后才明白,用户认为只有下载一个类似叫setup.exe或install.exe的程序,双击,然后下一步下一步,最后桌面上出现一个快捷方式,那才算是软件!在经过片刻的不可思议之后,我认为实际用户的理念总是落后于研发人员的理念,这个我很容易想明白。但后来发现,我那些学PB、Delphi的师兄弟也不是一时半会能接受B/S结构的应用算是软件的...他们认为:你不就是写个网页吗???
再后来,从03-08年,长期从事企业应用开发,主要是基于Weblogic Platform,包括Server、Integration、Portal,其中在Portal上工作的时间最多。
其中04-05年用Weblogic Portal做深圳市最大的电子政务项目,06-07年用Weblogic平台做广东省电信的3G业务平台,08-09年用Aqualogic做南方电网的SOA。
Weblogic Server中集成了Struts,没记错的话当时是1.1版本。BEA把Struts做了升级和改造,可以在Weblogic Workshop中可视化开发,就是下面这样:
其中圆形代表Action,有Begin Action,End Action,还有普通的中间节点Action。BEA把Struts的这个升级称作Java Page Flow(Java 页面流)。一组这样的图形当中包含的Action和JSP,会定义在一个扩展名是.jpf的文件中。
后来,BEA把JPF捐献给了Apache,成为ASF下的一个开源项目Apache Beehive。
Welcome to Apache Beehivebeehive.apache.org
这个项目现在已经停止更新了。
大概从06年开始,接触到了YUI,也就是Yahoo User Interface,Yahoo开源的一套前端JS组件库。从此算是开启了我的前端之路。
07-08年开始用Extjs,作者说Ext就是Extension(扩展)的意思,扩展了YUI,提供了更丰富的适合企业开发的前端组件。但这时候,Extjs还仅仅是丰富的UI组件库,算不上框架。就是在JSP生成的HTML里面嵌入Extjs的组件。
09-11年用GWT,就是Google Web Toolkits。Google当时的想法很先进,用Java开发前端UI,最终编译成JS。有点类似于现在TS编译成JS的过程,就是打算利用上Java的强类型、面向对象等特点。这时候就已经完全前后端分离了。可以说从08年之后我就再也没写过JSP,一个页面也没写过。
10年开始用Bootstrap。这时候GWT的缺点就暴露出来了,CSS非常难改。直到13年初,开始用上了Angularjs。记得当时在智联招聘上发布职位的时候搜了一下,北京市只有用友和我们公司招聘Angularjs开发。后来就从Angularjs用到React,又用回Angular4,一直到现在都以最新版本的Angular为主,企业应用和互联网应用都有开发。移动开发主要用Ionic,React Native也用过。
为什么要详细介绍我过去和JSP以及前端框架相关的开发经历呢?是因为我想表达一个观点:如果要客观公正评价JSP是否还有必要用,特别是还有必要学,需要一个真正长期用过JSP(前后端不分离)开发,也真正长期用前端框架(前后端分离)开发的人才可以。
就像我在有些知乎答案下评论的那样:
遇到这种情况,我总想起福特的名言:“如果我当年去问顾客他们想要什么,他们肯定会告诉我:‘一匹更快的马。’”
满大街跑马车的时代,福特问顾客需要什么,顾客就说需要一匹更快的马。他们不知道汽车时代会给生活带来怎样革命性的变化。
在BP机时代,大家认为有人戴BP机已经很牛了。满大街诺基亚摩托罗拉功能机的时代,大家也都觉得够用了。问他们需要什么,他们估计会回答:充一次电能不能待机一个月?能不能把自己喜欢的MP3当彩铃?
我觉得要对比评价两代产品,应该给两代产品都熟练体验过的人去判断。从功能机时代过来的人,现在iphone都已经用到第三部了,你再问他功能机够不够用。就拿一个两代产品都具有的功能(比如都可以QQ聊天)对比,你愿意回到功能机时代还是继续用智能机。
一直抱定JSP不撒手,没动力、没能力学习前端技术,没有真正理解前后端分离开发模式的人,不可能得出公正全面的评价。
在校期间或参加培训班就学习了前端框架,参加工作后就开始前后端分离的人,也无法理解老人只用JSP或用JSP+JS前端UI组件的开发模式是个怎么回事。
上面两种人,据我实际接触中了解,大部分都认为自己的开发模式是理所当然的。就像我之前描述自己刚毕业时候的经历一样。大部分客户和我的一些同学,理所当然认为双击setup.exe,然后下一步下一步才是软件。而我理所当然认为B/S架构的也是软件,只是更便于开发和操作。
过去一年多,陆陆续续在知乎上回答了一些关于JSP的问题。当然,我的回答都是建议淘汰JSP,新人小白一定不要再学JSP了。我现在集中把这些技术因素归纳一下。
一个现代主流Java Web应用,不管前端、后端、还是微服务架构,都在淘汰JSP。
其中,我认为Java服务器端主流技术还是Spring(Spring Boot + Spring MVC + Spring Cloud)。
下面三点,第一点几乎尽人皆知,第二点有一部分人清楚,第三点却很少有人意识到。
前端框架已经非常成熟和稳定,不需要JSP
前后端分离已经不是什么趋势了,而是当前B/S架构开发的主流模式。前后端分离之后,前端只负责展现和交互,后端负责核心业务逻辑。前后端通过API进行交互,并且最好符合RESTful风格。服务器端把数据返回给前端就不再关心这些数据用在哪里、如何布局、什么样式。
这个层面的原因非常容易理解,也是绝大多数讨论JSP是否还有必要学的时候里都会提到的。
服务器端的Spring MVC/WebFlux 和 Spring Boot已经开始抛弃JSP
从Spring 5开始,在原有的基于Servlet技术的Spring MVC之外增加了一个新的编程模型,就是Spring WebFlux。
Spring WebFlux是响应式非阻塞的,而且不支持Servlet API,所以也就不支持JSP!
上图左侧是Spring 5新引入的Spring WebFlux,右侧是大家熟悉的Spring MVC,两者并列,Spring同时支持。
关于这一点,可以看Stack Overflow上面来自Spring Framework和Spring Boot团队成员Brian Clozel的回答:
Spring WebFlux - no JSP support??stackoverflow.com
新的Spring WebFlux不支持JSP,那咱们不用就好了,至少Spring MVC还是支持JSP的啊。那我们继续看。
如果我们继续使用Spring Boot+Spring MVC开发,那么Spring Boot对JSP是有限制的,看官方文档怎么说的:
链接在这里:
Spring Boot Reference Guide?docs.spring.io
其中那行备注:
If possible, JSPs should be avoided. There are several known limitations when using them with embedded servlet containers.
尽可能避免用JSP。当使用嵌入式Servlet容器时,有一些已知的限制。
关于这些限制和如何继续在Spring Boot中使用JSP,可以自己查一下,知乎里就有好多文章
Spring Boot对JSP有限制,那咱们就凑合用呗,反正我是写Java的,我的发展方向是架构师,我正打算学习微服务,正在看Spring Cloud。那咱们就继续看看Spring Cloud吧。
微服务架构下更没有JSP的用武之地
首先要明白Spring Boot和Spring Cloud的关系。可以先看我的这个回答:
Spring boot与Spring cloud 是什么关系??www.zhihu.com
还是看这张图吧:
右侧绿色的部分都是Spring Cloud的组成部分,不管是API Gateway、Config Dashboard,Service Registry,还是多个MicroServices,他们都是Spring Boot应用!或者说Spring Boot是整个Spring Cloud的基石(其实也是Spring Cloud Data Flow的基石)。
哦,你明白了,因为有Spring Boot对JSP的限制,而Spring Cloud的组成部分都是Spring Boot应用,所以Spring Cloud也对JSP有限制。其实不仅仅是表面上这个原因,咱们继续分析。
如果强行继续在Spring Cloud环境中继续使用JSP,那么JSP放在哪里?有两种方案。
那怎么才算是使用Spring Cloud的正确姿势?还是看上面那幅图,这次关注左侧三个灰色的部分。IoT(物联网 Internet of Things)、Mobile(移动应用)、Browser(浏览器端),这三个也是应用啊。
我们再看一幅图:
整个Spring体系的图出来了。还是看左侧,Your App,也就是IoT(物联网 Internet of Things)、Mobile(移动应用)、Browser(浏览器端)这三类!
Browser就是前后端分离之后的前端应用,独立开发、独立部署、只和服务器端有HTTP RESTful通信。
我们看看Spring官方给出的Spring Cloud例子,链接在这里:
Spring Projects?spring.io
customers-stores-ui是前端应用,用Angularjs实现的。例子是便于学习的,不应该引入额外的太多其他技术!为什么Spring官方的例子非要用上前端技术?不能只用服务器端开发人员熟悉的模板引擎解(包括JSP)来演示Spring Cloud吗?
我们再看另外一个例子,Spring的Petclinic大家都熟悉吧?Spring 官方例子:
spring-projects/spring-petclinic?github.com
官方的是Monolithic(单体)应用,模板用的是Thymeleaf,自己去看代码。
用Spring Cloud实现的版本:
Spring Petclinic community?github.com
前端有Angular和React两种实现,服务器端有Java和Kotlin两种实现,都没有用服务器端模板。
同样的问题。为什么演示Spring Cloud的开发,要引入额外的前端技术?
答案都是同样的,Spring Cloud就必须前后端分离开发!用JSP就无法完美拆分微服务,无法利用微服务本应带来的各种优势。
总结:
我曾经在知乎某一个问题下总结过:现在JSP处于被前后端夹击的状态,生存空间越来越小了。就算你不打算管前端,只想在服务器端有所建树。微服务的前提也必须前后端分离。
放弃JSP吧,让自己的路走的宽一些。如果死守JSP不放,服务器端只能停留在SSH/SSM阶段,用Spring Boot+Spring MVC已经是你的天花板了。
ExtJs框架是目前市面上采用比较成熟的js框架,有着诸多优点特别适合用来实现一些内部的管理信息系统.ExtJs提供了一套组件来开发类似于windows桌面的单页面系统,其中desktop桌面的开始菜单按照后台提供的数据动态生成也是一个难点,下面将对desktop桌面动态开始菜单的生成进行介绍。
ExtJs官方提供了desktop桌面的demo,其中关于开始菜单的生成是静态的方式,在js脚本中设置好了固定的开始菜单内容再生成开始菜单。<font color=red>本文的讲解内容均是在官方demo基础上进行的修改</font>
整个需要改进的脚本只有两个一个是根目录下的App.js以及BogusModule.js,前台与后台之间通过Ajax交互,数据交换个是为json
后台定义了Mids类,如下所示:
public class Mids { private String mid; //菜单id private String text; //菜单名词 private String path; //菜单路径 private List<Mid> subs; //子菜单 //Mid作为Mids内部类 public class Mid { private String mid; private String text; private String path; } }
因此前后台交互的json数组示例如下:
[{mid:”m1”,text:”菜单1”,path:”/m1”,subs:null},{mid:”m2”,text:”菜单2”,path:”/m1”,subs:[mid:”m21”,text:”菜单21”,path:”/m21”}]
接下来我们就要修改App.js这个js文件
getModules : function(){ // return [ // //new MyDesktop.Blockalanche(), // //new MyDesktop.BogusMenuModule(), // //new MyDesktop.BogusModule() // // ]; return mArr; }, //找到这段代码并注释掉部分行并修改为return mArr,其中mArr就是开始菜单模块会在另一个js文件中定义
下面我们就看核心的BogusModule.js这个文件,这个文件定义了开始菜单的生成方式和类型
//首先需要定义一个模块类型MyDesktop.BogusModule Ext.define( 'MyDesktop.BogusModule', { extend: 'Ext.ux.desktop.Module', init:function () {}, createWindow: function (obj) { var desktop=this.app.getDesktop(); createWindow(desktop,obj);//该方法另外定义 } });
菜单数组以及Menu模型与后台传递的json数据进行绑定
var mArr=[]; Ext.define('Menu', { extend: 'Ext.data.Model', fields: ['mid', 'text', 'path','subs'] }); //
定义了一个store采用Ajax方式与后台进行是数据交互store进行数据加载并实现开始菜单动态加载和绑定,并且生成桌面
var store=Ext.create('Ext.data.Store', { model: 'Menu', proxy: { type: 'ajax', url: 'menu', reader: 'json' } }); store.load({ scope: this, callback: function (r, op, success) { if (success) { for (var i=0; i < r.length; i++) { var menu=Ext.define('MyDesktop.materialMenu', { extend: 'MyDesktop.BogusModule', init: function () { var mm=this; //判断是否有子菜单,有子菜单则设置为点击无效 if (r[i].data.subs) { mm.launcher={ text: r[i].data.text, iconCls: 'bogus', handler: function () { //有子菜单则点击无效 return false; }, menu: {items: []} }; //遍历子菜单数据并生成子菜单项 Ext.Array.each(r[i].data.subs, function (m, index, allItems) { mm.launcher.menu.items.push({ text: m.text, iconCls: 'bogus', handler: function (src) { var desktop=mm.app.getDesktop(); createWindow(desktop,src); }, //scope: this, src: m.path, windowId: m.mid }); }); } else { //没有子菜单则设置点击打开窗口 mm.launcher={ text: r[i].data.text, iconCls: 'bogus', handler: this.createWindow, scope: this, src: r[i].data.path, windowId: r[i].data.mid }; } } }); mArr.push(new menu()); } // 生成桌面 var myDesktopApp; Ext.onReady(function () { myDesktopApp=new MyDesktop.App(); }); } } });
定义对应的打开窗口模块,每个窗口模块均内嵌了一个iframe,通过该iframe可以加载其它页面内容
function createWindow(desktop,obj) { var win=desktop.getWindow('bogus' + obj.windowId); if (!win) { var iframeId='bogus_' + obj.windowId; win=desktop .createWindow({ id: 'bogus' + obj.windowId, title: obj.text, //width: 800, //height: 600, maximizable: true, maximized: true, closable: true, resizable: true, html: "<iframe id='" + iframeId + "' style='width:100%;height:100%;border:0px;margin:0px;padding:0px;' frameborder='0' src=''></iframe>", iconCls: 'bogus', animCollapse: false, constrainHeader: true, listeners: { afterrender: function () { document .getElementById(iframeId).src=obj.src; } }, buttons: [ { text: '刷新窗口内容', handler: function () { document .getElementById(iframeId).src=obj.src; } }, { text: '切换窗口大小', handler: function () { win.toggleMaximize(); } }, { text: '关闭', handler: function () { win.close(); } }] }); } win.show(); return win; }
这样就完成了ExtJs桌面的动态开始菜单生成
作者 | 张旭乾 责编 | 梦依丹
出品 | CSDN(id:csdnnews)
前端和后端开发,哪一个更容易上手?我们时常会在各大技术论坛看到类似的提问。话说兴趣是最好的老师,不实践,你可能很难知道自己更喜欢哪一个?
从Java开发再到前端工程师,他在转型路上遇到过哪些困难?本文作者张旭乾分享了他的转型经历,以及他在学习前端开发过程中,遇到的问题和总结出来的一些经验,希望对你有所启发。
在 2008 年的时候,我进入大专学习 Java 开发,HTML 和 CSS 只是专业的附属品。那时,主要还是前后端一体化开发,HTML 和 CSS 只是为了结合 Java 里的 Servlet 生成页面。JavaScript 则完全没有讲。
2010 年快毕业的时候,我参加了五个月的 Java EE 培训,在这期间了解了 HTML、CSS,以及一部分简单的 JavaScript DOM 操作和 jQuery,能够编写一些带交互的页面和 Ajax 异步请求。
在这期间,我没有太重视 HTML/CSS/JS 基础。因为本身刚入门,并不知道哪些重要,哪些不重要。在做项目的时候,页面部分要自己在网上搜索 HTML 标签和 CSS 属性的用法。对于 JS 部分,则只会 jQuery,高级的语法(例如闭包、原型链)完全没有概念,只知道该怎么定义变量,处理事件,做一些基本的逻辑处理。
我的第一份工作是 Java 开发,当时公司用的技术很新潮,算是前后端分离的雏形。页面部分完全使用了 ExtJS 库,它提供了一组现成的 UI 组件,所有的数据都是通过 Ajax 来从后端获取,后端则用 Java 的 Servlet 提供JSON 数据。
这份工作的主要难点是一开始不了解前后端分离的开发模式。由于是第一次尝试完全在客户端 JS 去请求数据,所以理解起来需要一点时间,当时阅读了 ExtJS 相关的文档,才大体的了解到这种开发模式。基本上是利用 Ajax 请求数据,然后通过它内置的 API 来填充 UI。后面随着开发的功能变多,对这种模式也适应了。
努力学习还是有回报的,过了三个月试用期之后,因为工作比较出色,在拿到正式员工薪资的基础上,又额外加薪了 10%。所以刚进入公司的时候不要怕上不了手,主流的技术遇到不会的地方要善于自行查找资料解决,对于公司内部的技术要勇于向前辈请教。
2010 年底从第一家公司离职,回到家里自己充电,学习了 PHP。因为当时建站非常流行,学了 PHP 既可以做个人站长,也可以通过自由职业,为客户建站来赚取收入。因为部署网站的主机基本上都支持 PHP 和 ASP,而 PHP 更加流行,所以我就自学了 PHP,通过官方文档,加上实战并结合搜索引擎搜索问题来学习。学完了之后就在网上发了个广告,提供个人建站服务,此时的我还是全栈开发。
2011 年底左右,广告发完了我就忘了,没把它太当回事。大年初六突然收到一个客户的电话,需要做一个网站,这让我兴奋不已。我给这位客户一共做了两个网站:
一个是论坛,直接二次开发的,修改了一下样式。
一个是质量保证查询系统,从零使用 PHP + MySQL + jQuery + jQuery UI 进行开发。
真正有挑战的是第 2 个项目,页面部分几乎遇到了前端开发中全部常见的难题:
JS 代码管理
当时 UI 部分选择了和 jQuery 配套的 jQuery UI。jQuery UI 封装了一组常见的 UI 组件,例如拖拽、对话框、按钮等组件,可以少写一些逻辑代码。尽管如此,编写出来的 JavaScript 文件还是乱七八糟,因为页面上有很多表格组件,需要在获取数据后,手动去循环展示表格,并在删除或修改的时候,还要修改 DOM 更新表格;另外还有其它逻辑,例如登录、查询等。
虽然代码分散在了不同的 JS 里,但是有的页面因为业务逻辑比较复杂,加上当时我也不太了解 JS 的复用方式和逻辑,导致了很多重复的代码。我还有当时的源代码,可以感受一下代码的长度(两张图片为同一 JS 文件的不同部分,这里通过缩略图展示):
一个 JS 文件中的代码
兼容性调整
彼时,浏览器主流的还是 IE,所以还是需要做一些兼容性调整。不过好在 jQuery 主打的就是兼容全部浏览器,所以 JS 方面没有太大问题,剩下的就是 CSS。这个项目在 IE、Chrome、火狐下显示的都不一致,后来查了一下,解决方法可以根据浏览器特定的语法,编写只在特定浏览器能识别的 CSS 属性,或者选择器,也就是所谓的 CSS hacks。另外也可以使用浏览器特殊的 HTML 指令,加载不同的 CSS 文件,最终把页面调成一致就可以了。
性能调优
因为项目页面部分处理数据比较多,加上开发经验有限,当时也只是在代码效率上进行了优化,例如减少不必要的循环操作等。
与客户沟通需求
这个是开发的软技能了,学会如何拒绝不合理的需求。因为当时我是第一次面对客户,也没有自信,所以客户说改什么,我立刻就开始给他改。这期间客户最常见的话术就是:“这个功能很简单,你做一下”,或者“这个问题很容易解决,花不了你几分钟”。当时我真觉得功能或者问题挺简单的,但是实际操作起来,发现要比想象的难多了。做了几次之后,知道无论多简单的功能或问题,都会涉及很多的细节,所以后面客户再提要求的时候,我就把这些细节先说清楚,给他一个大概的完工时间,再加上新增的功能需要额外收费,客户就会自己斟酌要不要做了。
网页设计水平
还有一个意外,让我学了一部分设计知识。在给这个客户做质量保证系统的时候,还要求附带一个产品的官网,客户给我发了产品资料之后,我参考网上同品类的网站,帮他设计了一版,但是客户以不够大气为由,让我重新设计,我又设计了一次,客户还是觉得不够好,反复几次,似乎无法满足他的需求,他就把官网这部分给别人做了。当时我也有点憋气,于是买了本《写给大家看的设计书》,专门学习了一些设计原则,努力提高自己的设计能力。后来等客户的官网上线之后,发现设计的也一般,大概是审美不同吧。
在自由职业后半段时间学习了其它的框架,那个时候 Bootstrap 3、Foundation 之类的 HTML/CSS 框架开始爆火,因为十分喜欢学习新的技术,我就去看了看它们的介绍,看到 Bootstrap 3 内置了很多组件,并且不怎么需要写 CSS,就学了一下 Bootstrap 3。Bootstrap 3 内部使用了 LESS 这个 CSS 预编译工具来生成 CSS,如果要自定义它的样式,还需要会 LESS。我就又看了一下 LESS 的文档,发现它提供了很多实用的功能,例如变量、继承、嵌套等,感觉很有意思也顺便学了。
从这里你就可以知道:前端库是互相依赖的。如果直接看前端需要哪些库,那么零零散散的有一堆,但是当你真的开始下手学习一个框架的时候,你会发现好多框架可以从一条线里牵出来,构成一个完整的开发工具库,这些自然就都掌握了。
前边所有的经历,奠定了我转型前端所需要的技术基础。而在从事自由职业期间,我发现我还是喜欢看做得见的项目,从 0 设计界面,直至实现出来,很有成就感,并且我也享受在设计过程中,灵感迸发的快乐,心底就有了想转前端的火苗。不过第 2 份工作,从 2013 年到 2016 年,我仍然做的是 Java 开发。
真正让我对前端产生兴趣,是 2016 年去留学之后。在 2017 年第一个学期,有同学问我 React 的问题,我不太会,于是就上网帮同学查,查着查着,就发现前端已经独立作为一个职业了,再接着从 React 文档找问题的解决方案时,发现之前我用 jQuery 的问题在 React 中全部都解决了,可以不用手动维护数据和 UI 之间的同步了,这让我感到很欣慰,发誓等这学期放暑假,就深入学习一下。
很快,暑假就到了,要兑现承诺开始学前端。当时室友学了高级 Web 编程,主要讲的是 React,React 在那个时候还非常难用,应该还是 React 15,需要手动配置好多东西:Babel、Bower.js 之类的。看着室友遇到一个组件显示不出来,经过一天的搜索解决方案,才发现是组件名大小写不一致导致的,这个让我有点对 React 好感度降低,不想学了。
后来我就研究了一下 Vue,发现普遍的说法是:功能和 React 类似,但是国内用 Vue 的多,国外用 React 的多。看了下 Vue 是华人尤雨溪开发的,很佩服,据说上手比较容易,于是就决定先看看 Vue?
在把 Vue 官方文档基础部分看完之后,结合 YouTube 的一些视频所教授的开发方法,大概一周的时间,觉得可以上手了,就想了一下练习项目。当时了解到 Vue 适合开发单页应用,看了一下单页应用的特点,发现似乎就是网页版 App 的概念? 于是,我就想着把当时我用的最多的网易云音乐模仿一下。花了一周多的时间,实现了首页 UI、添加歌曲,播放、暂停、快进、快退等功能,期间学会了 CSS flex 布局。
使用 Vue 仿网易云音乐(左)的最终界面(右)
后来发现网页版的功能局限性比较大,想着能不能做成桌面端的。当时室友在学校的课里学 Electron,一个跨平台的桌面开发框架,只用编写 HTML? CSS 和 JavaScript ,就可以生成在 Mac、Windows、Linux 操作系统都能运行的应用。于是我又把应用迁到了 Electron 上面。
从 Electron 这里也了解到了,Node.js 到底和浏览器 JS 运行时到底有什么不同:在 Node.js 的环境下,可以访问更底层的操作系统级 API,例如访问本地文件,这样可以方便用户自行添加音乐。
做这个项目的时候,也遇到了很多问题:
不知道什么时候需要定义成组件。刚刚接受这种组件化开发的方式之后,最大的难题就是怎么才知道该不该把一部分 UI 定义成组件。当时的思路就是,我先把所有的页面代码都写在入口组件里,后面再根据页面的布局,把这个组件拆分成各个部分,例如侧边栏、播放列表、播放控制器等,这样的分法似乎很合乎逻辑,不过这也带来了一个问题。
组件和数据杂糅到了一起。项目当时使用了 Vuex,应用的数据全部交给了它去管理,对于项目的功能逻辑,都是直接在相关的 UI 中实现的,并绑定了 vuex 的数据。例如播放进度条,它和歌曲的播放时间数据绑定了,后面要实现音量进度条的时候,发现这个组件无法复用。因此,我又把 UI 和数据分离了出来,这样的组件,可以在各处复用,之后再实现对应的逻辑就好了。
CSS Flex 布局遇到坑。这个项目使用了当时开始流行的 CSS Flex 布局,本着学习的态度使用它,遇到了很多问题,例如父容器对 flex 缩放的影响,如何让 flex 元素占满容器,又或是如何让 flex 不占满容器等等,这些在看了 MDN 文档的介绍,了解了 flex、align-items 和 justify-content 各个属性值的作用和含义之后,就清楚了元素的缩放逻辑。
通过这个小项目的开发,对 VUE 算是入门了,还得出了结论:
学前端,或者任何编程知识,一定要结合实践才能快速入门并掌握它们。
学完 Vue 之后暑假差不多也快结束了,最后一个学期都在努力学专业课,没有再看前端相关的东西。2018 年回国之后,开始找工作。因为留学的主要方向是分布式和云计算,所以我还是想以 Java 开发为主。面试的时候遭到了很多不屑,大多是看我刚研究生毕业,而以前的开发经历也没什么出彩的地方,就都草草了事了。这些经历让我很受打击,但是让我清楚的知道了,纵使有一肚子墨水,但是拿不出实际的产品,或者满足不了面试官的喜好,就不可能面试成功。
当然我不会否定自己,最后一次面试失败之后,突然就想要不要改行做一下前端,毕竟留学的时候钻研了不少,又在自由职业的时候做过一些产品,更是有浓厚的兴趣,于是我立刻下了决心转前端。
下定决心之后,我一刻也没闲着,开始看前端的工作要求。在某招聘 App 上搜了一圈,发现 React 在大厂用的多、工资也高一点,我就又开始自学 React,花了一周看了看官方文档,写了一个特别小的、只有一个页面的小例子,之后就开始投简历了。期间还看了看 React Router、Redux,以及 ES6 的新特性。
在阅读 React 官方文档的时候,发现有一节是《Thinking in React》,里边详细的介绍了 React 组件化开发的步骤,并且解释了什么时候需要定义组件,文档提供了一个表格 UI 作为示例,把它拆解成了表格整体、搜索框、表格内容、类别行和产品行组件,说明了为什么这么拆解,有没有其它拆解的方法,以及拆解过程的方案折中,建议看一看。
图片来源:https://reactjs.org/docs/thinking-in-react.html
觉得准备的差不多了之后,就开始投简历了,大约 1 个月的时间,收到 3 家面试,只通过了 1 家。没过的那两家同样也是见我刚毕业,连前端开发经验都没有,就草草了事了。通过的这家,面试官是我工作时的技术总监和组长,在面试的时候没有刻意刁难,只是问了些框架方面的基础问题,还问了一下我平时是怎么解决问题的。后来,我在工作的时候,问他们为何决定让我入职,他们告诉我,看中了我的学习能力。
所以面试如果没经验的话,就努力说明自己的学习能力,总会有面试官欣赏你的。我到现在还非常感谢两位,让我正式进入了前端开发的行列。
进了公司就开始了日常做项目,大大小小一共做了 3 个,这期间经历了逻辑混乱期、尝到甜头期和精进技术期,积累了大量的开发经验。
第 1 个项目,是改造一个传统的项目,按技术总监的建议,使用 React + dva.js 框架。UI 方面,项目之前用的是 Bootstrap,我用了 React Bootstrap 把项目迁移了过来。
这个项目里遇到的问题是:代码混乱。这个时期因为刚刚上手 React 开发,对于代码的管理也没有太大的概念,加上 dva.js 的项目结构也不同于普通的 React 项目,所以这个项目开发起来有点麻烦,再加上项目的逻辑比较多,导致组件的代码很长很长,复用起来也很困难(俗称面条式代码),不过因为这个项目也不是完全对外公开的,并且使用频率较低,所以就没在优化。
第 2 个项目,是做一个公司内部用的运营管理后台,时间大约是 2018 年底,当时 React alpha 测试版出了 hooks。看了一下官方文档,感觉很神奇,能够清晰地分离组件 UI 和逻辑,应该能给代码管理提供不小的帮助。虽然是测试版,但这个项目是完全对内的后台项目,所以果断的用上了。
这个项目的后端比较特殊,一位大佬同事搭建了 GraphQL 服务,之前在留学的时候就已经听同学提到过很多遍了,现在有机会体验体验了。在看 GraphQL 官方文档学习、以及使用搜素引擎搜索的时候发现,使用 GraphQL 后可以不用 Redux,于是这个项目我只用了 React? React Router 和 Apollo-GraphQL 这几个主要的库。
这套技术加上 React hooks,让我真正感受到了前端开发的乐趣。组件从类的形式转换成了函数形式,代码量减少了很多,公共的逻辑也能抽离成 Hooks,在各个组件使用,组件自身的逻辑也能抽离成 hooks,来让功能和 UI 展示代码分开,让代码更易读。这样,整体的开发效率提高了不少。
UI 方面则尝试了 Ant Design,因为纯后台的,没有设计稿,只有产品原型。
另外这个项目是基于 Create-React-App 脚手架创建,了解到脚手架提供的功能非常全面,像静态资源(图片、字体)管理、插件、打包构建等都包括了,省了很多手工配置。
第 3 个项目,是一个从 0 开始、面向客户的应用,UI 是由设计师专门设计,有很多自定义的样式。这是我积累最多前端开发经验的项目,从技术选型,到组件规划,再到代码复用,对前端开发的架构有了全新的认识。
为了研究怎么在 React 项目中管理样式最方便,我开始研究大型项目中的 CSS 样式管理,了解到有普通 CSS 和 CSS-in-JS 两种方案之后,再查资料发现 CSS-in-JS 方案更灵活,能够在 CSS 里访问 JS 变量,让组件样式可以随着组件状态的变化而变化。
决定用 CSS-in-JS 方案之后,我找到了 GitHub Star 数比较高的 styled-components 库,它支持 CSS 嵌套、主题等功能,并且能够访问组件的属性,而且它定义的样式,本身也是一个 React 组件,可以直接在 JSX 中使用。
UI 库继续使用了 Ant Design,不过也就是利用一下它的组件功能逻辑,样式几乎全部都修改了。
项目后端这次没有用 GraphQL,我又发现不用 GraphQL 也没必要使用 Redux,所以就没有再添加 Redux,结果也证明我的选择是对的:项目本身没太多全局状态,舍弃 Redux 大概让开发效率提升了 1 倍,之前像表单这样的组件大概需要一天才能完成,现在只需要半天。不过项目里有个内嵌的聊天系统,需要用一点全局状态,我就从网上查找了一些解决方案,发现使用 React Context + useReducer Hooks 的方式实现全局状态管理就够了。
这个项目使用的新框架都是一边看官方文档一边学习的,有不好解决的问题,就结合搜索引擎和 GitHub Issues 解决。
对于项目的结构,这次使用了就近原则来组织代码,每个组件放到单独的文件夹中,组件相关的 styles、图片、hooks 等都放在同一个文件夹,对于公用的部分,则放到项目顶级的 src 目录下。API 和其它库的配置项也都放到单独的文件夹里,同样遵循就近原则,这样管理项目就方便多了。
这个项目的图表也比较多,为了和 App 端保持一致,选择了 Echarts。在使用 Echarts 的时候,虽然能够实现大部分设计稿中的样式,但是还是有小部分不能精准还原,在拿着实际效果跟设计师沟通之后,有些样式就做了些调整,或直接舍弃了。
项目最后验收的时候,还需要跟 UI 设计师核对样式,这期间我和设计师找了单独的工位,每天都是在沟通哪里的设计需要修改,哪里的设计不好实现,怎样取一个大家都满意的折中方案。这些在了解设计基础原则之后,你也会明白设计师设计的意图和用意,这样用理解的心态来沟通,再辅以技术上的难度展示和时间需求,就能够更好的避免不必要的 UI 改动和代码重构。
先看一下前端工程师需要掌握哪些技能。
综合大、中、小企业的前端工程师技能需求,实际上前端工程师的职能包含以下职业中的 1 种或多种:
网页开发工程师
网页设计师(UI)
用户体验工程师(UE)
最重要的职能是网页开发,包括小程序、APP 等跨端应用界面的开发,虽然它们实现的技术不同,但本质上还是做页面。
前端工程师必备的技能有:
使用 HTML + CSS,精准地还原设计稿,制作符合要求的页面。
使用 JavaScript 给页面添加交互,懂得 DOM 操作和 Ajax 请求。
掌握 React 或 Vue 等主流框架的一种或几种,并了解随着这些框架的工程化,所牵涉的一系列工具(不同工程需要不同的工具,这里列出常见的), 例如:
Node.js 与 npm。
Webpack、SnowPack、Vite 等打包工具。
Create React App、Vue CLI、Vite 等脚手架。(Vite 既包含脚手架,也包含打包工具)
Gulp、Grunt 等自动化工具。
SASS/LESS 等 CSS 预编译工具。
styled-components、emotion 等 CSS-In-JS 库。
ESLint 语法检查工具。
Jest、mocha 等测试库。
兼容性调整,利用 CSS hacks,或 JS Polyfill,实现跨浏览器页面表现一致。
性能优化,减少文件体积,减少请求次数,延迟加载图片和脚本等。
SEO 搜索引擎优化,提高网站在搜索引擎的排名。
其他的一些框架或技能,如果工作要求,也需要掌握:
SSR 服务端渲染框架,例如 Next.js(React)、Remix.js (React)、Nuxt.js(Vue)。
SSG 静态网站生成器,例如 Next.js、Gatsby、VuePress 等。
TypeScript。
GraphQL。
PS/Sketch/Figma,能根据需要进行切图,或者自行设计页面。
下面这些技能不是必须的,但是如果能掌握,可以提高工作效率、跟后端或设计师沟通的能力,以提升求职升职的竞争力:
网页设计,了解设计基本原则。
用户体验设计,了解网页的动效、辅助功能对用户体验的影响。辅助功能(可访问性)在国外比较重视,目的是方便有阅读障碍的人士,使用屏幕阅读器进行网站浏览。如果你想去外企,这些技能是必须要掌握的。
Docker,了解如何把前端项目构建为 docker image,会编写简单的 docker file。
后端语言、框架、数据库,任选一套,例如 Java + Spring + PostgreSQL,Express + Node.js + MongoDB 等,了解 RESTful API 开发过程。
乍一看要掌握的有很多,但很多库都是随着 React、Vue 等最重要的前端库自然而然地引入进来的,大部分的用法都很简单,并且我们还会在工作中持续学习,一开始只需要入门就行。下图展示了 React 前端开发工程师,根据 React 框架所衍生的技术栈(示意):
React 前端工程师技能图谱(示意)
2019 年从公司再次离职,不想再打工了,借鉴在国外留学时所学到的经验,转型开始做视频和线上教学,运营着“峰华前端工程师”账号,同时也在 CSDN 发表博客。在这期间还撰写了《JavaScript 基础语法详解》一书。
编写书籍的时候,又是一次学习的过程,在查阅各种资料之后,对 JavaScript 有了更完全的认识。同时也明白了,人只有存在目标的情况下,才会有动力去完成看似不可能的事,避免浑浑噩噩度日。
如果你像我一样,也算比较大龄的程序员,有年龄焦虑,可以适当的想想还要不要在公司里继续工作下去,是不是该拿出勇气来尝试做自己真正想做的事,之后利用兴趣养活自己。这不是一条容易的路,所以在决定之前一定要做好两年之内没有起色的打算,这些如果我能总结出一套经验之后,再来分享。
这些大体就是我学习、掌握前端开发的过程,总结了下面这些重点:
学会独立学习。前端的框架太多了,并且经常出现新奇特框架,必须要能自己独立通过官方文档和搜索引擎进行学习,因为前端框架多数比较小众,不会有很多相关的教程。如果连文档都没有,就要学会读源码学习用法。
基础打牢。前端库虽然多,但万变不离其宗,总是要回归到 HTML、CSS 和 JavaScript 上面,所以基础一定要打牢,尤其是在 ES6 以后出现的新特性,在前端用途非常广泛。
实战练习。学完前端库之后,一定要找个小项目做,把学到的东西真正地掌握。Github 上有很多前端项目灵感的库,可以搜索 “front-end project ideas" 找到 ,或者你也可以改造模仿市面上的网站、App 等。
不要把前端只局限在技术层面。向上往设计和产品扩一下,向下从后端和运维钻一下,你会更能从整体角度观望整个项目,从而在前端技术选型、开发过程以及和同事沟通的时候,懂得取舍和折衷。
线上文档。对于 HTML、CSS 和 JavaScript 最权威的文档就是 MDN。其它的像 React、Vue 等框架,就是官方文档。如果遇到了问题,就去搜索引擎搜索,看其他人写的解决方案。
书籍。对于体系化的教程,可以购买相关的书籍看,重点看专业、经典的书籍,这些网上有很多推荐。书籍可以帮助你快速入门并深入,不用在网上东找西找了。
视频。现在视频平台正火爆,不要只用来消遣,上边也会有很多编程相关的视频,空余时间可以刷一刷,可能会获得一些开发灵感、技巧,以及未来工作可能用到的新技能。
在线课程或培训。在线课程或者培训能帮你直接学到和就业相关的技能,积累项目实战经验,但是要注意鉴别课程和机构的质量。
向有经验的人学习。如果你看到有高级工程师发布的博客、微博、视频等内容,可以尝试和他们建立联系,拿出你学习的诚意,让他们帮你指点迷津,或许能少走一些弯路。
END
成就一亿技术人
*请认真填写需求信息,我们会在24小时内与您取得联系。