Angular开发常见问题

摘要

现在的前端发展可以说是日新月异,新技术、新东西层出不穷。新技术、新东西的出现带来的变化便是开发模式的转变。传统的开发模式已经慢慢地被前后端分离模式所取代。正是这种开发模式的转变,使得前端开发人员要学习的东西越来越多,技术水平要求也越来越高。

现在的前端发展可以说是日新月异,新技术、新东西层出不穷。新技术、新东西的出现带来的变化便是开发模式的转变。传统的开发模式已经慢慢地被前后端分离模式所取代。正是这种开发模式的转变,使得前端开发人员要学习的东西越来越多,技术水平要求也越来越高。

纵观前端的发展历程:jQuery处理了浏览器的兼容性问题,方便了DOM操作;Angular、Vue、React以MV*模式取代了传统的DOM操作,以数据驱动视图,极大的提高了页面性能。以目前的发展趋势来看,MV*模式将会成为未来前端发展的主流方向。

使用angular-cli开发的同学,笔者建议使用最新稳定版的VS Code,原因如下:

1、一款好的编辑器能极大提高工作效率,这就是我们常说的:工欲善其事,必先利其器。

2、angular是基于TypeScript开发的,而TypeScript又是微软出的,VS Code也同样是微软的产品,合理的配置后可以让其完美支持TypeScript。

WebStorm卡顿问题解决方案

在用vue-cli开发时,笔者建议这样解决WebStrom卡顿问题:

File -> Setting -> Editor -> File types -> Ignore files and folders
在Ignore files and folders最后加上node_modules;保存就可以了,然后重启WebStorm一切就将改变。

经过笔者测试,上面的方法对于用angular-cli开发的项目会出现报错提示。因此,笔者找到了一种通用的方式(推荐方法1)。

1、打开一个没有安装过依赖的项目后,并在该项目中新建一个安装依赖的文件夹(多为node_modules),然后该文件夹上右键选择Mark Directory As -> Excluded即可。再然后安装依赖就可以了。

2、如果打开的是一个安装过依赖的项目,很有可能第一次打开会很慢,打开会再进行右键选择Mark Directory As -> Excluded依然可以让之后开起的速度提供。

使用WebStrom的开发人员,建议装一个Angular 2 TypeScript Live Templates的插件,此插件可以获得更多的angular语法提示,提高开发效率。

特别说明,以下是针对angular2+总结的问题,部分通用于angularJS

提醒:npm install等价于npm i,--save等价于-S,--save-dev等价于-D。一个是完整命令,一个是快捷命令。npm cache clean的别名为npm cache clear和npm cache rm。

使用angular-cli构建angular项目

理由:angular-cli用于快速构建angular的应用。它的优点是进一步屏蔽了很多配置的步骤、自动按官方推荐的模式进行代码组织、自动生成组件/服务等模板以及更方便的发布和测试代码。

特别说明:$符号是某些类DOS系统特有的,后面才是真正的执行命令(敲入$之后的命令即可),很多新手都会在这里犯错。

1、安装Node最新版本(推荐使用LTS版,该版本为长期稳定版)

2、替换npm为淘宝镜像(如无必要,尽量不要使用镜像)

---->卸载cnpm命令(npm uninstall cnpm -g),此条只针对全局安装过cnpm的人

注:打开DOS面板,执行npm config set registry https://registry.npm.taobao.org

如果想恢复默认,打开DOS面板,执行npm config set registry https://registry.npmjs.org

特别说明:替换npm为淘宝镜像原因是因为npm在国内访问不太稳定。当然,如果你的网络访问npm没问题,可忽略这步;

特别强调:淘宝镜像和cnpm是不一样的,这里设置的是淘宝镜像而不是cnpm。经过笔者多次踩坑和血淋淋的教训得出的结论——珍爱生命,远离cnpm

3、安装angular-cli(建议先清一下缓存:npm cache clean)

npm install @angular-cli -g

4、初始化项目

ng new ngx-demo

注:此处的ngx-demo为项目名,可以根据需要进行修改。如果要生成一个带有路由的angular项目,可以使用ng new ngx-demo --routing命令。

angular4发布后,新的命名也随之出现。大家习惯以ngx-作为前缀来区别angular2和angularJS

你可以使用下面的命令快速初始化一个使用SCSS且带有路由的项目:

ng new ngx-demo --routing --style=scss

5、项目初始化完成后,进行项目文件夹,安装依赖即可

angular项目中使用Scss/Stylus/Less

angular-cli默认就支持Scss/Stylus/Less,你唯一要做的就是把文件后缀由css变为对应的即可。

初始化使用Scss的项目,执行如下命令即可

ng new ng-demo --style=scss

初始化使用Stylus的项目,执行如下命令即可

ng new ng-demo --style=styl

初始化使用Less的项目,执行如下命令即可

ng new ng-demo --style=less

angular项目中引入jQuery和Bootstrap

引入其它第三方JS步骤类似

1、npm安装jQuery和Bootstrap

npm install jquery bootstrap -S

2、npm安装jquery的TypeScript类型声明文件

npm install @types/jquery -S

3、修改angular-cli.json文件

  1. "styles": [
  2.     "styles.css",
  3.     "../node_modules/bootstrap/dist/css/bootstrap.css"
  4. ],
  5. "scripts": [
  6.     "../node_modules/jquery/dist/jquery.min.js",
  7.     "../node_modules/bootstrap/dist/js/bootstrap.min.js"
  8. ]

4、修改tsconfig.app.json文件

  1. "types": ["jquery"]

注:请使用npm执行上面的步骤,切勿使用cnpm、切勿使用cnpm、切勿使用cnpm。如果npm安装无法安装,可以使用淘宝镜像——淘宝镜像和cnpm是不一样的,设置淘宝镜像可以参考文章开头部分。

npm安装依赖报错

当我们使用npm安装依赖时,很多时候会出现一堆报错。报错的原因是多数是因为在node scripts/install阶段会从github上下载一个.node文件。而GitHub Releases里的文件都托管在s3.amazonaws.com上面,而这个托管网址在国内访问极度不稳定的,所以当依赖包含有node-sass、 electron、phantomjs等依赖时会报错。

解决方法:

在C:\Users\Administrator目录下找 一个为.npmrc的文件(没有可以自己新建一个),打开该文件并添加对应包的淘宝镜像即可(第四行代码是将npm默认地址替换为淘宝镜像,如果已经设置 过淘宝镜像只须添加对应报错依赖项即可,笔者给出常见报错依赖项的淘宝镜像,推荐这三项都添加进去)。然后删除项目的node_modules文件夹,重新安装依赖(建议安装依赖前执行一下清除npm缓存操作:npm cache clean)。

  1. sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
  2. electron_mirror=https://npm.taobao.org/mirrors/electron/
  3. phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/
  4. registry=https://registry.npm.taobao.org

启动项目,端口被占用

排除一些软件默认使用指定端口的情况外,最大的可能性是之前有用Node运行过其它项目导致端口被占用。如果是后面这种情况,最简单的方法就是通过任务管理器结束掉所有Node进程,然后再执行项目启动命令即可。

当然,如果你喜欢折腾,你也可以去修改webpack的配置文件来更改默认的端口,然后再执行项目启动命令即可。相比这种方式,笔者更推荐通过任务管理器结束掉所有Node进程的方式。

*ngIf和*ngFor报错

在vue中,我们可以在v-for上的元素上同时使用v-if,但是在angular中,官方明确表明同一个元素上不能使用多个指令。既然官方这样说了,那么肯定有解决方法。要解决这个问题其实并不难,我们可以借用指定的嵌套来实现。

对于*ngFor命令,我们可以借助ng-container标签,这个标签并不会在页面中渲染出来,所以我们可以放心的用。

代码如下:

  1. <ng-container *ngFor="let item of [1, 2, 3]; let index = index;">
  2.   <div *ngIf="index % 2">{{item}}</div>
  3. </ng-container>

angular如何实现绑定某个class后,同时在根据条件进行class绑定

用过vue的人都知道,在vue中绑定class有一种数组中使用对象的写法,但是这种方式目前在angular中是不支持。看过angular文档的人应该都知道,官网并没有提供一种特别好的解决方式。对于习惯了这种写法的人来说就是一种痛苦。因此我们只能另辟蹊径了——借助三元表达式。经过笔者测试,这种方式angular是支持的(vue也是支持的),所以我们可以大胆的使用这种方式来解决class绑定问题。

angular如何启动hash模式

当我们要开发的项目是运行到微信中的,笔者建议使用hash模式,这样可以在微信中少踩不少坑。

笔者提供两种方法(推荐使用方法一):

方法一(针对初始化时带有路由的项目):

具体配置如下(此配置是在app-routing.module.ts中进行的):

只需要找对位置,添加{ useHash: true }即可

  1. @NgModule({
  2.   imports: [RouterModule.forRoot(routes , { useHash: true })],
  3.   exports: [RouterModule]
  4. })

方法二:

具体配置如下(此配置是在app.module.ts中进行的):

  1. // 引入相关服务
  2. import {HashLocationStrategy, LocationStrategy} from '@angular/common';
  3. // 在@NgModule中的配置如下 | 服务依赖注入
  4. providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]

angular导入字体文件报错

由于angular-cli和vue-cli初始化的项目结构和配置不一样,所以我们不能用vue-cli那种在main.js里导入全局样式的方法。

angular中正确的做法应该是在angular-cli.json中导入。

笔者把全局要用样式放到了app/common下(common文件夹里面分别是fonts、js、scss文件夹),所以可以这样配置angular-cli.json文件。

  1. "styles": [
  2.     "styles.scss",
  3.     "./app/common/scss/index.scss"
  4. ]

angular项目中如何实现路由缓存

相信很多朋友和笔者一样,都对vue中的keep-alive设计拍案叫绝。如此一个简单的问题在angular项目中实现起来确非易事。笔者给出一种解决方法,希望对要在angular项目中实现类似vue的keep-alive效果的你有所帮助。

将下列代码保存为app-routing.cache.ts文件并保存在app文件夹下

  1. import { RouteReuseStrategy, DefaultUrlSerializer, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';
  2. export class AppRoutingCache implements RouteReuseStrategy {
  3.   public static handlers: { [key: string]: DetachedRouteHandle } = {};
  4.   // 表示对路由允许复用
  5.   public shouldDetach(route: ActivatedRouteSnapshot): boolean {
  6.     // 默认对所有路由复用 可通过给路由配置项增加data: { keep: true }来进行选择性使用,代码如下
  7.     // if (!route.data.keep) {
  8.     //   return false;
  9.     // }
  10.     return true;
  11.   }
  12.   // 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象
  13.   public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
  14.     AppRoutingCache.handlers[route.routeConfig.path] = handle;
  15.   }
  16.   // 若path在缓存中有的都认为允许还原路由
  17.   public shouldAttach(route: ActivatedRouteSnapshot): boolean {
  18.     return !!route.routeConfig && !!AppRoutingCache.handlers[route.routeConfig.path];
  19.   }
  20.   // 从缓存中获取快照,若无则返回null
  21.   public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
  22.     if (!route.routeConfig) {
  23.       return null;
  24.     }
  25.     return AppRoutingCache.handlers[route.routeConfig.path];
  26.   }
  27.   // 进入路由触发,判断是否同一路由
  28.   public shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
  29.     return future.routeConfig == current.routeConfig;
  30.   }
  31. }

然后在app.module.ts中添加如下代码:

  1. import { RouteReuseStrategy } from '@angular/router';
  2. import { AppRoutingCache } from './app-routing.cache';

修改app.module.ts中的providers: []为如下

  1. providers: [{ provide: RouteReuseStrategy, useClass: AppRoutingCache }]

采用以上默认设置,则实现整个项目的缓存,如果我们要进行针对性的缓存,可以在配置路由每项时加一个data: {keep: true}的选项,然后在app-routing.cache.ts打开对应注释掉的代码即可。

具体实现可以参考ngx-eleme项目

dist文件部署后刷新出现404问题

文件部署到服务器后,直接访问没有问题,但是刷新当前页后出现404问题。出现这个问题,99.99%是因为使用了默认路由配置(angular默认用history模式)。使用history模式,在开发环境不会出现刷新后404问题。但是,部署到服务器环境是需要对服务器做相关配置的。

解决方案:找到对应的服务器,把对应的代码放到对应的位置即可

  1. # Apache代码,加入到网站的.htaccess里,没有该文件,自己可以新建一个
  2. <IfModule mod_rewrite.c>
  3.   RewriteEngine On
  4.   RewriteBase /
  5.   RewriteRule ^index\.html$ - [L]
  6.   RewriteCond %{REQUEST_FILENAME} !-f
  7.   RewriteCond %{REQUEST_FILENAME} !-d
  8.   RewriteRule . /index.html [L]
  9. </IfModule>
  10. # Tomcat代码,加入到网站的web.xml里,没有该文件,自己可以新建一个
  11. <web-app>
  12.   <error-page>
  13.     <error-code>404</error-code>
  14.     <location>/index.html</location>
  15.   </error-page>
  16. </web-app>
  17. # Nginx代码,加入到网站的nginx.conf里,没有该文件,自己可以新建一个
  18. location / {
  19.   try_files $uri $uri/ /index.html;
  20. }

如何将打包好的文件放到指定目录

很多时候,我们因为某些原因不能将打包好的dist文件夹里的东西直接放到网站根目录(多数为www目录),而需要放到一个指定的文件夹,这里笔者以demo文件夹为例。因此,我们的访问路径就变为类似这样的地址:www.***.com/demo/。

对于这样的操作,angular-cli并没有提前帮我们做相关处理。如果我们采用默认配置,直接将打包好的dist文件夹里的东西上传到demo文件夹,将无法达到我们预期的效果。

此方法针对使用angular-cli初始化的模板,其它模板未经测试。

要想实现将打包好的文件放到指定目录非常简单,只需要我们简单修改一下index.html文件即可,此配置不会影响本地开发。

将index.html文件里默认的<base href="/">修改为<base href="./">即可。

完成了这一步,如果你的路由使用的是hash模式则大功告成,无须进行下面步骤。

如果你想使用histroy模式,你还需要对服务器做相关配置,这里笔者以Apache为例

  1. # Apache代码,加入到网站的.htaccess里,没有该文件,自己可以新建一个(注意将最后一条规则里的demo修改成自己的目录名,否则只对demo文件夹有效)
  2. <IfModule mod_rewrite.c>
  3. RewriteEngine On
  4. RewriteBase /
  5. RewriteRule ^index\.html$ - [L]
  6. RewriteCond %{REQUEST_FILENAME} !-f
  7. RewriteCond %{REQUEST_FILENAME} !-d
  8. RewriteRule ^(demo|demo/.*)$ demo/index.html [L]
  9. </IfModule>

欢迎分享你在使用Angular开发过程中遇到的问题。

shaw

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: