整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          放棄JSP吧-否則你無(wú)路可走

          放棄JSP吧-否則你無(wú)路可走

          說一下我自己學(xué)習(xí)和使用JSP的經(jīng)歷吧

          我1998年開始學(xué)習(xí)Java,那時(shí)候?qū)W校里老師可能聽說過Java,但是同學(xué)基本上都不知道Java。校圖書館進(jìn)第一批Java的書,后面的借閱記錄上都是我的名字。當(dāng)時(shí)幾乎所有男同學(xué)都在學(xué)C++、PB、VB、Delphi,女生很多在學(xué)ASP。所以很多同學(xué)問我學(xué)的是什么,Java是干什么的。

          大學(xué)畢業(yè)以后,開始用Java做的第一個(gè)實(shí)際項(xiàng)目是對(duì)日外包,是2001年。日方有一套很老的系統(tǒng),想用Java重構(gòu)一下,要求用JSP。我下班就跑去西單圖書大廈,發(fā)現(xiàn)那里的書都還是Servlet的, 沒有JSP的!

          還好,當(dāng)時(shí)的公司同時(shí)進(jìn)行的一項(xiàng)業(yè)務(wù)就是代理BEA的Weblogic(BEA是三個(gè)從SUN出來(lái)的人創(chuàng)建的,后來(lái)被Oracle收購(gòu))。Weblogic的產(chǎn)品文檔里包含非常全面的JSP介紹,所以起初對(duì)JSP的學(xué)習(xí)都是從Weblogic開始的。

          那時(shí)候還沒聽說過什么Struts。自己在SUN的官網(wǎng)發(fā)現(xiàn)了WAF的文檔,全稱是Web Application Framework,算是最早MVC模式的介紹。這個(gè)WAF不算是框架,只是介紹了MVC模式應(yīng)該是個(gè)什么樣子,如何用Servlet+JSP實(shí)現(xiàn)MVC模式。SUN的官網(wǎng)提供了少量的樣例代碼,剩下的都是我們根據(jù)文檔自己搭建和實(shí)踐。

          在項(xiàng)目的中后期(02年下半年吧),有一次坐班車,聽到后面座位上兩個(gè)人在說話。一個(gè)人問:你知道Struts嗎?另外一個(gè)人說:不知道。問的那個(gè)人說:就是S T R U T S這幾個(gè)字母,開發(fā)Java的。我偷偷記在心里,然后第二天上網(wǎng)查了一下(當(dāng)時(shí)沒有智能機(jī),家里也沒有WIFI),才算開啟了Apache這扇大門。后來(lái)在ASF上又學(xué)習(xí)了Cocoon、pluto、turbine等等很多框架。

          大概02年底,對(duì)日外包項(xiàng)目順利完成了,我公司開始接國(guó)內(nèi)的項(xiàng)目。第一個(gè)國(guó)內(nèi)項(xiàng)目是東北一所大學(xué)的科研經(jīng)費(fèi)審批項(xiàng)目。記得去給人家部署和演示的時(shí)候特別有意思。我們用了半天時(shí)間在服務(wù)器上部署好,然后去給客戶演示。打開瀏覽器,輸入ip+端口,開始操作。操作了十幾分鐘,所有的客戶沒有說一個(gè)字。越演示心里越?jīng)]底,不知道客戶啥反應(yīng)。大概又過了幾分鐘,客戶的主任發(fā)話了:你們的軟件呢?

          我們的軟件呢?我給你演示了半天,這不就是我們的軟件嗎?最后才明白,用戶認(rèn)為只有下載一個(gè)類似叫setup.exe或install.exe的程序,雙擊,然后下一步下一步,最后桌面上出現(xiàn)一個(gè)快捷方式,那才算是軟件!在經(jīng)過片刻的不可思議之后,我認(rèn)為實(shí)際用戶的理念總是落后于研發(fā)人員的理念,這個(gè)我很容易想明白。但后來(lái)發(fā)現(xiàn),我那些學(xué)PB、Delphi的師兄弟也不是一時(shí)半會(huì)能接受B/S結(jié)構(gòu)的應(yīng)用算是軟件的...他們認(rèn)為:你不就是寫個(gè)網(wǎng)頁(yè)嗎???

          再后來(lái),從03-08年,長(zhǎng)期從事企業(yè)應(yīng)用開發(fā),主要是基于Weblogic Platform,包括Server、Integration、Portal,其中在Portal上工作的時(shí)間最多。

          其中04-05年用Weblogic Portal做深圳市最大的電子政務(wù)項(xiàng)目,06-07年用Weblogic平臺(tái)做廣東省電信的3G業(yè)務(wù)平臺(tái),08-09年用Aqualogic做南方電網(wǎng)的SOA。

          Weblogic Server中集成了Struts,沒記錯(cuò)的話當(dāng)時(shí)是1.1版本。BEA把Struts做了升級(jí)和改造,可以在Weblogic Workshop中可視化開發(fā),就是下面這樣:

          其中圓形代表Action,有Begin Action,End Action,還有普通的中間節(jié)點(diǎn)Action。BEA把Struts的這個(gè)升級(jí)稱作Java Page Flow(Java 頁(yè)面流)。一組這樣的圖形當(dāng)中包含的Action和JSP,會(huì)定義在一個(gè)擴(kuò)展名是.jpf的文件中。

          后來(lái),BEA把JPF捐獻(xiàn)給了Apache,成為ASF下的一個(gè)開源項(xiàng)目Apache Beehive。

          Welcome to Apache Beehivebeehive.apache.org

          這個(gè)項(xiàng)目現(xiàn)在已經(jīng)停止更新了。

          大概從06年開始,接觸到了YUI,也就是Yahoo User Interface,Yahoo開源的一套前端JS組件庫(kù)。從此算是開啟了我的前端之路。

          07-08年開始用Extjs,作者說Ext就是Extension(擴(kuò)展)的意思,擴(kuò)展了YUI,提供了更豐富的適合企業(yè)開發(fā)的前端組件。但這時(shí)候,Extjs還僅僅是豐富的UI組件庫(kù),算不上框架。就是在JSP生成的HTML里面嵌入Extjs的組件。

          09-11年用GWT,就是Google Web Toolkits。Google當(dāng)時(shí)的想法很先進(jìn),用Java開發(fā)前端UI,最終編譯成JS。有點(diǎn)類似于現(xiàn)在TS編譯成JS的過程,就是打算利用上Java的強(qiáng)類型、面向?qū)ο蟮忍攸c(diǎn)。這時(shí)候就已經(jīng)完全前后端分離了。可以說從08年之后我就再也沒寫過JSP,一個(gè)頁(yè)面也沒寫過。

          10年開始用Bootstrap。這時(shí)候GWT的缺點(diǎn)就暴露出來(lái)了,CSS非常難改。直到13年初,開始用上了Angularjs。記得當(dāng)時(shí)在智聯(lián)招聘上發(fā)布職位的時(shí)候搜了一下,北京市只有用友和我們公司招聘Angularjs開發(fā)。后來(lái)就從Angularjs用到React,又用回Angular4,一直到現(xiàn)在都以最新版本的Angular為主,企業(yè)應(yīng)用和互聯(lián)網(wǎng)應(yīng)用都有開發(fā)。移動(dòng)開發(fā)主要用Ionic,React Native也用過。

          為什么要詳細(xì)介紹我過去和JSP以及前端框架相關(guān)的開發(fā)經(jīng)歷呢?是因?yàn)槲蚁氡磉_(dá)一個(gè)觀點(diǎn):如果要客觀公正評(píng)價(jià)JSP是否還有必要用,特別是還有必要學(xué),需要一個(gè)真正長(zhǎng)期用過JSP(前后端不分離)開發(fā),也真正長(zhǎng)期用前端框架(前后端分離)開發(fā)的人才可以。

          就像我在有些知乎答案下評(píng)論的那樣:

          遇到這種情況,我總想起福特的名言:“如果我當(dāng)年去問顧客他們想要什么,他們肯定會(huì)告訴我:‘一匹更快的馬。’”

          滿大街跑馬車的時(shí)代,福特問顧客需要什么,顧客就說需要一匹更快的馬。他們不知道汽車時(shí)代會(huì)給生活帶來(lái)怎樣革命性的變化。

          在BP機(jī)時(shí)代,大家認(rèn)為有人戴BP機(jī)已經(jīng)很牛了。滿大街諾基亞摩托羅拉功能機(jī)的時(shí)代,大家也都覺得夠用了。問他們需要什么,他們估計(jì)會(huì)回答:充一次電能不能待機(jī)一個(gè)月?能不能把自己喜歡的MP3當(dāng)彩鈴?

          我覺得要對(duì)比評(píng)價(jià)兩代產(chǎn)品,應(yīng)該給兩代產(chǎn)品都熟練體驗(yàn)過的人去判斷。從功能機(jī)時(shí)代過來(lái)的人,現(xiàn)在iphone都已經(jīng)用到第三部了,你再問他功能機(jī)夠不夠用。就拿一個(gè)兩代產(chǎn)品都具有的功能(比如都可以QQ聊天)對(duì)比,你愿意回到功能機(jī)時(shí)代還是繼續(xù)用智能機(jī)。

          一直抱定JSP不撒手,沒動(dòng)力、沒能力學(xué)習(xí)前端技術(shù),沒有真正理解前后端分離開發(fā)模式的人,不可能得出公正全面的評(píng)價(jià)。

          在校期間或參加培訓(xùn)班就學(xué)習(xí)了前端框架,參加工作后就開始前后端分離的人,也無(wú)法理解老人只用JSP或用JSP+JS前端UI組件的開發(fā)模式是個(gè)怎么回事。

          上面兩種人,據(jù)我實(shí)際接觸中了解,大部分都認(rèn)為自己的開發(fā)模式是理所當(dāng)然的。就像我之前描述自己剛畢業(yè)時(shí)候的經(jīng)歷一樣。大部分客戶和我的一些同學(xué),理所當(dāng)然認(rèn)為雙擊setup.exe,然后下一步下一步才是軟件。而我理所當(dāng)然認(rèn)為B/S架構(gòu)的也是軟件,只是更便于開發(fā)和操作。

          JSP為什么不適合現(xiàn)在的主流開發(fā),為什么正在被拋棄

          過去一年多,陸陸續(xù)續(xù)在知乎上回答了一些關(guān)于JSP的問題。當(dāng)然,我的回答都是建議淘汰JSP,新人小白一定不要再學(xué)JSP了。我現(xiàn)在集中把這些技術(shù)因素歸納一下。

          一個(gè)現(xiàn)代主流Java Web應(yīng)用,不管前端、后端、還是微服務(wù)架構(gòu),都在淘汰JSP。

          其中,我認(rèn)為Java服務(wù)器端主流技術(shù)還是Spring(Spring Boot + Spring MVC + Spring Cloud)。

          下面三點(diǎn),第一點(diǎn)幾乎盡人皆知,第二點(diǎn)有一部分人清楚,第三點(diǎn)卻很少有人意識(shí)到。

          前端框架已經(jīng)非常成熟和穩(wěn)定,不需要JSP
          前后端分離已經(jīng)不是什么趨勢(shì)了,而是當(dāng)前B/S架構(gòu)開發(fā)的主流模式。前后端分離之后,前端只負(fù)責(zé)展現(xiàn)和交互,后端負(fù)責(zé)核心業(yè)務(wù)邏輯。前后端通過API進(jìn)行交互,并且最好符合RESTful風(fēng)格。服務(wù)器端把數(shù)據(jù)返回給前端就不再關(guān)心這些數(shù)據(jù)用在哪里、如何布局、什么樣式。

          這個(gè)層面的原因非常容易理解,也是絕大多數(shù)討論JSP是否還有必要學(xué)的時(shí)候里都會(huì)提到的。


          服務(wù)器端的Spring MVC/WebFlux 和 Spring Boot已經(jīng)開始拋棄JSP
          從Spring 5開始,在原有的基于Servlet技術(shù)的Spring MVC之外增加了一個(gè)新的編程模型,就是Spring WebFlux。
          Spring WebFlux是響應(yīng)式非阻塞的,而且不支持Servlet API,所以也就不支持JSP!

          上圖左側(cè)是Spring 5新引入的Spring WebFlux,右側(cè)是大家熟悉的Spring MVC,兩者并列,Spring同時(shí)支持。

          關(guān)于這一點(diǎn),可以看Stack Overflow上面來(lái)自Spring Framework和Spring Boot團(tuán)隊(duì)成員Brian Clozel的回答:

          Spring WebFlux - no JSP support??stackoverflow.com

          新的Spring WebFlux不支持JSP,那咱們不用就好了,至少Spring MVC還是支持JSP的啊。那我們繼續(xù)看。

          如果我們繼續(xù)使用Spring Boot+Spring MVC開發(fā),那么Spring Boot對(duì)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。當(dāng)使用嵌入式Servlet容器時(shí),有一些已知的限制。

          關(guān)于這些限制和如何繼續(xù)在Spring Boot中使用JSP,可以自己查一下,知乎里就有好多文章

          Spring Boot對(duì)JSP有限制,那咱們就湊合用唄,反正我是寫Java的,我的發(fā)展方向是架構(gòu)師,我正打算學(xué)習(xí)微服務(wù),正在看Spring Cloud。那咱們就繼續(xù)看看Spring Cloud吧。


          微服務(wù)架構(gòu)下更沒有JSP的用武之地
          首先要明白Spring Boot和Spring Cloud的關(guān)系。可以先看我的這個(gè)回答:

          Spring boot與Spring cloud 是什么關(guān)系??www.zhihu.com

          還是看這張圖吧:

          右側(cè)綠色的部分都是Spring Cloud的組成部分,不管是API Gateway、Config Dashboard,Service Registry,還是多個(gè)MicroServices,他們都是Spring Boot應(yīng)用!或者說Spring Boot是整個(gè)Spring Cloud的基石(其實(shí)也是Spring Cloud Data Flow的基石)。

          哦,你明白了,因?yàn)橛蠸pring Boot對(duì)JSP的限制,而Spring Cloud的組成部分都是Spring Boot應(yīng)用,所以Spring Cloud也對(duì)JSP有限制。其實(shí)不僅僅是表面上這個(gè)原因,咱們繼續(xù)分析。

          如果強(qiáng)行繼續(xù)在Spring Cloud環(huán)境中繼續(xù)使用JSP,那么JSP放在哪里?有兩種方案。

          1. API Gateway和每個(gè)MicroService里面都有@Controller以及對(duì)應(yīng)的JSP。那么這種方案下,不同微服務(wù)中的JSP如何通信?用戶訪問的時(shí)候,同一個(gè)應(yīng)用下的所有JSP頁(yè)面會(huì)在不同IP和端口下來(lái)回變換。一會(huì)是http://ip0:8081/xxx/xxx.jsp,一會(huì)是http://ip1:8082/xxx/xxx.jsp,點(diǎn)個(gè)連接又跳轉(zhuǎn)到http://ip2:8080/xxx/xxx.jsp....
          2. 把整個(gè)微服務(wù)應(yīng)用下的所有@Controller和JSP都放在API Gateway里面,其他Microservice中只有提供REST API的@Controller和@Service。這種方案并不算理想的微服務(wù)架構(gòu),因?yàn)镚ateway沒有解耦,里面的所有@Controller不能拆分部署。這樣就相當(dāng)于在MicroService架構(gòu)下有了一個(gè)局部的Monolithic(單體應(yīng)用)。

          那怎么才算是使用Spring Cloud的正確姿勢(shì)?還是看上面那幅圖,這次關(guān)注左側(cè)三個(gè)灰色的部分。IoT(物聯(lián)網(wǎng) Internet of Things)、Mobile(移動(dòng)應(yīng)用)、Browser(瀏覽器端),這三個(gè)也是應(yīng)用啊。

          我們?cè)倏匆环鶊D:

          整個(gè)Spring體系的圖出來(lái)了。還是看左側(cè),Your App,也就是IoT(物聯(lián)網(wǎng) Internet of Things)、Mobile(移動(dòng)應(yīng)用)、Browser(瀏覽器端)這三類!

          Browser就是前后端分離之后的前端應(yīng)用,獨(dú)立開發(fā)、獨(dú)立部署、只和服務(wù)器端有HTTP RESTful通信。

          我們看看Spring官方給出的Spring Cloud例子,鏈接在這里:

          Spring Projects?spring.io

          customers-stores-ui是前端應(yīng)用,用Angularjs實(shí)現(xiàn)的。例子是便于學(xué)習(xí)的,不應(yīng)該引入額外的太多其他技術(shù)!為什么Spring官方的例子非要用上前端技術(shù)?不能只用服務(wù)器端開發(fā)人員熟悉的模板引擎解(包括JSP)來(lái)演示Spring Cloud嗎?

          我們?cè)倏戳硗庖粋€(gè)例子,Spring的Petclinic大家都熟悉吧?Spring 官方例子:

          spring-projects/spring-petclinic?github.com

          官方的是Monolithic(單體)應(yīng)用,模板用的是Thymeleaf,自己去看代碼。

          用Spring Cloud實(shí)現(xiàn)的版本:

          Spring Petclinic community?github.com

          前端有Angular和React兩種實(shí)現(xiàn),服務(wù)器端有Java和Kotlin兩種實(shí)現(xiàn),都沒有用服務(wù)器端模板。

          同樣的問題。為什么演示Spring Cloud的開發(fā),要引入額外的前端技術(shù)?

          答案都是同樣的,Spring Cloud就必須前后端分離開發(fā)!用JSP就無(wú)法完美拆分微服務(wù),無(wú)法利用微服務(wù)本應(yīng)帶來(lái)的各種優(yōu)勢(shì)。


          總結(jié):

          我曾經(jīng)在知乎某一個(gè)問題下總結(jié)過:現(xiàn)在JSP處于被前后端夾擊的狀態(tài),生存空間越來(lái)越小了。就算你不打算管前端,只想在服務(wù)器端有所建樹。微服務(wù)的前提也必須前后端分離。

          放棄JSP吧,讓自己的路走的寬一些。如果死守JSP不放,服務(wù)器端只能停留在SSH/SSM階段,用Spring Boot+Spring MVC已經(jīng)是你的天花板了。

          xtJs Desktop桌面開始菜單動(dòng)態(tài)生成

          ExtJs框架是目前市面上采用比較成熟的js框架,有著諸多優(yōu)點(diǎn)特別適合用來(lái)實(shí)現(xiàn)一些內(nèi)部的管理信息系統(tǒng).ExtJs提供了一套組件來(lái)開發(fā)類似于windows桌面的單頁(yè)面系統(tǒng),其中desktop桌面的開始菜單按照后臺(tái)提供的數(shù)據(jù)動(dòng)態(tài)生成也是一個(gè)難點(diǎn),下面將對(duì)desktop桌面動(dòng)態(tài)開始菜單的生成進(jìn)行介紹。

          ExtJs官方提供了desktop桌面的demo,其中關(guān)于開始菜單的生成是靜態(tài)的方式,在js腳本中設(shè)置好了固定的開始菜單內(nèi)容再生成開始菜單。<font color=red>本文的講解內(nèi)容均是在官方demo基礎(chǔ)上進(jìn)行的修改</font>

          整個(gè)需要改進(jìn)的腳本只有兩個(gè)一個(gè)是根目錄下的App.js以及BogusModule.js,前臺(tái)與后臺(tái)之間通過Ajax交互,數(shù)據(jù)交換個(gè)是為json

          后臺(tái)定義了Mids類,如下所示:

          public class Mids {
           private String mid; //菜單id
           private String text; //菜單名詞
           private String path; //菜單路徑
           private List<Mid> subs; //子菜單
           //Mid作為Mids內(nèi)部類
           public class Mid {
           private String mid;
           private String text;
           private String path;
           }
          }
          

          因此前后臺(tái)交互的json數(shù)組示例如下:

          [{mid:”m1”,text:”菜單1”,path:”/m1”,subs:null},{mid:”m2”,text:”菜單2”,path:”/m1”,subs:[mid:”m21”,text:”菜單21”,path:”/m21”}]

          接下來(lái)我們就要修改App.js這個(gè)js文件

           getModules : function(){
          // return [
          // //new MyDesktop.Blockalanche(),
          // //new MyDesktop.BogusMenuModule(),
          // //new MyDesktop.BogusModule()
          // 
          // ];
           return mArr;
          },
          //找到這段代碼并注釋掉部分行并修改為return mArr,其中mArr就是開始菜單模塊會(huì)在另一個(gè)js文件中定義
          

          下面我們就看核心的BogusModule.js這個(gè)文件,這個(gè)文件定義了開始菜單的生成方式和類型

          //首先需要定義一個(gè)模塊類型MyDesktop.BogusModule
          Ext.define(
           'MyDesktop.BogusModule',
           {
           extend: 'Ext.ux.desktop.Module',
           init:function () {},
           createWindow: function (obj) {
           var desktop=this.app.getDesktop();
           createWindow(desktop,obj);//該方法另外定義
           }
           });
          

          菜單數(shù)組以及Menu模型與后臺(tái)傳遞的json數(shù)據(jù)進(jìn)行綁定

          var mArr=[];
          Ext.define('Menu', {
           extend: 'Ext.data.Model',
           fields: ['mid', 'text', 'path','subs']
          });
          // 
          

          定義了一個(gè)store采用Ajax方式與后臺(tái)進(jìn)行是數(shù)據(jù)交互store進(jìn)行數(shù)據(jù)加載并實(shí)現(xiàn)開始菜單動(dòng)態(tài)加載和綁定,并且生成桌面

          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;
           //判斷是否有子菜單,有子菜單則設(shè)置為點(diǎn)擊無(wú)效
           if (r[i].data.subs) {
           mm.launcher={
           text: r[i].data.text,
           iconCls: 'bogus',
           handler: function () {
           //有子菜單則點(diǎn)擊無(wú)效
           return false;
           },
           menu: {items: []}
           };
           //遍歷子菜單數(shù)據(jù)并生成子菜單項(xiàng)
           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 {
           //沒有子菜單則設(shè)置點(diǎn)擊打開窗口
           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();
           });
           }
          }
          });
          

          定義對(duì)應(yīng)的打開窗口模塊,每個(gè)窗口模塊均內(nèi)嵌了一個(gè)iframe,通過該iframe可以加載其它頁(yè)面內(nèi)容

          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: '刷新窗口內(nèi)容',
           handler: function () {
           document
           .getElementById(iframeId).src=obj.src;
           }
           }, {
           text: '切換窗口大小',
           handler: function () {
           win.toggleMaximize();
           }
           }, {
           text: '關(guān)閉',
           handler: function () {
           win.close();
           }
           }]
           });
          }
          win.show();
          return win;
          }
          

          這樣就完成了ExtJs桌面的動(dòng)態(tài)開始菜單生成

          作者 | 張旭乾 責(zé)編 | 夢(mèng)依丹

          出品 | CSDN(id:csdnnews)

          前端和后端開發(fā),哪一個(gè)更容易上手?我們時(shí)常會(huì)在各大技術(shù)論壇看到類似的提問。話說興趣是最好的老師,不實(shí)踐,你可能很難知道自己更喜歡哪一個(gè)?

          從Java開發(fā)再到前端工程師,他在轉(zhuǎn)型路上遇到過哪些困難?本文作者張旭乾分享了他的轉(zhuǎn)型經(jīng)歷,以及他在學(xué)習(xí)前端開發(fā)過程中,遇到的問題和總結(jié)出來(lái)的一些經(jīng)驗(yàn),希望對(duì)你有所啟發(fā)。

          我的學(xué)習(xí)經(jīng)歷


          編程入門


          在 2008 年的時(shí)候,我進(jìn)入大專學(xué)習(xí) Java 開發(fā),HTML 和 CSS 只是專業(yè)的附屬品。那時(shí),主要還是前后端一體化開發(fā),HTML 和 CSS 只是為了結(jié)合 Java 里的 Servlet 生成頁(yè)面。JavaScript 則完全沒有講。

          2010 年快畢業(yè)的時(shí)候,我參加了五個(gè)月的 Java EE 培訓(xùn),在這期間了解了 HTML、CSS,以及一部分簡(jiǎn)單的 JavaScript DOM 操作和 jQuery,能夠編寫一些帶交互的頁(yè)面和 Ajax 異步請(qǐng)求。

          在這期間,我沒有太重視 HTML/CSS/JS 基礎(chǔ)。因?yàn)楸旧韯側(cè)腴T,并不知道哪些重要,哪些不重要。在做項(xiàng)目的時(shí)候,頁(yè)面部分要自己在網(wǎng)上搜索 HTML 標(biāo)簽和 CSS 屬性的用法。對(duì)于 JS 部分,則只會(huì) jQuery,高級(jí)的語(yǔ)法(例如閉包、原型鏈)完全沒有概念,只知道該怎么定義變量,處理事件,做一些基本的邏輯處理。



          順利轉(zhuǎn)正,還加薪10%


          我的第一份工作是 Java 開發(fā),當(dāng)時(shí)公司用的技術(shù)很新潮,算是前后端分離的雛形。頁(yè)面部分完全使用了 ExtJS 庫(kù),它提供了一組現(xiàn)成的 UI 組件,所有的數(shù)據(jù)都是通過 Ajax 來(lái)從后端獲取,后端則用 Java 的 Servlet 提供JSON 數(shù)據(jù)。

          這份工作的主要難點(diǎn)是一開始不了解前后端分離的開發(fā)模式。由于是第一次嘗試完全在客戶端 JS 去請(qǐng)求數(shù)據(jù),所以理解起來(lái)需要一點(diǎn)時(shí)間,當(dāng)時(shí)閱讀了 ExtJS 相關(guān)的文檔,才大體的了解到這種開發(fā)模式。基本上是利用 Ajax 請(qǐng)求數(shù)據(jù),然后通過它內(nèi)置的 API 來(lái)填充 UI。后面隨著開發(fā)的功能變多,對(duì)這種模式也適應(yīng)了。

          努力學(xué)習(xí)還是有回報(bào)的,過了三個(gè)月試用期之后,因?yàn)楣ぷ鞅容^出色,在拿到正式員工薪資的基礎(chǔ)上,又額外加薪了 10%。所以剛進(jìn)入公司的時(shí)候不要怕上不了手,主流的技術(shù)遇到不會(huì)的地方要善于自行查找資料解決,對(duì)于公司內(nèi)部的技術(shù)要勇于向前輩請(qǐng)教。


          自由職業(yè):實(shí)踐與進(jìn)階


          2010 年底從第一家公司離職,回到家里自己充電,學(xué)習(xí)了 PHP。因?yàn)楫?dāng)時(shí)建站非常流行,學(xué)了 PHP 既可以做個(gè)人站長(zhǎng),也可以通過自由職業(yè),為客戶建站來(lái)賺取收入。因?yàn)椴渴鹁W(wǎng)站的主機(jī)基本上都支持 PHP 和 ASP,而 PHP 更加流行,所以我就自學(xué)了 PHP,通過官方文檔,加上實(shí)戰(zhàn)并結(jié)合搜索引擎搜索問題來(lái)學(xué)習(xí)。學(xué)完了之后就在網(wǎng)上發(fā)了個(gè)廣告,提供個(gè)人建站服務(wù),此時(shí)的我還是全棧開發(fā)。

          2011 年底左右,廣告發(fā)完了我就忘了,沒把它太當(dāng)回事。大年初六突然收到一個(gè)客戶的電話,需要做一個(gè)網(wǎng)站,這讓我興奮不已。我給這位客戶一共做了兩個(gè)網(wǎng)站:

          • 一個(gè)是論壇,直接二次開發(fā)的,修改了一下樣式。

          • 一個(gè)是質(zhì)量保證查詢系統(tǒng),從零使用 PHP + MySQL + jQuery + jQuery UI 進(jìn)行開發(fā)。

          真正有挑戰(zhàn)的是第 2 個(gè)項(xiàng)目,頁(yè)面部分幾乎遇到了前端開發(fā)中全部常見的難題:

          JS 代碼管理

          當(dāng)時(shí) UI 部分選擇了和 jQuery 配套的 jQuery UI。jQuery UI 封裝了一組常見的 UI 組件,例如拖拽、對(duì)話框、按鈕等組件,可以少寫一些邏輯代碼。盡管如此,編寫出來(lái)的 JavaScript 文件還是亂七八糟,因?yàn)轫?yè)面上有很多表格組件,需要在獲取數(shù)據(jù)后,手動(dòng)去循環(huán)展示表格,并在刪除或修改的時(shí)候,還要修改 DOM 更新表格;另外還有其它邏輯,例如登錄、查詢等。

          雖然代碼分散在了不同的 JS 里,但是有的頁(yè)面因?yàn)闃I(yè)務(wù)邏輯比較復(fù)雜,加上當(dāng)時(shí)我也不太了解 JS 的復(fù)用方式和邏輯,導(dǎo)致了很多重復(fù)的代碼。我還有當(dāng)時(shí)的源代碼,可以感受一下代碼的長(zhǎng)度(兩張圖片為同一 JS 文件的不同部分,這里通過縮略圖展示):

          一個(gè) JS 文件中的代碼

          兼容性調(diào)整

          彼時(shí),瀏覽器主流的還是 IE,所以還是需要做一些兼容性調(diào)整。不過好在 jQuery 主打的就是兼容全部瀏覽器,所以 JS 方面沒有太大問題,剩下的就是 CSS。這個(gè)項(xiàng)目在 IE、Chrome、火狐下顯示的都不一致,后來(lái)查了一下,解決方法可以根據(jù)瀏覽器特定的語(yǔ)法,編寫只在特定瀏覽器能識(shí)別的 CSS 屬性,或者選擇器,也就是所謂的 CSS hacks。另外也可以使用瀏覽器特殊的 HTML 指令,加載不同的 CSS 文件,最終把頁(yè)面調(diào)成一致就可以了。

          性能調(diào)優(yōu)

          因?yàn)轫?xiàng)目頁(yè)面部分處理數(shù)據(jù)比較多,加上開發(fā)經(jīng)驗(yàn)有限,當(dāng)時(shí)也只是在代碼效率上進(jìn)行了優(yōu)化,例如減少不必要的循環(huán)操作等。

          與客戶溝通需求

          這個(gè)是開發(fā)的軟技能了,學(xué)會(huì)如何拒絕不合理的需求。因?yàn)楫?dāng)時(shí)我是第一次面對(duì)客戶,也沒有自信,所以客戶說改什么,我立刻就開始給他改。這期間客戶最常見的話術(shù)就是:“這個(gè)功能很簡(jiǎn)單,你做一下”,或者“這個(gè)問題很容易解決,花不了你幾分鐘”。當(dāng)時(shí)我真覺得功能或者問題挺簡(jiǎn)單的,但是實(shí)際操作起來(lái),發(fā)現(xiàn)要比想象的難多了。做了幾次之后,知道無(wú)論多簡(jiǎn)單的功能或問題,都會(huì)涉及很多的細(xì)節(jié),所以后面客戶再提要求的時(shí)候,我就把這些細(xì)節(jié)先說清楚,給他一個(gè)大概的完工時(shí)間,再加上新增的功能需要額外收費(fèi),客戶就會(huì)自己斟酌要不要做了。

          網(wǎng)頁(yè)設(shè)計(jì)水平

          還有一個(gè)意外,讓我學(xué)了一部分設(shè)計(jì)知識(shí)。在給這個(gè)客戶做質(zhì)量保證系統(tǒng)的時(shí)候,還要求附帶一個(gè)產(chǎn)品的官網(wǎng),客戶給我發(fā)了產(chǎn)品資料之后,我參考網(wǎng)上同品類的網(wǎng)站,幫他設(shè)計(jì)了一版,但是客戶以不夠大氣為由,讓我重新設(shè)計(jì),我又設(shè)計(jì)了一次,客戶還是覺得不夠好,反復(fù)幾次,似乎無(wú)法滿足他的需求,他就把官網(wǎng)這部分給別人做了。當(dāng)時(shí)我也有點(diǎn)憋氣,于是買了本《寫給大家看的設(shè)計(jì)書》,專門學(xué)習(xí)了一些設(shè)計(jì)原則,努力提高自己的設(shè)計(jì)能力。后來(lái)等客戶的官網(wǎng)上線之后,發(fā)現(xiàn)設(shè)計(jì)的也一般,大概是審美不同吧。

          在自由職業(yè)后半段時(shí)間學(xué)習(xí)了其它的框架,那個(gè)時(shí)候 Bootstrap 3、Foundation 之類的 HTML/CSS 框架開始爆火,因?yàn)槭窒矚g學(xué)習(xí)新的技術(shù),我就去看了看它們的介紹,看到 Bootstrap 3 內(nèi)置了很多組件,并且不怎么需要寫 CSS,就學(xué)了一下 Bootstrap 3。Bootstrap 3 內(nèi)部使用了 LESS 這個(gè) CSS 預(yù)編譯工具來(lái)生成 CSS,如果要自定義它的樣式,還需要會(huì) LESS。我就又看了一下 LESS 的文檔,發(fā)現(xiàn)它提供了很多實(shí)用的功能,例如變量、繼承、嵌套等,感覺很有意思也順便學(xué)了。

          從這里你就可以知道:前端庫(kù)是互相依賴的。如果直接看前端需要哪些庫(kù),那么零零散散的有一堆,但是當(dāng)你真的開始下手學(xué)習(xí)一個(gè)框架的時(shí)候,你會(huì)發(fā)現(xiàn)好多框架可以從一條線里牽出來(lái),構(gòu)成一個(gè)完整的開發(fā)工具庫(kù),這些自然就都掌握了。



          初識(shí) Vue


          前邊所有的經(jīng)歷,奠定了我轉(zhuǎn)型前端所需要的技術(shù)基礎(chǔ)。而在從事自由職業(yè)期間,我發(fā)現(xiàn)我還是喜歡看做得見的項(xiàng)目,從 0 設(shè)計(jì)界面,直至實(shí)現(xiàn)出來(lái),很有成就感,并且我也享受在設(shè)計(jì)過程中,靈感迸發(fā)的快樂,心底就有了想轉(zhuǎn)前端的火苗。不過第 2 份工作,從 2013 年到 2016 年,我仍然做的是 Java 開發(fā)。

          真正讓我對(duì)前端產(chǎn)生興趣,是 2016 年去留學(xué)之后。在 2017 年第一個(gè)學(xué)期,有同學(xué)問我 React 的問題,我不太會(huì),于是就上網(wǎng)幫同學(xué)查,查著查著,就發(fā)現(xiàn)前端已經(jīng)獨(dú)立作為一個(gè)職業(yè)了,再接著從 React 文檔找問題的解決方案時(shí),發(fā)現(xiàn)之前我用 jQuery 的問題在 React 中全部都解決了,可以不用手動(dòng)維護(hù)數(shù)據(jù)和 UI 之間的同步了,這讓我感到很欣慰,發(fā)誓等這學(xué)期放暑假,就深入學(xué)習(xí)一下。

          很快,暑假就到了,要兌現(xiàn)承諾開始學(xué)前端。當(dāng)時(shí)室友學(xué)了高級(jí) Web 編程,主要講的是 React,React 在那個(gè)時(shí)候還非常難用,應(yīng)該還是 React 15,需要手動(dòng)配置好多東西:Babel、Bower.js 之類的。看著室友遇到一個(gè)組件顯示不出來(lái),經(jīng)過一天的搜索解決方案,才發(fā)現(xiàn)是組件名大小寫不一致導(dǎo)致的,這個(gè)讓我有點(diǎn)對(duì) React 好感度降低,不想學(xué)了。

          后來(lái)我就研究了一下 Vue,發(fā)現(xiàn)普遍的說法是:功能和 React 類似,但是國(guó)內(nèi)用 Vue 的多,國(guó)外用 React 的多。看了下 Vue 是華人尤雨溪開發(fā)的,很佩服,據(jù)說上手比較容易,于是就決定先看看 Vue?

          在把 Vue 官方文檔基礎(chǔ)部分看完之后,結(jié)合 YouTube 的一些視頻所教授的開發(fā)方法,大概一周的時(shí)間,覺得可以上手了,就想了一下練習(xí)項(xiàng)目。當(dāng)時(shí)了解到 Vue 適合開發(fā)單頁(yè)應(yīng)用,看了一下單頁(yè)應(yīng)用的特點(diǎn),發(fā)現(xiàn)似乎就是網(wǎng)頁(yè)版 App 的概念? 于是,我就想著把當(dāng)時(shí)我用的最多的網(wǎng)易云音樂模仿一下。花了一周多的時(shí)間,實(shí)現(xiàn)了首頁(yè) UI、添加歌曲,播放、暫停、快進(jìn)、快退等功能,期間學(xué)會(huì)了 CSS flex 布局。

          使用 Vue 仿網(wǎng)易云音樂(左)的最終界面(右)

          后來(lái)發(fā)現(xiàn)網(wǎng)頁(yè)版的功能局限性比較大,想著能不能做成桌面端的。當(dāng)時(shí)室友在學(xué)校的課里學(xué) Electron,一個(gè)跨平臺(tái)的桌面開發(fā)框架,只用編寫 HTML? CSS 和 JavaScript ,就可以生成在 Mac、Windows、Linux 操作系統(tǒng)都能運(yùn)行的應(yīng)用。于是我又把應(yīng)用遷到了 Electron 上面。

          從 Electron 這里也了解到了,Node.js 到底和瀏覽器 JS 運(yùn)行時(shí)到底有什么不同:在 Node.js 的環(huán)境下,可以訪問更底層的操作系統(tǒng)級(jí) API,例如訪問本地文件,這樣可以方便用戶自行添加音樂。

          做這個(gè)項(xiàng)目的時(shí)候,也遇到了很多問題:

          • 不知道什么時(shí)候需要定義成組件剛剛接受這種組件化開發(fā)的方式之后,最大的難題就是怎么才知道該不該把一部分 UI 定義成組件。當(dāng)時(shí)的思路就是,我先把所有的頁(yè)面代碼都寫在入口組件里,后面再根據(jù)頁(yè)面的布局,把這個(gè)組件拆分成各個(gè)部分,例如側(cè)邊欄、播放列表、播放控制器等,這樣的分法似乎很合乎邏輯,不過這也帶來(lái)了一個(gè)問題。

          • 組件和數(shù)據(jù)雜糅到了一起。項(xiàng)目當(dāng)時(shí)使用了 Vuex,應(yīng)用的數(shù)據(jù)全部交給了它去管理,對(duì)于項(xiàng)目的功能邏輯,都是直接在相關(guān)的 UI 中實(shí)現(xiàn)的,并綁定了 vuex 的數(shù)據(jù)。例如播放進(jìn)度條,它和歌曲的播放時(shí)間數(shù)據(jù)綁定了,后面要實(shí)現(xiàn)音量進(jìn)度條的時(shí)候,發(fā)現(xiàn)這個(gè)組件無(wú)法復(fù)用。因此,我又把 UI 和數(shù)據(jù)分離了出來(lái),這樣的組件,可以在各處復(fù)用,之后再實(shí)現(xiàn)對(duì)應(yīng)的邏輯就好了。

          • CSS Flex 布局遇到坑。這個(gè)項(xiàng)目使用了當(dāng)時(shí)開始流行的 CSS Flex 布局,本著學(xué)習(xí)的態(tài)度使用它,遇到了很多問題,例如父容器對(duì) flex 縮放的影響,如何讓 flex 元素占滿容器,又或是如何讓 flex 不占滿容器等等,這些在看了 MDN 文檔的介紹,了解了 flex、align-items 和 justify-content 各個(gè)屬性值的作用和含義之后,就清楚了元素的縮放邏輯。

          通過這個(gè)小項(xiàng)目的開發(fā),對(duì) VUE 算是入門了,還得出了結(jié)論:

          學(xué)前端,或者任何編程知識(shí),一定要結(jié)合實(shí)踐才能快速入門并掌握它們。


          受挫轉(zhuǎn)型前端,嘗試 React


          學(xué)完 Vue 之后暑假差不多也快結(jié)束了,最后一個(gè)學(xué)期都在努力學(xué)專業(yè)課,沒有再看前端相關(guān)的東西。2018 年回國(guó)之后,開始找工作。因?yàn)榱魧W(xué)的主要方向是分布式和云計(jì)算,所以我還是想以 Java 開發(fā)為主。面試的時(shí)候遭到了很多不屑,大多是看我剛研究生畢業(yè),而以前的開發(fā)經(jīng)歷也沒什么出彩的地方,就都草草了事了。這些經(jīng)歷讓我很受打擊,但是讓我清楚的知道了,縱使有一肚子墨水,但是拿不出實(shí)際的產(chǎn)品,或者滿足不了面試官的喜好,就不可能面試成功。

          當(dāng)然我不會(huì)否定自己,最后一次面試失敗之后,突然就想要不要改行做一下前端,畢竟留學(xué)的時(shí)候鉆研了不少,又在自由職業(yè)的時(shí)候做過一些產(chǎn)品,更是有濃厚的興趣,于是我立刻下了決心轉(zhuǎn)前端。

          下定決心之后,我一刻也沒閑著,開始看前端的工作要求。在某招聘 App 上搜了一圈,發(fā)現(xiàn) React 在大廠用的多、工資也高一點(diǎn),我就又開始自學(xué) React,花了一周看了看官方文檔,寫了一個(gè)特別小的、只有一個(gè)頁(yè)面的小例子,之后就開始投簡(jiǎn)歷了。期間還看了看 React Router、Redux,以及 ES6 的新特性。

          在閱讀 React 官方文檔的時(shí)候,發(fā)現(xiàn)有一節(jié)是《Thinking in React》,里邊詳細(xì)的介紹了 React 組件化開發(fā)的步驟,并且解釋了什么時(shí)候需要定義組件,文檔提供了一個(gè)表格 UI 作為示例,把它拆解成了表格整體、搜索框、表格內(nèi)容、類別行和產(chǎn)品行組件,說明了為什么這么拆解,有沒有其它拆解的方法,以及拆解過程的方案折中,建議看一看。

          圖片來(lái)源:https://reactjs.org/docs/thinking-in-react.html


          面試后端頻繁受挫 正式轉(zhuǎn)型前端


          覺得準(zhǔn)備的差不多了之后,就開始投簡(jiǎn)歷了,大約 1 個(gè)月的時(shí)間,收到 3 家面試,只通過了 1 家。沒過的那兩家同樣也是見我剛畢業(yè),連前端開發(fā)經(jīng)驗(yàn)都沒有,就草草了事了。通過的這家,面試官是我工作時(shí)的技術(shù)總監(jiān)和組長(zhǎng),在面試的時(shí)候沒有刻意刁難,只是問了些框架方面的基礎(chǔ)問題,還問了一下我平時(shí)是怎么解決問題的。后來(lái),我在工作的時(shí)候,問他們?yōu)楹螞Q定讓我入職,他們告訴我,看中了我的學(xué)習(xí)能力。

          所以面試如果沒經(jīng)驗(yàn)的話,就努力說明自己的學(xué)習(xí)能力,總會(huì)有面試官欣賞你的。我到現(xiàn)在還非常感謝兩位,讓我正式進(jìn)入了前端開發(fā)的行列。

          進(jìn)了公司就開始了日常做項(xiàng)目,大大小小一共做了 3 個(gè),這期間經(jīng)歷了邏輯混亂期、嘗到甜頭期和精進(jìn)技術(shù)期,積累了大量的開發(fā)經(jīng)驗(yàn)。

          邏輯混亂期

          第 1 個(gè)項(xiàng)目,是改造一個(gè)傳統(tǒng)的項(xiàng)目,按技術(shù)總監(jiān)的建議,使用 React + dva.js 框架。UI 方面,項(xiàng)目之前用的是 Bootstrap,我用了 React Bootstrap 把項(xiàng)目遷移了過來(lái)。

          這個(gè)項(xiàng)目里遇到的問題是:代碼混亂。這個(gè)時(shí)期因?yàn)閯倓偵鲜?React 開發(fā),對(duì)于代碼的管理也沒有太大的概念,加上 dva.js 的項(xiàng)目結(jié)構(gòu)也不同于普通的 React 項(xiàng)目,所以這個(gè)項(xiàng)目開發(fā)起來(lái)有點(diǎn)麻煩,再加上項(xiàng)目的邏輯比較多,導(dǎo)致組件的代碼很長(zhǎng)很長(zhǎng),復(fù)用起來(lái)也很困難(俗稱面條式代碼),不過因?yàn)檫@個(gè)項(xiàng)目也不是完全對(duì)外公開的,并且使用頻率較低,所以就沒在優(yōu)化。

          嘗到甜頭期

          第 2 個(gè)項(xiàng)目,是做一個(gè)公司內(nèi)部用的運(yùn)營(yíng)管理后臺(tái),時(shí)間大約是 2018 年底,當(dāng)時(shí) React alpha 測(cè)試版出了 hooks。看了一下官方文檔,感覺很神奇,能夠清晰分離組件 UI 和邏輯,應(yīng)該能給代碼管理提供不小的幫助。雖然是測(cè)試版,但這個(gè)項(xiàng)目是完全對(duì)內(nèi)的后臺(tái)項(xiàng)目,所以果斷的用上了。

          這個(gè)項(xiàng)目的后端比較特殊,一位大佬同事搭建了 GraphQL 服務(wù),之前在留學(xué)的時(shí)候就已經(jīng)聽同學(xué)提到過很多遍了,現(xiàn)在有機(jī)會(huì)體驗(yàn)體驗(yàn)了。在看 GraphQL 官方文檔學(xué)習(xí)、以及使用搜素引擎搜索的時(shí)候發(fā)現(xiàn),使用 GraphQL 后可以不用 Redux,于是這個(gè)項(xiàng)目我只用了 React? React Router 和 Apollo-GraphQL 這幾個(gè)主要的庫(kù)。

          這套技術(shù)加上 React hooks,讓我真正感受到了前端開發(fā)的樂趣。組件從類的形式轉(zhuǎn)換成了函數(shù)形式,代碼量減少了很多,公共的邏輯也能抽離成 Hooks,在各個(gè)組件使用,組件自身的邏輯也能抽離成 hooks,來(lái)讓功能和 UI 展示代碼分開,讓代碼更易讀。這樣,整體的開發(fā)效率提高了不少。

          UI 方面則嘗試了 Ant Design,因?yàn)榧兒笈_(tái)的,沒有設(shè)計(jì)稿,只有產(chǎn)品原型。

          另外這個(gè)項(xiàng)目是基于 Create-React-App 腳手架創(chuàng)建,了解到腳手架提供的功能非常全面,像靜態(tài)資源(圖片、字體)管理、插件、打包構(gòu)建等都包括了,省了很多手工配置。

          精進(jìn)前端技術(shù)期

          第 3 個(gè)項(xiàng)目,是一個(gè)從 0 開始、面向客戶的應(yīng)用,UI 是由設(shè)計(jì)師專門設(shè)計(jì),有很多自定義的樣式。這是我積累最多前端開發(fā)經(jīng)驗(yàn)的項(xiàng)目,從技術(shù)選型,到組件規(guī)劃,再到代碼復(fù)用,對(duì)前端開發(fā)的架構(gòu)有了全新的認(rèn)識(shí)。

          樣式管理

          為了研究怎么在 React 項(xiàng)目中管理樣式最方便,我開始研究大型項(xiàng)目中的 CSS 樣式管理,了解到有普通 CSS 和 CSS-in-JS 兩種方案之后,再查資料發(fā)現(xiàn) CSS-in-JS 方案更靈活,能夠在 CSS 里訪問 JS 變量,讓組件樣式可以隨著組件狀態(tài)的變化而變化。

          決定用 CSS-in-JS 方案之后,我找到了 GitHub Star 數(shù)比較高的 styled-components 庫(kù),它支持 CSS 嵌套、主題等功能,并且能夠訪問組件的屬性,而且它定義的樣式,本身也是一個(gè) React 組件,可以直接在 JSX 中使用。

          UI 庫(kù)繼續(xù)使用了 Ant Design,不過也就是利用一下它的組件功能邏輯,樣式幾乎全部都修改了。

          全局狀態(tài)的取舍

          項(xiàng)目后端這次沒有用 GraphQL,我又發(fā)現(xiàn)不用 GraphQL 也沒必要使用 Redux,所以就沒有再添加 Redux,結(jié)果也證明我的選擇是對(duì)的:項(xiàng)目本身沒太多全局狀態(tài),舍棄 Redux 大概讓開發(fā)效率提升了 1 倍,之前像表單這樣的組件大概需要一天才能完成,現(xiàn)在只需要半天。不過項(xiàng)目里有個(gè)內(nèi)嵌的聊天系統(tǒng),需要用一點(diǎn)全局狀態(tài),我就從網(wǎng)上查找了一些解決方案,發(fā)現(xiàn)使用 React Context + useReducer Hooks 的方式實(shí)現(xiàn)全局狀態(tài)管理就夠了。

          提升學(xué)習(xí)能力

          這個(gè)項(xiàng)目使用的新框架都是一邊看官方文檔一邊學(xué)習(xí)的,有不好解決的問題,就結(jié)合搜索引擎和 GitHub Issues 解決。

          改良前端項(xiàng)目結(jié)構(gòu)

          對(duì)于項(xiàng)目的結(jié)構(gòu),這次使用了就近原則來(lái)組織代碼,每個(gè)組件放到單獨(dú)的文件夾中,組件相關(guān)的 styles、圖片、hooks 等都放在同一個(gè)文件夾,對(duì)于公用的部分,則放到項(xiàng)目頂級(jí)的 src 目錄下。API 和其它庫(kù)的配置項(xiàng)也都放到單獨(dú)的文件夾里,同樣遵循就近原則,這樣管理項(xiàng)目就方便多了。

          鍛煉溝通能力

          這個(gè)項(xiàng)目的圖表也比較多,為了和 App 端保持一致,選擇了 Echarts。在使用 Echarts 的時(shí)候,雖然能夠?qū)崿F(xiàn)大部分設(shè)計(jì)稿中的樣式,但是還是有小部分不能精準(zhǔn)還原,在拿著實(shí)際效果跟設(shè)計(jì)師溝通之后,有些樣式就做了些調(diào)整,或直接舍棄了。

          項(xiàng)目最后驗(yàn)收的時(shí)候,還需要跟 UI 設(shè)計(jì)師核對(duì)樣式,這期間我和設(shè)計(jì)師找了單獨(dú)的工位,每天都是在溝通哪里的設(shè)計(jì)需要修改,哪里的設(shè)計(jì)不好實(shí)現(xiàn),怎樣取一個(gè)大家都滿意的折中方案。這些在了解設(shè)計(jì)基礎(chǔ)原則之后,你也會(huì)明白設(shè)計(jì)師設(shè)計(jì)的意圖和用意,這樣用理解的心態(tài)來(lái)溝通,再輔以技術(shù)上的難度展示和時(shí)間需求,就能夠更好的避免不必要的 UI 改動(dòng)和代碼重構(gòu)。


          前端工程師的技能要求


          先看一下前端工程師需要掌握哪些技能。

          綜合大、中、小企業(yè)的前端工程師技能需求,實(shí)際上前端工程師的職能包含以下職業(yè)中的 1 種或多種:

          • 網(wǎng)頁(yè)開發(fā)工程師

          • 網(wǎng)頁(yè)設(shè)計(jì)師(UI)

          • 用戶體驗(yàn)工程師(UE)

          最重要的職能是網(wǎng)頁(yè)開發(fā),包括小程序、APP 等跨端應(yīng)用界面的開發(fā),雖然它們實(shí)現(xiàn)的技術(shù)不同,但本質(zhì)上還是做頁(yè)面。

          前端工程師必備的技能有

          • 使用 HTML + CSS,精準(zhǔn)地還原設(shè)計(jì)稿,制作符合要求的頁(yè)面。

          • 使用 JavaScript 給頁(yè)面添加交互,懂得 DOM 操作和 Ajax 請(qǐng)求。

          • 掌握 React 或 Vue 等主流框架的一種或幾種,并了解隨著這些框架的工程化,所牽涉的一系列工具(不同工程需要不同的工具,這里列出常見的), 例如:

            • Node.js 與 npm。

            • Webpack、SnowPack、Vite 等打包工具。

            • Create React App、Vue CLI、Vite 等腳手架。(Vite 既包含腳手架,也包含打包工具)

            • Gulp、Grunt 等自動(dòng)化工具。

            • SASS/LESS 等 CSS 預(yù)編譯工具。

            • styled-components、emotion 等 CSS-In-JS 庫(kù)。

            • ESLint 語(yǔ)法檢查工具。

            • Jest、mocha 等測(cè)試庫(kù)。

          • 兼容性調(diào)整,利用 CSS hacks,或 JS Polyfill,實(shí)現(xiàn)跨瀏覽器頁(yè)面表現(xiàn)一致。

          • 性能優(yōu)化,減少文件體積,減少請(qǐng)求次數(shù),延遲加載圖片和腳本等。

          • SEO 搜索引擎優(yōu)化,提高網(wǎng)站在搜索引擎的排名。

          其他的一些框架或技能,如果工作要求,也需要掌握:

          • SSR 服務(wù)端渲染框架,例如 Next.js(React)、Remix.js (React)、Nuxt.js(Vue)。

          • SSG 靜態(tài)網(wǎng)站生成器,例如 Next.js、Gatsby、VuePress 等。

          • TypeScript。

          • GraphQL。

          • PS/Sketch/Figma,能根據(jù)需要進(jìn)行切圖,或者自行設(shè)計(jì)頁(yè)面。

          下面這些技能不是必須的,但是如果能掌握,可以提高工作效率、跟后端或設(shè)計(jì)師溝通的能力,以提升求職升職的競(jìng)爭(zhēng)力:

          • 網(wǎng)頁(yè)設(shè)計(jì),了解設(shè)計(jì)基本原則。

          • 用戶體驗(yàn)設(shè)計(jì),了解網(wǎng)頁(yè)的動(dòng)效、輔助功能對(duì)用戶體驗(yàn)的影響。輔助功能(可訪問性)在國(guó)外比較重視,目的是方便有閱讀障礙的人士,使用屏幕閱讀器進(jìn)行網(wǎng)站瀏覽。如果你想去外企,這些技能是必須要掌握的。

          • Docker,了解如何把前端項(xiàng)目構(gòu)建為 docker image,會(huì)編寫簡(jiǎn)單的 docker file。

          • 后端語(yǔ)言、框架、數(shù)據(jù)庫(kù),任選一套,例如 Java + Spring + PostgreSQL,Express + Node.js + MongoDB 等,了解 RESTful API 開發(fā)過程。

          乍一看要掌握的有很多,但很多庫(kù)都是隨著 React、Vue 等最重要的前端庫(kù)自然而然地引入進(jìn)來(lái)的,大部分的用法都很簡(jiǎn)單,并且我們還會(huì)在工作中持續(xù)學(xué)習(xí),一開始只需要入門就行。下圖展示了 React 前端開發(fā)工程師,根據(jù) React 框架所衍生的技術(shù)棧(示意):

          React 前端工程師技能圖譜(示意)


          離職,做自己感興趣的事


          2019 年從公司再次離職,不想再打工了,借鑒在國(guó)外留學(xué)時(shí)所學(xué)到的經(jīng)驗(yàn),轉(zhuǎn)型開始做視頻和線上教學(xué),運(yùn)營(yíng)著“峰華前端工程師”賬號(hào),同時(shí)也在 CSDN 發(fā)表博客。在這期間還撰寫了《JavaScript 基礎(chǔ)語(yǔ)法詳解》一書。

          編寫書籍的時(shí)候,又是一次學(xué)習(xí)的過程,在查閱各種資料之后,對(duì) JavaScript 有了更完全的認(rèn)識(shí)。同時(shí)也明白了,人只有存在目標(biāo)的情況下,才會(huì)有動(dòng)力去完成看似不可能的事,避免渾渾噩噩度日。

          如果你像我一樣,也算比較大齡的程序員,有年齡焦慮,可以適當(dāng)?shù)南胂脒€要不要在公司里繼續(xù)工作下去,是不是該拿出勇氣來(lái)嘗試做自己真正想做的事,之后利用興趣養(yǎng)活自己。這不是一條容易的路,所以在決定之前一定要做好兩年之內(nèi)沒有起色的打算,這些如果我能總結(jié)出一套經(jīng)驗(yàn)之后,再來(lái)分享。


          學(xué)習(xí)建議


          這些大體就是我學(xué)習(xí)、掌握前端開發(fā)的過程,總結(jié)了下面這些重點(diǎn):

          1. 學(xué)會(huì)獨(dú)立學(xué)習(xí)。前端的框架太多了,并且經(jīng)常出現(xiàn)新奇特框架,必須要能自己獨(dú)立通過官方文檔和搜索引擎進(jìn)行學(xué)習(xí),因?yàn)榍岸丝蚣芏鄶?shù)比較小眾,不會(huì)有很多相關(guān)的教程。如果連文檔都沒有,就要學(xué)會(huì)讀源碼學(xué)習(xí)用法。

          2. 基礎(chǔ)打牢。前端庫(kù)雖然多,但萬(wàn)變不離其宗,總是要回歸到 HTML、CSS 和 JavaScript 上面,所以基礎(chǔ)一定要打牢,尤其是在 ES6 以后出現(xiàn)的新特性,在前端用途非常廣泛。

          3. 實(shí)戰(zhàn)練習(xí)。學(xué)完前端庫(kù)之后,一定要找個(gè)小項(xiàng)目做,把學(xué)到的東西真正地掌握。Github 上有很多前端項(xiàng)目靈感的庫(kù),可以搜索 “front-end project ideas" 找到 ,或者你也可以改造模仿市面上的網(wǎng)站、App 等。

          4. 不要把前端只局限在技術(shù)層面。向上往設(shè)計(jì)和產(chǎn)品擴(kuò)一下,向下從后端和運(yùn)維鉆一下,你會(huì)更能從整體角度觀望整個(gè)項(xiàng)目,從而在前端技術(shù)選型、開發(fā)過程以及和同事溝通的時(shí)候,懂得取舍和折衷。

          1. 線上文檔。對(duì)于 HTML、CSS 和 JavaScript 最權(quán)威的文檔就是 MDN。其它的像 React、Vue 等框架,就是官方文檔。如果遇到了問題,就去搜索引擎搜索,看其他人寫的解決方案。

          2. 書籍。對(duì)于體系化的教程,可以購(gòu)買相關(guān)的書籍看,重點(diǎn)看專業(yè)、經(jīng)典的書籍,這些網(wǎng)上有很多推薦。書籍可以幫助你快速入門并深入,不用在網(wǎng)上東找西找了。

          3. 視頻。現(xiàn)在視頻平臺(tái)正火爆,不要只用來(lái)消遣,上邊也會(huì)有很多編程相關(guān)的視頻,空余時(shí)間可以刷一刷,可能會(huì)獲得一些開發(fā)靈感、技巧,以及未來(lái)工作可能用到的新技能。

          4. 在線課程或培訓(xùn)。在線課程或者培訓(xùn)能幫你直接學(xué)到和就業(yè)相關(guān)的技能,積累項(xiàng)目實(shí)戰(zhàn)經(jīng)驗(yàn),但是要注意鑒別課程和機(jī)構(gòu)的質(zhì)量。

          5. 向有經(jīng)驗(yàn)的人學(xué)習(xí)。如果你看到有高級(jí)工程師發(fā)布的博客、微博、視頻等內(nèi)容,可以嘗試和他們建立聯(lián)系,拿出你學(xué)習(xí)的誠(chéng)意,讓他們幫你指點(diǎn)迷津,或許能少走一些彎路。

          END


          成就一億技術(shù)人


          主站蜘蛛池模板: 国产精品一区电影| 一区二区三区影院| 一区二区精品在线观看| 成人免费av一区二区三区| 精品一区二区三人妻视频| 精品无码综合一区| 狠狠综合久久av一区二区| 一本一道波多野结衣一区| 一区二区三区亚洲| 精品日韩在线视频一区二区三区 | 国产精品综合一区二区三区| 综合久久一区二区三区| 日本在线观看一区二区三区| 国产麻豆剧果冻传媒一区| 色综合久久一区二区三区| 国产成人一区二区三区| 亚洲中文字幕一区精品自拍| 亚洲国产AV一区二区三区四区| 色窝窝无码一区二区三区| 久久久久久人妻一区精品| 无码精品人妻一区二区三区人妻斩 | 国语精品一区二区三区| 国产在线精品一区二区三区不卡| 日韩av片无码一区二区三区不卡| 日韩AV无码一区二区三区不卡 | 国模私拍福利一区二区| 中文字幕AV无码一区二区三区| 亚洲av永久无码一区二区三区 | 国产伦精品一区二区三区视频猫咪| 亚洲美女视频一区二区三区| 日本免费一区二区三区最新| 亚洲国产综合精品中文第一区| 精品无码综合一区| 国产精品无码AV一区二区三区| 波多野结衣免费一区视频 | 无码人妻品一区二区三区精99| 久久久久人妻精品一区| AV鲁丝一区鲁丝二区鲁丝三区| 亚洲av无码一区二区三区在线播放| 国产一区二区好的精华液| 男人免费视频一区二区在线观看 |