亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

淺談angular4實際項目搭建總結

2019-11-19 14:48:44
字體:
來源:轉載
供稿:網友

前言

接到一個pc端后臺項目,還會加入兩個安卓同事一起學習和做這個項目,需要帶一下他們。 既ng1之后,我就沒怎么有過其它后臺框架的實際項目經驗了,期間用的移動端框架也并非vue、angular系列、react,包括es6、webpack等也都并不熟悉。 公司一個其它后臺項目使用了vue,偶爾我會維護一下但是總體來說對體系不熟悉。 一直比較喜歡angular,應該是有過ng1框架搭建的經驗的原因(前面也有寫過博客),學習過ng2和ng4的官方demo,總的來說照著抄寫一遍意義不大,必須要用于實際項目才能真正吸收。 目前ng1肯定不要用了,我要重新熟悉和搭建一個架子,從自我喜好和前期一些基礎來講,ng4是最好的選擇,剛好typescript的語法對安卓同事也比較友好。 向領導請示了之后,也得到了允許。

入坑之初,問題一般比較多,使用的是官方angular-cli創建項目。 中途完善cli的功能,理解整個框架是比較費精力的事情。 總的來說這次就花了兩三天時間,梳理好了框架,配置好了一些基本功能和依賴,比如環境部署,路由嵌套,主頁面布局(側邊欄,導航欄,內容,底部),公共服務(loading,http請求封裝,全局服務title,用戶信息存?。?。 而后就直接和同事一起開發了。 最開始還有點沒底,不知道搭架子要花多久時間,現在來看這個進度和時間還是很滿意的,當然過程中參考了一些網上的同行分享的資源和代碼。 非常感謝兩位同事的積極支持,他們學習的也很快。

問題細節點

scss

angular-cli.json 設置 styleExt為scss之后,在組件里寫Styles,并不會編譯把scss編譯成css,必須要寫在獨立的scss,然后通過styleUrls引入。

routes path

routes path前面不能加 / 否則會報錯

const routes: Routes = [  { path: '', redirectTo: '/main', pathMatch: 'full' },  {    path: 'main',    component: MainComponent  },]

<router-outlet>

<router-outlet> 的意思是當通過路由訪問component的時候,component的selector會找到 <router-outlet></router-outlet> ,@Component定義的selector會直接生成一個標簽,載入到<router-outlet></router-outlet>下方,如果不設置selector標簽名就是默認的ng-component。

RouterModule

  1. forRoot creates a module that contains all the directives, the given routes, and the router service itself.
  2. forChild creates a module that contains all the directives and the given routes, but does not include the router service.

總的來說forRoot是定義一級路由,forChild是定義二級路由或者說是子路由。比如我們的引導模塊(命名一般是app.module.ts),也就是根模塊,里面注冊路由假設是 /main,就需要使用forRoot。根模塊通過forRoot注冊的路由/main,需要嵌套路由成為 /main/home,那home的module就需要用forChild去注冊路由。

routes的loadChildren屬性

ng4的提供了路由懶加載,如下,我們有個一級路由/main,/main有個二級路由/home對應home組件,我們可以通過,下面的方法來定義子模塊的路由和組件,但是這種寫法就需要把路由寫在一起,而我們希望home組件的路由是一個單獨的home.routes.ts文件存在于home文件夾中,通過在類似父模塊中引入子模塊的方式注冊home路由

{ path: 'main', compontent: MainComponent, children: [   {    path: 'home',    component: HomeComponent,   }  ] }

所以就要使用loadChildren,通過它來注冊子模塊和子路由,代碼如下。loadChildren會找到路徑文件app/home/home.module,#隔開,后面是exports的模塊名。 下面的HomeModule, 定義了home的路由和組件關系,因為是二級路由,所以這里用的是RouterModule.forChild,最后通過框架的處理,就達到了上面代碼里的 children 屬性的效果。 ps: 原本是訪問/main/home就會載入main和home組件,但是發現直接訪問路徑 /home 能直接載入home組件,似乎也注冊了一個根域名。 原來是使用了loadChildren之后,HomeModule模塊就已經被注冊了到main模塊下了,而我在AppModule里又通過imports注冊了一次HomeModule,這樣就重復注入了,而且還是一次和父模塊同級的注冊,這一點要小心。

{ path: 'main', compontent: MainComponet,//注意這里加載的是Main loadChildren: 'app/home/home.module#HomeModule',}//HomeModuleconst routes: Routes = [  { path: '', component: HomeCompontent}]@NgModule({declarations: [  HomeCompontent],imports: [  RouterModule.forChild(routes)],providers: []})export class HomeModule { }

總結一下上面的router相關內容 :

假設一個場景,根模塊注冊兩個路徑,一個是/login,一個是/main。/login這個路由訪問就是單純的一個登陸頁面,/main下面的路由都將是對應核心頁面和業務,因為在main組件里包含了公用的側邊欄、導航欄、內容容器和底部欄,所以 /main路由加載的main組件的內容容器里需要嵌套子模塊。 舉個實例,當我訪問/main/home的時候main組件會加載home組件到content容器中,當我訪問/main/manager,manager組件又會替換content中的home。這樣我們的公共頁面部分就是不變的main組件,根據子路由的變化,去加載不同的組件到content里。

以下是main組件的html大致代碼和實際頁面截圖:

這里也有一個知識點是<router-outlet>標簽的嵌套,上面的代碼中<div>下面有一個<router-outlet>標簽,home等二級組件會被載入到父組件main的<router-outlet>標簽下。而main組件的父組件是引導組件AppCompontent,所以main組件是通過一級路由被載入到AppCompontent的html模板的<router-outlet>下方,以下是AppCompontent組件部分代碼:

那么打開調試器,我們就能從dom節點上看清楚,router-outlet的嵌套關系:

目錄結構

再看下src的目錄結構,component文件夾是存放一些公共的組件,login和main組件是注冊的一級路由,home和另一個馬賽克組件是注冊為main的二級路由,實際后面會注冊很多組件到main下,但是他們的文件夾劃分都是同級。

使用hash路由

RouterModule.forRoot(routes, { useHash: true });使用hash路由,后端不用修改配置,這樣比較方便,省去很多麻煩

title

引入了platform-browser的Title,使用它的setTitle方法改標題

APP_BASE_HREF

在非hash路由情況下,有時候環境的原因布置靜態資源路徑的時候可能不是根域名,同時還要刪除index.html的<base>標簽,否則會有問題

import { APP_BASE_HREF } from '@angular/common';

在app.module里注冊providers: [{provide: APP_BASE_HREF, useValue: environment.publicBase}],

http

使用http相關API,需要注入HttpModule,否則會報錯: No provider for Http

import { HttpModule } from '@angular/http';

引入了三方JS,三方JS定義的全局變量,在引入到代碼里,編譯會報錯:沒有定義。需要在前面加個申明declare let thirdVar:any;

規范

文件命名service,component,route,module,主要類型的文件種類不多,每次新建文件命名太長,引入的時候也麻煩,所以除了根目錄命名保持xx.component.ts這種格式,其他文件統一為xx.c.ts,xx.s.ts。

xx.s.ts == xx.service.ts | export class xxSxx.r.ts == xx.routes.ts | export class xxRxx.m.ts == xx.module.ts | export class xxMxx.c.ts == xx.component.ts | export class xxC

bootstrap4

考慮引入boostrap4來作為css庫布局。

關于rem,我們一般用rem作為單位的時候,是更希望利用它的特性改變font-size達到自適應效果,會先定義一個font-size的范圍和對應的屏幕寬度范圍,根據設計稿的寬度得到一個基數,再用設計稿中元素的實際像素去除以基數得到rem,最后根據屏幕寬度動態設置font-size的相應值達到自適應效果。bootstrap4以瀏覽器字體默認大小16px,直接定義了元素的rem值,它的源碼里沒有任何計算,我想他們是參照16px來設置的元素大小,然后求出的rem值,當頁面根font-size的值是16px的時候,所有的bootstrap4的元素大小就是標準大小,如果我們想讓頁面的元素整體放大或者縮小,我們只需要去改變font-size的大小,font-size設置為多少,需要我們自己計算和定義規則。因為是三方庫,所以這塊的實現方法和我們自己實際項目使用rem的時候,會有些反差。

如果項目中引入了它,我們給自定義元素直接設置px值的話,就會出現問題,如果我們需要改變font-size的大小,就必須統一使用rem,否則font-size改變的時候,自定義的px元素并不會改變。那么自定義元素需要設置為rem值。

NG-ZORRO

想了想,需要快速開發,還是需要一個UI插件庫,自己去造輪子開發成本太高,經擼哥介紹,知道了螞蟻金服的ng庫ng-zorro,支持ng4,https://ng.ant.design。 看了下很全,還提供了柵格布局和按鈕樣式,轉眼一想,如果用bootstrap4,相互之間可能有沖突,比如boostrap的reset相關的,而且用boot的按鈕樣式和螞蟻的樣式可能看起來不搭調。所以我在引入ng-zorro之后,先注釋了對bootstrap4的引用,一些公用樣式,后面可以考慮自己寫。

部署打包

src目錄下有個environments文件夾,這里的文件是配置環境的,.angular-cli.json文件有配置兩個默認環境,一個是開發一個是發布環境,在我們開發的時候,默認選擇的是dev環境

在src下的main.ts里有這么一段代碼,這里的意思是切換到生產模式時禁用開發環境下特有的檢查(雙重變更檢測周期)來讓應用運行得更快。

我們在開發項目的時候,也必然需要配置開發,測試和生產環境,不同的環境的接口或者其他設置肯定是不一樣的。 我需要配置一個apiBase變量,代表不同環境的接口域名,在開發的時候ng4會運行ng serve在本地運行一個服務,域名是localhost,那么后端部署的接口肯定不在我們這個開發域名下,所以這個 apiBase 就是我們后端接口的域名 apiBase='http://www.xxxx.com' (需要后端支持跨域)。 當我們把打包好的代碼部署到QA或者生產環境后,訪問前端頁面的url和后端接口都在同一域名,所以 apiBase='/' 。 那么dev和prod的environment代碼分別如下:

//devexport const environment = { production: false, apiBase: 'http://www.xx.com/'};
//prodexport const environment = { production: true, apiBase: '/'};

angular-cli 創建的 environment.ts 里有一段注釋,如下圖。 意思是如果我們用 ng build 命令打包的時候,加上--env=prod(如果是自定義environment文件,必須是ng build --environment=xxx命令),將會把 environment.ts 替代為 environment.prod.ts ,那么 main.ts 里的代碼 import { environment } from './environments/environment'; 實際變成了import { environment } from './environments/environment.prod'; 可以通過在 main.ts 打印日志查詢當前環境變量是否是我們需要的

因此,我們就只需要把相應的環境變量配置好,如下API接口的代碼和 main.ts 文件一樣,我引入了 environment,在開發或者打包的時候,angular 配置的打包工具會自動載入相應的環境變量

結語

因為業務需求原因,太久沒真正學習搭建新框架了,心里也一直不踏實,感覺再不學點都跟不上時代了, 所以這次項目的機會也算是了卻自己一個心愿。 對比ng4和ng1,開發模式有了很大的變化,給我的感覺就是ng4的模塊劃分更干凈,寫法更舒服。 也可能是因為有一些angualr系列的基礎, 能力也應該比前年學習ng1的時候更強,這次入門很快。 es6和typescript語法有時候分不清誰是誰,落后的知識趁著這次盡快補起來。 因為新鮮感的原因,寫代碼變得更有樂趣了,在頁面細節和動畫上,稍微多搞了一點東西進去(后臺項目沒有設計師,自由發揮)。轉眼3個多月沒寫博客了,這之間學的新東西不多,但是回頭補了一下基礎的一些知識,也算是有很多收獲和新的理解。 設計模式的博客寫了一部分,后面會抽時間一步步完成,是一篇希望大家都能看懂的博客,盡請期待!

PS:這篇博客不定期更新,更新的寫到下面吧。

  1. [ngClass]="item.fromAccount == webimS.userId ? 'me':'other'" ,ngClass可以這樣寫,官網沒有這種示例
  2. 按照縮寫規則,指令directive我應該寫成xx.d.ts的,但是d.ts這個格式的文件似乎會被框架其他程序處理,就會報錯,所以指令的命名我就沒用d.ts這樣的縮寫了
  3. 指令在父模塊declarations之后,發現在子模塊里使用指令,根本沒有反應。折騰了很久,發現declarations申明的只在當前模塊才能使用,而我的懶加載的子模塊無效,所以為指令定義一個獨立的module,在需要使用指令的地方import這個module,如下圖

在指令directive中要拿到當前使用指令的dom,需要使用ViewContainerRef

import { Directive, EventEmitter, ViewContainerRef, AfterViewInit, OnDestroy} from '@angular/core';constructor(public viewContainerRef: ViewContainerRef) { }

如果我們需要拿到當前控制器下某個dom節點,需要使用@ViewChild

//compontent@ViewChild('xxx') xxx: ElementRef;getXXX(){  console.log(this.xxx)}//html<div #xxx></div>

表單驗證指令封裝

ng提供表單驗證 FormGroup 可以定義每個表單的驗證條件,定義好之后,需要在表單下面寫很多的ngIf dom來判斷和展示當前表單的錯誤填寫提醒,這樣很不好的一點是提醒的文字是需要占位置的,在處理頁面的時候需要兼容這些提醒文案,給他們做兼容布局(如果表單全部是獨立的一排一排的還好,如果一行里有很多表單,每個表單的寬度可能也不一樣,這時提醒文案就不好放了),而且每次寫那么多條件和dom真的很麻煩。

寫了一個指令組件,提醒文案作為彈出層展示出來,把當前表單的formControl對象傳入指令,把所有的條件統一文案,比如說required 文案為‘'必填‘'。那需要做4件事情,1:動態為指令里加入組件(參考了官網核心知識->模板與綁定->動態組件),2:讓組件絕對定位到表單右上角,需要用一個div包裹一下表單,并獲取表單的寬度,把寬度傳給組件,組件給提示框設置絕對定位。3:傳入formControl對象,指令組件需要判斷顯示隱藏,4:統一文案,條件滿足后給顯示框展示對應文案,因為formControl的errors是一個對象,所以需要配置一個管道pipe來把errors轉換為對應文案。

一個報錯:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'false'.

我寫的每一個指令都會有這個報錯,一般報錯在數據變化后觸發,網上查了一下,說是沒有使用 enableProdMode();方法就會觸發這個報錯,在main.ts中判斷了環境,如果是開發環境的話就不使用enableProdMode();方法,所以目前開發環境會報錯,但是也不影響邏輯,所以這個報錯暫時忽略

formreset:

一個頁面可能會有一個彈窗來填寫表單,填寫的時候有兩種狀態,編輯和新增,但是都是用的同一個彈窗對象,表單做了驗證、錯誤條件達到并且dirty屬性為true的時候,就會展示錯誤提醒。在新增和編輯切換的時候如果直接修改表單的值,dirty就會一直是true,就可能一直有錯誤提示。所以需要在一定情況下使用 formGroup 的 reset來重置表單,dirty就會是false了。每個表單自己也有reset方法。當使用formGroup重置表單的時候,textarea有可能并不會被重置,如果沒有被重置,需要單獨處理下textarea,給textarea的formControl對象單獨reset一下。

正式環境打包的檢查:

使用ng build --prod命令時,打包的檢查比較嚴格。開發時候使用的private定義可以在模板里使用對象,在開發環境就會報錯。一些模板里綁定的對象數據,是需要后端返回了數據才會傳值給對象,在打包的時候就會檢測到當前對象屬性不存在就無法通過,這時就不能用{{xxx.atrr}}這種形式輸出數據,得用{{xxx['attr']}}這種方式,才能跳過檢查。

某些情況使用this編譯會報錯:

直接上圖,圖一會報錯編譯無法通過,代碼邏輯是正確的。圖二能編譯通過

ng5出來后,我會把當前項目升級,到時候項目也比較完善了,我會抽出核心部分,分享到github上,敬請期待。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久国产一区二区三区| 91精品在线影院| 欧美成人免费全部观看天天性色| 搡老女人一区二区三区视频tv| 久久在精品线影院精品国产| 亚洲成人精品av| 久久人人爽人人爽爽久久| 久久久在线免费观看| 992tv成人免费影院| 成人网在线免费观看| 精品magnet| 国产在线观看91精品一区| 亚洲性xxxx| 亚洲影视九九影院在线观看| 一区二区国产精品视频| 欧美第一页在线| 日韩亚洲国产中文字幕| 国产日韩av高清| 久久精品99无色码中文字幕| 亚洲精品二三区| 久久99精品久久久久久青青91| 热re91久久精品国99热蜜臀| 欧美大片免费观看在线观看网站推荐| 成人欧美一区二区三区在线| 欧美有码在线视频| 色偷偷9999www| 97高清免费视频| 欧美专区中文字幕| 2019日本中文字幕| 国产日韩在线免费| 久久久久国色av免费观看性色| 亚洲风情亚aⅴ在线发布| 国产成人亚洲综合91精品| 成人乱色短篇合集| 欧美午夜激情视频| 国模极品一区二区三区| 91国语精品自产拍在线观看性色| 日韩在线一区二区三区免费视频| 91高潮在线观看| 精品久久久久久中文字幕一区奶水| 亚洲激情电影中文字幕| 揄拍成人国产精品视频| 欧美性理论片在线观看片免费| 色噜噜狠狠狠综合曰曰曰| 狠狠综合久久av一区二区小说| 欧美高清一级大片| 色一区av在线| 色妞欧美日韩在线| 国产精品成人va在线观看| 国产精品一区二区久久国产| www.亚洲一区| 伊人av综合网| 欧美一级视频在线观看| 国产精品∨欧美精品v日韩精品| 亚洲大尺度美女在线| 97精品国产97久久久久久免费| 欧美主播福利视频| 日韩欧美在线一区| 亚洲美女在线视频| 精品少妇v888av| 日韩欧美高清在线视频| 91九色单男在线观看| 成人免费看吃奶视频网站| 91wwwcom在线观看| 久久香蕉国产线看观看av| 亚洲欧美日韩国产中文| 亚洲欧美在线第一页| 不卡在线观看电视剧完整版| 亚洲丁香久久久| 欧美xxxwww| 国产亚洲精品久久久| 欧美裸身视频免费观看| 国产主播精品在线| www.午夜精品| 久久精品国产欧美激情| 麻豆国产va免费精品高清在线| 国产精品一区二区三区久久久| 欧美激情啊啊啊| 国自产精品手机在线观看视频| 久久国产精品免费视频| 不卡av电影院| 伊人久久久久久久久久久久久| 欧美国产高跟鞋裸体秀xxxhd| 日韩精品极品在线观看| 第一福利永久视频精品| 欧美一级大片在线观看| 国产ts一区二区| 国产精品福利片| 欧美理论电影在线播放| 91九色单男在线观看| 国产精品视频永久免费播放| 欧美久久久精品| 亚洲成人精品视频在线观看| 久久久久久久影视| 92版电视剧仙鹤神针在线观看| 亚洲女同性videos| 黑人精品xxx一区| 日韩av在线不卡| 亚洲免费精彩视频| 国产精品国产三级国产专播精品人| 国产精品中文字幕在线| 欧美丰满片xxx777| 欧美网站在线观看| 日本中文字幕成人| 国产精品午夜国产小视频| 国内精久久久久久久久久人| 亚洲一区制服诱惑| 这里只有精品在线播放| 琪琪第一精品导航| 欧美性xxxxx极品娇小| 欧美xxxx14xxxxx性爽| 精品国产乱码久久久久久婷婷| 国内免费精品永久在线视频| 精品福利一区二区| 91在线观看免费高清完整版在线观看| 日韩专区在线播放| 亚洲欧洲一区二区三区久久| 国内免费精品永久在线视频| 国产欧美日韩免费| 久久精品亚洲94久久精品| 欧美人在线视频| 久久久久久久久久国产精品| 欧美电影免费播放| 亚洲人成在线一二| 国产一区二区三区在线观看视频| 海角国产乱辈乱精品视频| 91国产中文字幕| 成人欧美在线视频| 欧洲日本亚洲国产区| 久久精视频免费在线久久完整在线看| 中文日韩在线观看| 国产精品久久久久久av下载红粉| 亚洲免费人成在线视频观看| 国产成人精品久久| 欧美电影免费观看高清| 中文字幕成人精品久久不卡| 国产欧美日韩中文| 亚洲男人天堂视频| 亚洲国产婷婷香蕉久久久久久| 国内精品小视频| 国产成+人+综合+亚洲欧美丁香花| 日韩高清免费在线| 亚洲美女中文字幕| 亚洲精品一区二区三区婷婷月| 亚洲一区二区久久| 91精品视频在线| 欧美一级大片在线免费观看| 国产精品91久久| 欧美激情在线观看视频| 亚洲mm色国产网站| 成人午夜在线视频一区| 国产国产精品人在线视| 97视频人免费观看| 青青草99啪国产免费| 欧美日韩成人免费| 国产成人在线亚洲欧美| 国产亚洲综合久久| 91深夜福利视频| 国产精品香蕉国产| 国内精品视频久久| 2018中文字幕一区二区三区| 青青在线视频一区二区三区| 永久免费看mv网站入口亚洲| 亚洲人午夜色婷婷|