亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

淺談angular4實際項目搭建總結

發布時間:2020-10-18 03:12:02 來源:腳本之家 閱讀:155 作者:子慕大詩人 欄目:web開發

前言

接到一個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',
}

//HomeModule
const 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大致代碼和實際頁面截圖:

淺談angular4實際項目搭建總結

淺談angular4實際項目搭建總結

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

淺談angular4實際項目搭建總結

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

淺談angular4實際項目搭建總結

目錄結構

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

淺談angular4實際項目搭建總結

使用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 xxS
xx.r.ts == xx.routes.ts | export class xxR
xx.m.ts == xx.module.ts | export class xxM
xx.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環境

淺談angular4實際項目搭建總結

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

淺談angular4實際項目搭建總結

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

//dev
export const environment = {
 production: false,
 apiBase: 'http://www.xx.com/'
};
//prod
export 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 打印日志查詢當前環境變量是否是我們需要的

淺談angular4實際項目搭建總結

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

淺談angular4實際項目搭建總結

結語

因為業務需求原因,太久沒真正學習搭建新框架了,心里也一直不踏實,感覺再不學點都跟不上時代了, 所以這次項目的機會也算是了卻自己一個心愿。 對比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,如下圖

淺談angular4實際項目搭建總結

淺談angular4實際項目搭建總結

在指令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轉換為對應文案。

淺談angular4實際項目搭建總結

一個報錯:

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編譯會報錯:

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

淺談angular4實際項目搭建總結

淺談angular4實際項目搭建總結

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

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

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

尼玛县| 涪陵区| 苍溪县| 宜君县| 青海省| 南江县| 夹江县| 临清市| 滨海县| 祁连县| 永城市| 连南| 石城县| 宁河县| 孝感市| 宜州市| 牙克石市| 宜城市| 雷山县| 杭锦旗| 金溪县| 永顺县| 柯坪县| 上虞市| 楚雄市| 洛扎县| 丹凤县| 城步| 瓮安县| 洛宁县| 柘荣县| 岢岚县| 和平区| 丰宁| 丹棱县| 石首市| 新民市| 河北区| 绩溪县| 柏乡县| 漳州市|