前言相信大家在访问技术论坛或者技术博客的时候,都会发现一些写得很好的文章,我们想要保存下来,以便反复阅读和查看。在一些比较大的网站上,比如SegmentFault或者Nuggets,都会提供收藏夹之类的功能来帮助我们做这个保存的工作。我们可以稍后再回来查看,但是我们通常会浏览多个站点,有时一些个人技术博客没有这样的功能。功能,我们只能保存浏览器书签来做,这样我们平时保存的一些文章会比较散乱,没有一个统一的地方帮我们管理。如果有这样的应用,我们只需要输入某篇我们想要保存的文章的URL地址,就可以帮我们生成这篇文章的文字内容,并且可以支持标签分类和搜索功能。本应用就是基于这样的需求和我平时的个人经验开发的。可以输入这个地址先体验一下。帐号是test,密码是123456。应用是用Angular4开发的,koa2提供数据接口。由于本人是Angular初学者,在阅读官方文档的过程中做了这个应用,遇到了一些问题。我简单说一下开发过程和遇到的问题。一些问题的解决方案。技术方案选择如下:Angular前端框架AngularCli前端打包构建koa2提供数据接口MongoDB提供数据存储幻象和节点可读性提供文章文本提取1.项目初始化Angular官方是前端2016年9月发布的Framework(其实Angular的定位是一个平台),它和vue、react不一样,Angular不只是一个视图层的库,它提供了完整的解决方案和生态,它构建了-在组件解决方案、模块化解决方案、测试、表单验证、路由、国际化和HTTP服务等方面,我们开发者不用纠结如何选择这些东西,按照官方的推荐和说明去做,绝对是非常容易难选的患者我喜欢这个,但是相对来说不如vue和react灵活。这个怎么看,就看我们每个人的项目需求了。既然Angular本身如此完备,那它肯定也有一个CLI工具,就是AngularCLI。AngularCLI是一个命令行界面工具,可以创建项目、添加文件并执行一整套开发任务,例如测试、打包和发布。我们可以先执行如下命令全局安装AngularCLInpminstall-g@angular/cli然后执行ngnew[ProjectName]初始化一个项目。二、模块化和组件化Angular应用程序是模块化的,Angular有自己的模块系统,称为NgModules。我们的应用程序由一个或多个模块组成,并且必须有一个根模块,我们通常将其命名为AppModule,每个模块都会有一个装饰器函数,称为@NgModule,它接收一个用于描述模块属性的元数据对象,我们在这个对象属性上配置我们的应用需要的组件、路由、指令、管道、服务等。然后Angular会引导根模块启动应用,代码如下import{platformBrowserDynamic}from'@angular/platform-b??rowser-dynamic';从'./app/app.module'导入{AppModule};platformBrowserDynamic().bootstrapModule(AppModule);Angular应用程序仍然是组件化的。组件负责控制屏幕上的一小块区域,称为视图。每个组件还有一个名为@Component的装饰器函数,它也接收一个元数据对象。我们可以在对象属性上配置组件的模板文件,以及组件模板的样式文件等,看下面代码@Component({selector:'app-root',templateUrl:'./app.component.html',styleUrls:['./app.component.scss']})这样我们就可以组合不同的组件来组装我们的整个应用程序。整体架构图如下3.路由配置Angular路由是通过一个叫做RouterModule的模块进行配置的。RouterModule在@angular/router包中,所以路由配置模块RouterModule需要先从@angular/router包中导出,然后调用RouterModule的forRoot方法,传入一个数组配置对象即可。需要注意的是,我们还需要有一个路由来匹配我们所有的路由都没有配置的情况。它的路径应该写成两个星号import{Routes,RouterModule}from'@angular/router';constroutes:Routes=[{path:'index',component:IndexComponent},{path:'**',redirectTo:'index',pathMatch:'full'}])@NgModule({导入:[RouterModule.forRoot(routes)]...})路由配置完成后,将其返回值添加到AppModule的imports数组中。然后在我们的根组件appComponent的模板中添加作为我们的路由渲染出口,到这里基本的路由配置就完成了。当然Angular路由还有很多内容,比如路由守卫,路由模块划分,路由值传递等等,更详细的内容可以参考Angular的中文文档。4.目录结构目录的划分是根据我个人的开发习惯来做的,我们的业务逻辑开发大多是在app文件夹下进行的。我一般会在app文件夹下创建一个pages文件来存放页面级组件,然后新建directive,pip,service,animation,interceptor文件夹用来存放我们应用的指令,管道,服务,动画,拦截器,因为我这个应用没有使用一些第三方的UI组件库,一些常用的组件是自己封装的,所以还需要一个组件文件夹来存放整个应用需要的一些常用的UI组件,这样划分我们整个应用程序非常清晰。最终目录说明大致如下app├──animations//animation│└──global-router-animation.ts├──app-routing.module.ts//路由配置文件├──app.component.html//根组件模板文件├──app.component.scss//根组件样式文件├──app.component.spec.ts//根组件测试文件├──app.component.ts//Rootcomponent├──app.module.ts//rootmodule├──component//commonUIcomponent├──button│└──dropdown├──directives//instruction│└──markdown-editor├──interceptor//Interceptor│└──global-response-interceptor.ts├──page//页面级组件│├──add-link-note│├──add-note│├──classification│├──edit-note│├──index│├──search│├──tag│└──view-note└─services//service├──loading-bar├──msg├──note└──tag5.交叉-域问题现代前端项目几乎都会遇到跨域问题。在vue、react等项目中,我们可以通过webpack-dev-server的代理配置来解决。AngularCLI创建的项目底层也是通过webpack。应用打包编译,但是AngularCLI把webpack的配置隐藏到了package中。我们可以通过执行命令ngeject来暴露webpack的配置文件,但是暴露webpack的配置是为了配置跨域问题。不需要。我们可以先在项目根目录下创建一个proxy.config.json配置文件,在文件中写入如下代码,告诉Angular应用中所有以api开头的HTTP请求都转发到的3002端口本地主机。{"/api":{"target":"http://localhost:3002"}}写好配置文件后,我们需要添加这个配置"start":"ngserve--proxy-configproxy.config。json”并执行npmrunstart重启服务,这样我们的跨域问题就迎刃而解了。6.未解决的问题如前所述,本应用没有使用一些第三方UI组件库。项目中使用的一些UI组件是我自己封装的,包括一个LoadingBar组件和一个消息提示组件。它的调用方法应该是以服务的形式调用的,类似于下面的代码this.loadingBar.start()this.msg.info('这??是一条消息提示')但是服务本身没有模板在Angular,只有组件才有Template,所以这样的组件应该是通过service动态加载一个有模板的组件,但是我没有找到相关的实现方案。看了ng-zorro的源码没看懂?希望这里有大神。最后,我的实现是通过最不优雅的方案,直接在服务中操作DOM。比我的LoadingBar服务import{Injectable}from'@angular/core';@Injectable()exportclassLoadingBarService{constructor(){}public$Loading={start:function(){constmyLoadingBar=document.querySelector('.我的加载栏');if(myLoadingBar!==null&&myLoadingBarinstanceofHTMLElement){让LoadingBarDivWidth=0;this.timer=setInterval(()=>{LoadingBarDivWidth++;myLoadingBar.style.width=LoadingBarDivWidth+'vw';if(LoadingBarDivWidth>=100){clearInterval(this.timer);}},25);}else{constLoadingBarDiv=document.createElement('div');LoadingBarDiv.className='my-loading-bar';constbodyEl=document.querySelector('body');bodyEl.appendChild(LoadingBarDiv);让LoadingBarDivWidth=0;this.timer=setInterval(()=>{LoadingBarDivWidth++;LoadingBarDiv.style.width=LoadingBarDivWidth+'vw';如果(LoadingBarDivWidth>=100){clearInterval(this.timer);}},25);}},完成:function(){constmyLoadingBar=document.querySelector('.my-loading-bar');if(myLoadingBar!==null&&myLoadingBarinstanceofHTMLElement){clearInterval(this.timer);myLoadingBar.style.width=0+'vw';}}};}七、打包在我们整个应用开发完成后,需要构建静态文件,交给节点部署。这里有几点需要注意的是,在CLI生成的项目的编译配置命令中没有开启--prod配置。我们需要手动添加命令来启用它。添加--prod后,打包后的资源将不再有资源映射,因此文件体积会小很多。如果AngularCli使用的是1.3.0以上的版本,还可以加上--build-optimizer(摇树优化),文件体积会小一些,而我做这个项目时使用的版本还是1.2.7.最终的构建命令配置如下"build":"ngbuild--prod--build-optimizer"8.总结本文只是对一个Angular新手做的第一个项目的总结,不谈任何新的和深入的。Angular是一个非常好的框架。进入门槛并不像大多数人想象的那么高。只要你的JavaScript基础扎实,对ES6语法有基本的了解,就可以学起来。相信会给你不一样的开发体验。最后提供项目基本信息体验地址https://weiweinote.cn/indexGitHub源码地址https://github.com/linguowei/micro-note其实如果你有自己的个人服务器,就可以自己部署这个应用,如果没有,也可以部署到heroku等国外的一些免费服务商。好了,如果大家对这个项目有什么问题或者建议,欢迎大家留言一起讨论。