首頁 web前端 js教程 angular4實際專案建置詳解

angular4實際專案建置詳解

Jan 05, 2018 am 10:36 AM
搭建 詳解

本文主要介紹了淺談angular4實際專案建置總結,小編覺得蠻不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望能幫助大家。

前言

接到一個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
  },
]
登入後複製

的意思是當透過路由存取component的時候,component的selector會找到 ,@Component定義的selector會直接產生一個標籤,載入到< /router-outlet>下方,如果不設定selector標籤名稱就是預設的ng-component。

RouterModule

  1. forRoot creates a module that contains all the directives, the given routes, and the router service itself.

######################################################################################################## #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大致代码和实际页面截图:

这里也有一个知识点是标签的嵌套,上面的代码中

下面有一个标签,home等二级组件会被载入到父组件main的标签下。而main组件的父组件是引导组件AppCompontent,所以main组件是通过一级路由被载入到AppCompontent的html模板的下方,以下是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的标签,否则会有问题

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环境

在src下的main.ts里有这么一段代码,这里的意思是切换到生产模式时禁用开发环境下特有的检查(双重变更检测周期)来让应用运行得更快。

我们在开发项目的时候,也必然需要配置开发,测试和生产环境,不同的环境的接口或者其他设置肯定是不一样的。 我需要配置一个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 打印日志查询当前环境变量是否是我们需要的

因此,我们就只需要把相应的环境变量配置好,如下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
<p #xxx></p>
登入後複製

表单验证指令封装

ng提供表单验证 FormGroup 可以定义每个表单的验证条件,定义好之后,需要在表单下面写很多的ngIf dom来判断和展示当前表单的错误填写提醒,这样很不好的一点是提醒的文字是需要占位置的,在处理页面的时候需要兼容这些提醒文案,给他们做兼容布局(如果表单全部是独立的一排一排的还好,如果一行里有很多表单,每个表单的宽度可能也不一样,这时提醒文案就不好放了),而且每次写那么多条件和dom真的很麻烦。

写了一个指令组件,提醒文案作为弹出层展示出来,把当前表单的formControl对象传入指令,把所有的条件统一文案,比如说required 文案为‘'必填‘'。那需要做4件事情,1:动态为指令里加入组件(参考了官网核心知识->模板与绑定->动态组件),2:让组件绝对定位到表单右上角,需要用一个p包裹一下表单,并获取表单的宽度,把宽度传给组件,组件给提示框设置绝对定位。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编译会报错:

直接上图,图一会报错编译无法通过,代码逻辑是正确的。图二能编译通过

相关推荐:

angular4实现tab栏切换的方法分享

Angular4绑定html内容出现警告如何解决

Angular4表单响应功能示例分析

以上是angular4實際專案建置詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1670
14
CakePHP 教程
1428
52
Laravel 教程
1329
25
PHP教程
1276
29
C# 教程
1256
24
C++中的眾數函數詳解 C++中的眾數函數詳解 Nov 18, 2023 pm 03:08 PM

C++中的眾數函數詳解在統計學中,眾數指的是一組資料中出現次數最多的數值。在C++語言中,我們可以透過寫一個眾數函數來找出任意一組資料中的眾數。眾數函數的實作可以採用多種不同的方法,以下將詳細介紹其中兩種常用的方法。第一種方法是使用哈希表來統計每個數字出現的次數。首先,我們需要定義一個哈希表,將每個數字作為鍵,出現次數作為值。然後,對於給定的資料集,我們遍

Win11管理員權限取得詳解 Win11管理員權限取得詳解 Mar 08, 2024 pm 03:06 PM

Windows作業系統是全球最受歡迎的作業系統之一,其新版本Win11備受矚目。在Win11系統中,管理員權限的取得是一個重要的操作,管理員權限可以讓使用者對系統進行更多的操作和設定。本文將詳細介紹在Win11系統中如何取得管理員權限,以及如何有效地管理權限。在Win11系統中,管理員權限分為本機管理員和網域管理員兩種。本機管理員是指具有對本機電腦的完全管理權限

Oracle SQL中的除法運算詳解 Oracle SQL中的除法運算詳解 Mar 10, 2024 am 09:51 AM

OracleSQL中的除法運算詳解在OracleSQL中,除法運算是一種常見且重要的數學運算運算,用來計算兩個數相除的結果。除法在資料庫查詢中經常用到,因此了解OracleSQL中的除法運算及其用法是資料庫開發人員必備的技能之一。本文將詳細討論OracleSQL中除法運算的相關知識,並提供具體的程式碼範例供讀者參考。一、OracleSQL中的除法運算

C++中的取餘函式詳解 C++中的取餘函式詳解 Nov 18, 2023 pm 02:41 PM

C++中的取餘函數詳解在C++中,取餘運算子(%)用於計算兩個數相除的餘數。它是一種二元運算符,其運算元可以是任何整數型別(包括char、short、int、long等),也可以是浮點數型別(如float、double)。取餘運算子傳回的結果與被除數的符號相同。例如,對於整數的取餘運算,我們可以使用以下程式碼來實作:inta=10;intb=3;

linux系統呼叫system()函數詳解 linux系統呼叫system()函數詳解 Feb 22, 2024 pm 08:21 PM

Linux系統呼叫system()函數詳解系統呼叫是Linux作業系統中非常重要的一部分,它提供了一種與系統核心互動的方式。其中,system()函數是常用的系統呼叫函數之一。本文將詳細介紹system()函數的使用方法,並提供對應的程式碼範例。系統呼叫的基本概念系統呼叫是使用者程式與作業系統核心互動的一種方式。使用者程式透過呼叫系統呼叫函數來請求作業系統

PHP模運算子的作用及用法詳解 PHP模運算子的作用及用法詳解 Mar 19, 2024 pm 04:33 PM

PHP中的模運算子(%)是用來取得兩個數值相除的餘數的。在本文中,我們將詳細討論模運算子的作用及用法,並提供具體的程式碼範例來幫助讀者更好地理解。 1.模運算子的作用在數學中,當我們將一個整數除以另一個整數時,就會得到一個商和一個餘數。例如,當我們將10除以3時,商數為3,餘數為1。模運算子就是用來取得這個餘數的。 2.模運算子的用法在PHP中,使用%符號來表示模

Linux的curl指令詳解 Linux的curl指令詳解 Feb 21, 2024 pm 10:33 PM

Linux的curl命令詳解摘要:curl是一種強大的命令列工具,用於與伺服器進行資料通訊。本文將介紹curl指令的基本用法,並提供實際的程式碼範例,幫助讀者更好地理解和應用該指令。一、curl是什麼? curl是命令列工具,用於發送和接收各種網路請求。它支援多種協議,如HTTP、FTP、TELNET等,並提供了豐富的功能,如檔案上傳、檔案下載、資料傳輸、代

numpy版本查詢方法詳解 numpy版本查詢方法詳解 Jan 19, 2024 am 08:20 AM

Numpy是一款Python科學計算庫,提供了豐富的陣列操作函數與工具。升級Numpy版本時需要查詢目前版本以確保相容性,本文將詳細介紹Numpy版本查詢的方法,並提供具體的程式碼範例。方法一:使用Python程式碼查詢Numpy版本使用Python程式碼可以輕鬆查詢Numpy的版本,以下是實作方法和範例程式碼:importnumpyasnpprint(np

See all articles