关于angular:Angular-为什么要引入-injection-token-的概念

你能够定义和应用一个 InjectionToken 对象来为非类的依赖抉择一个提供者令牌。 这里的重点是:非类。 下列例子定义了一个类型为 InjectionToken 的 APP_CONFIG . import { InjectionToken } from '@angular/core';export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');这里的 APP_CONFIG 只是一个令牌 token,或者说是一个 place holder. 可选的参数 <AppConfig> 和令牌形容 app.config 指明了此令牌的用处。接着,用 APP_CONFIG 这个 InjectionToken 对象在组件中注册依赖提供者。 providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]语义是,消费者代码里,注入 APP_CONFIG 的令牌,则运行时,令牌会被理论的值 HERO_DI_CONFIG 取代。这个 HERO_DI_CONFIG 不是一个 Angular class, 所以只能以 injection token 的形式注册提供者。 当初,借助参数装璜器 @Inject(),你能够把这个配置对象注入到构造函数中。 constructor(@Inject(APP_CONFIG) config: AppConfig) { this.title = config.title;}接口和依赖注入尽管 TypeScript 的 AppConfig 接口能够在类中提供类型反对,但它在依赖注入时却没有任何作用。在 TypeScript 中,接口是一项设计期工件,它没有可供 DI 框架应用的运行时示意模式或令牌。 ...

October 17, 2021 · 1 min · jiezi

关于angular:如何创建-Angular-库并在-Angular-应用里调用

把性能打包成库会强制库中的工件与利用的业务逻辑拆散。这有助于防止各种不良实际或架构失误,这些失误会导致未来很难解耦和复用代码。 把代码放到一个独自的库中比简略地把所有内容都放在一个利用中要简单得多。它须要更多的工夫投入,并且须要治理、保护和更新这个库。不过,当把该库用在多个利用中时,这种复杂性就会失去回报。 Angular 库是一个 Angular 我的项目,它与利用的不同之处在于它自身是不能运行的。必须在某个利用中导入库并应用它。 应用上面的命令行,创立一个库: ng generate library my-libangular.json 文件在 projects 节点下,多了一个 my-lib 节点,其 projectType 类型为 library: angular.json 里的层级构造和文件系统的目录同样是统一的: 这个库有属于本人独自的 package.json: 这个库无奈独自运行,那么如何测试呢? 应用如下命令行。 ng build my-lib --configuration developmentng test my-libng lint my-lib 要让库代码能够复用,你必须为它定义一个公共的 API。这个“用户层”定义了库中消费者的可用内容。该库的用户应该能够通过单个的导入门路来拜访公共性能(如 NgModules、服务提供者和工具函数)。 库的公共 API 是在库文件夹下的 public-api.ts 文件中保护的。当你的库被导入利用时,从该文件导出的所有内容都会公开。 下图是一个例子: 我的 service 类: 请应用 NgModule 来裸露这些服务和组件: Use an NgModule to expose services and components. 如何生产咱们本人开发的库间接在咱们的 AppModule 的 imports 区域里,导入咱们的 Angular library 通过 public_api.ts 导出的 component 和 service 即可。 ...

October 17, 2021 · 1 min · jiezi

关于angular:Angular-如何为多个项目使用单一存储仓库

Angular 工作区是 Angular project 的汇合。Angular project 蕴含 application 和 library 两种。 而用来创立或操作利用和库的命令(比方 add 和 generate)必须在工作区目录下能力执行。 ng new <my-project>上述命令行实际上创立的是一个新的工作区。 当你运行这个命令时,CLI 会在一个新的工作区中装置必须的 Angular npm 包和其它依赖项,其根利用(root leavl application)名叫 my-project。 该工作区的根文件夹中蕴含一些工作区配置文件,和一个带有主动生成的描述性文本的自述文件,你能够自定义它。 ng new 还会默认创立一个位于工作区根级的骨架利用,及其端到端测试项目。这个骨架是一个简略的 Welcome 利用,它能够运行,也很容易批改。这个根利用与工作区同名,其源文件位于工作区的 src/ 子文件夹中。 这种默认行为实用于典型的“多重(multi)repo”开发格调,每个利用都位于它本人的工作区中。倡议初学者和中级用户应用 ng new 为每个利用创立一个独自的工作区。 如下图所示:工作区和根利用的名称雷同: Angular 还反对蕴含多个我的项目的工作区。这种开发环境实用于正在开发可共享库的高级用户,以及那些应用“繁多(mono)仓库”开发格调的企业,它只须要一个仓库,而且所有 Angular 我的项目都应用全局配置。 SAP Spartacus 就采取的该种格调。 要设置繁多仓库的工作区,你应该跳过创立根利用的过程。 多我的项目工作区实用于对所有 Angular 我的项目应用繁多存储库(单仓库模型)和全局配置的企业。多我的项目工作区也能为库开发提供反对。 运行命令行: ng new angular-monorepo --create-application false创立好之后的我的项目构造如下图所示: angular.json 里很洁净: 而后,你能够应用工作区内惟一的名字来生成利用和库: ng generate application jerry-first-app增加了新的利用之后,咱们的 Angular 工作区,到底产生了哪些变动? 查看这个 commit即可。 ...

October 17, 2021 · 1 min · jiezi

关于angular:angular组验证器

前言咱们在对表单进行验证时,有时须要对多个字段同时进行验证,对不同字段的值进行比拟,并针对它们的组合判断是否验证通过,在这种状况下应用对繁多字段进行验证的验证器难以实现,这个时候就须要用到组验证器,在官网文档也叫跨字段穿插验证器。 组验证器的应用官网文档链接组验证器应用示例 上面通过我的项目中的实例解说组验证器的用法。 以后我的项目中须要对是否接种疫苗,接种地点,未接种起因三个字段进行验证,如果接种疫苗,需填写接种地点(必填),否则填写未接种起因(非必填)。 1.为FormGroup增加组验证器留神:要想在单个自定义验证器中计算这三个控件,你就必须在它们独特的先人控件中执行验证: FormGroup 能够在新建FormGroup时间接增加验证器,在创立时把一个新的验证器传给它的第二个参数 formGroup = new FormGroup({ 'beVaccinated': new FormControl(), 'vaccinatedPlace': new FormControl(), 'notVaccinatedReason': new FormControl() },{validators: VaccinatedValidator});当然,通常咱们在写的时候不会在新建FormGroup的时候增加参数,而是应用上面的形式增加验证器 formGroup.setValidators(VaccinatedValidator);增加完验证器后咱们开始实现验证器的性能,这样就能够对formGroup中的值进行验证了 2.自定义组验证器验证器代码如下 import {AbstractControl, ValidationErrors, ValidatorFn} from '@angular/forms';/** * 跨字段穿插验证器 * 同时验证接种疫苗和 地点 起因 三个字段 * 如果接种,地点必填,只有填写地点能力验证通过,返回null * 未接种,地点不用填,间接返回null * @param control 须要验证的 formGroup */export const VaccinatedValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { const beVaccinated = control.get('beVaccinated'); const vaccinatedPlace = control.get('vaccinatedPlace'); const notVaccinatedReason = control.get('notVaccinatedReason'); // 判断是否传值 if (beVaccinated === null || vaccinatedPlace === null || notVaccinatedReason === null) { return {vaccinated: true}; } return (beVaccinated.value as boolean && vaccinatedPlace.value as string) || !beVaccinated.value as boolean ? null : {vaccinated: true};};这个验证器实现了 ValidatorFn 接口。它接管一个 Angular 表单控件对象作为参数,control即为以后验证的FormGroup,通过control.get('')的形式获取formGroup中的相应的formControl,这样就能够依据须要本人对其中的值进行验证。 如果验证信息无效,返回null,否则返回ValidationErrors,也就是{vaccinated: true},其中的名称'vaccinated'和'true'能够依据须要本人定义。 留神:为防止没有传入相应FormControl,须要对应用get办法获取到的FormControl进行判断,如果为空间接返回ValidationErrors ...

October 16, 2021 · 1 min · jiezi

关于angular:Angular-应用里的-vendorjs-是用来干什么的

What is vendor file in angular? 以 SAP 电商云 UI 的 Angular 页面为例,这个 vendor.js 有超过 17 万行代码: 此文件蕴含导入您的应用程序 (app.module) 的所有库,包含 Angular 库。 导入到您的应用程序中的第三方库也会被编译到此文件中(例如 lodash、moment 等)。 这个文件在开发编译(ng build)之后很大,因为它蕴含在浏览器中编译 Angular 所需的所有。 在将您的应用程序公布到生产环境之前,始终运行 prod 构建 (ng build –prod)。 prod 构建运行 Ahead of Time (AoT) 编译并执行 tree-shaking。 main.js蕴含应用程序的 action 相干代码,比方 Effect 实现。 同样的 effect 实现,在 vendor.js 里找不到。 在浏览器下载并运行代码之前的构建阶段,Angular 提前 (AOT) 编译器将您的 Angular HTML 和 TypeScript 代码转换为高效的 JavaScript 代码。在构建过程中编译您的应用程序可在浏览器中提供更快的渲染。 除了下面的内容,vendor bundle JS 还蕴含什么?制作“供应商捆绑包”。供应商包蕴含每个应用程序性能所依赖的所有框架和库。通过将所有这些代码构建到单个包中,客户端能够无效地缓存包,并且您只须要在框架或库更新时从新构建包。因而,vendor.js 里不蕴含自开发代码。 ...

October 10, 2021 · 1 min · jiezi

关于angular:原理图开发指南

总结原理图是什么?这里援用一个在 Angular 中的定义原理图是一个基于模板的反对简单逻辑的代码生成器. A schematic is a template-based code generator that supports complex logic. It is a set of instructions for transforming a software project by generating or modifying code. Schematics are packaged into collections and installed with npm. https://angular.cn/guide/schematics所以相比广义的脚手架来讲,原理图也能够称为智能代码生成器通用唬人图 个性原子性Angular开发的原理图框架对文件的操作应用的是虚构文件系统,所以对文件的任何解决都不会即时的反馈到我的项目中,只有在所有操作完结,没有异样时,才会写入到代码中通用性尽管为Angular开发的原理图,然而实现不局限于Angular,不局限于前端,甚至不局限语言只有是文件,皆可操作可测试性因为对文件的操作都在虚构文件系统中,所以能够建设单元测试,保障每一个原理图执行合乎预期交互性通过定义JSON Schema定义原理图传入字段,能够设置在命令行中的提醒输出反对输出,单选,多选,判断等不同输出形式版本控制并不是所有批改都间接失效,保留在虚构文件系统中Angular在其中实现了一个相似git的简化零碎单文件的批改(非笼罩)只有在commit时才会变更非主tree中文件的批改只有在merge后才会失效 能够通过branch创立另一个tree性能模板生成也就是最传统的脚手架开发,只须要调用两个办法就能实现文件操作能够对当前工作空间内的文件进行create,overwrite,rename,delete create在工作空间内创立文件overwrite笼罩工作空间已有文件rename重命名工作空间文件,在这里门路就是名字,因而重命名也能够用来挪动文件delete删除工作空间内的文件内置了文件操作规定,更不便的对文件解决代码操作当我的项目中的文件有配套的语法解析工具,就能够对代码进行解决对代码的解决能够更加准确,比方按类型,变量名,值的不同,进行不同的批改 现有前端举荐.ts->typescript,.html->@angular/compiler,.json->jsonc-parser 对于其余类型语言,语法解析工具能够参考这里https://astexplorer.net/链式调用以后原理图能够去调用其余原理图,作为一个规定,其余原理图能够解决之后返回,为下一个规定提供解决好的文件自动化工作解决如果指定过增加工作,那么在原理图的文件批改完结,并写入到硬盘后,会主动执行 目前内置的工作包含初始化仓库,npm装置,执行其余原理图能够用来做什么我的项目初始化这个也是最根底,利用最宽泛的,只须要保留文件并执行就能够主动生成我的项目更新对于我的项目中局部代码须要更新(如依赖更新引发的废除),能够通过语言解析替换相干节点内容通过其余代码,进行语法解析取得元数据生成相干逻辑 这里的元数据因为非 json 格局,所以须要语法解析取得源码工厂一个猜测,通过简单的规定及逻辑,把文件视为模块,通过输出的参数,生成符合要求的源码因为生产的源码是又原理图生成的,所以可读性与失常开发人员写的统一,并且不会呈现开发人员犯的低级谬误源码作为生成产品,不必放心泄露,因为真正的源码是原理图的源码工厂,而不是生成的源码名称解释workflow汇合及原理图工作的惟一环境初始化汇合应用engine创立并执行原理图engine用来创立collection,schematic,SchematicContext读取文件(模板),转换参数等底层办法collectioncollection.json的实例初始化原理图schematic在collection中的schematic实例调用规定解决传递进去的文件Tree一个虚拟机文件树原理图的第一个规定(默认执行的第一个),传入的Tree为当前工作空间次要用于传入给Rule中,进行解决SchematicContext原理图上下文以后原理图实例engineRule解决传入的Tree返回的Tree会给予下一个Rule持续进行解决Source与rxjs相似,Angular的原理图引入了Source(起源)与Rule(规定) Source相当于rxjs中的创立操作符,Rule相当于管道符Source能够由规定转换为Tree,而后提供给Rule进行解决因为规定是解决传入的文件,所以Source的作用就是限定文件原理图入门教程https://www.bilibili.com/video/BV13h411J7mU教程所用源码https://github.com/wszgrcy/schematics-tutorial

October 10, 2021 · 1 min · jiezi

关于angular:为什么我们需要给-Angular-library-创建多重入口-multiple-entry-point

原文:Creating Secondary Entry Points for your Angular Library 自从 Angular 库性能(从 Angular 7 开始)公布以来,当初开发 Angular 库比以往任何时候都容易。 Angular 库自身装备了一个名为 ng-packagr 的社区驱动包,它简直是外围。 在本文中,咱们将看看如何利用 ng-packagr 辅助入口点进一步拆分咱们的 Angular 库! Why do we need secondary entry points?咱们心愿领有辅助入口点的起因之一是使咱们可能拆分咱们的依赖项。 让咱们看一个例子,其中一个模块有 peerDependencies,而另一个没有。 假如咱们有如下的 library 文件夹构造: library 名称:my-awesome-lib两个 module,awesome-plain 和 awesome-time 查看 awesome-plain Component 的实现: import { Component } from '@angular/core';@Component({ selector: 'awesome-plain', template: ` <div>Hey I'm just a plain text with no dependencies!</div> `})export class AwesomePlainComponent {}以及 awesome-time Component 的实现: ...

October 2, 2021 · 3 min · jiezi

关于angular:NgRx-Store-createSelector-返回的-selector-执行取数逻辑的单步调试

测试源代码: import { Component } from '@angular/core';import { createSelector } from '@ngrx/store'; export interface State { counter1: number; counter2: number;} export const selectCounter1 = (state: State) => state.counter1;export const selectCounter2 = (state: State) => state.counter2;export const selectTotal = createSelector( selectCounter1, selectCounter2, (counter1, counter2) => counter1 + counter2); // selectTotal has a memoized value of null, because it has not yet been invoked. let state = { counter1: 3, counter2: 4 }; @Component({ selector: 'selector', template: ''})export class SelectorComponent{ constructor(){ console.log(selectTotal(state)); // computes the sum of 3 & 4, returning 7. selectTotal now has a memoized value of 7 console.log(selectTotal(state)); // does not compute the sum of 3 & 4. selectTotal instead returns the memoized value of 7 }}首先执行构造函数里第一条 selector 调用。 ...

September 25, 2021 · 1 min · jiezi

关于angular:NgRx-Store-createSelector-的单步调试和源代码分析

源代码: import { Component } from '@angular/core';import { createSelector } from '@ngrx/store'; export interface State { counter1: number; counter2: number;} export const selectCounter1 = (state: State) => state.counter1;export const selectCounter2 = (state: State) => state.counter2;export const selectTotal = createSelector( selectCounter1, selectCounter2, (counter1, counter2) => counter1 + counter2); // selectTotal has a memoized value of null, because it has not yet been invoked.createSelector 外部: function createSelector(...input) { return createSelectorFactory(defaultMemoize)(...input);}defaultMemoize 返回一个对象,每个字段指向一个函数: ...

September 25, 2021 · 1 min · jiezi

关于angular:Angular-CLI-全局-ngcmd-文件内容分析

文件内容如下: REM Jerry::这是正文@ECHO offSETLOCALCALL :find_dp0IF EXIST "%dp0%\node.exe" ( SET "_prog=%dp0%\node.exe") ELSE ( SET "_prog=node" SET PATHEXT=%PATHEXT:;.JS;=;%)"%_prog%" "%dp0%\node_modules\@angular\cli\bin\ng" %*ENDLOCALEXIT /b %errorlevel%:find_dp0SET dp0=%~dp0EXIT /b SETLOCAL:开始批处理文件中环境改变的本地化操作。在执行 SETLOCAL 之后所做的环境改变只限于批处理文件。要还原原先的设置,必须执行 ENDLOCAL。 在批处理文件中开始环境变量的本地化。 本地化始终继续到遇到匹配的 endlocal 命令或达到批处理文件的开端。 更多细节见 windows 文档。 CALL在不进行父批处理程序的状况下从另一个调用一个批处理程序。 call 命令承受标签作为调用的指标 CALL :find_dp0魔法变量 %n 蕴含用于调用文件的参数:%0 是 bat 文件自身的门路,%1 是前面的第一个参数,%2 是第二个,依此类推。 因为参数通常是文件门路,所以有一些额定的语法来提取局部门路。 ~d 是驱动器,~p 是门路(不含驱动器),~n 是文件名。 它们能够组合,所以 ~dp 是驱动器+门路。 因而 %~dp0 在 bat 中十分有用:它是执行 bat 文件所在的文件夹。 您还能够取得无关文件的其余类型的元信息:~t 是工夫戳,~z 是大小。 dp0 意思是批处理文件所在的驱动器和门路。 第五行调用的 :find_dp0, 实现在第18行。 set: 设置环境变量。SET dp0=%~dp0 ...

September 15, 2021 · 1 min · jiezi

关于angular:Angular-UniversalAngular-统一平台简介

Angular Universal 本文介绍 Angular Universal(对立平台),一项在服务端运行 Angular 利用的技术,即服务器端渲染。 如下图 package.json 里定义的依赖 @nguniversal/express-engine 所示: 规范的 Angular 利用会运行在浏览器中,它会在 DOM 中渲染页面,以响应用户的操作。 而Angular Universal 会在服务端运行,生成一些动态的利用页面,稍后再通过客户端进行启动。 这意味着该利用的渲染通常会更快,让用户能够在利用变得齐全可交互之前,先查看利用的布局。 服务器端渲染返回的 HTML 源代码,尽管没有加载对应的 .js 文件,无奈响应用户输出,然而能够给用户一个直观残缺的页面布局。 Node.js Express Web 服务器则会依据客户端的申请,利用 Universal 编译 HTML 页面。 要创立服务端利用模块 app.server.module.ts,请运行以下 CLI 命令: ng add @nguniversal/express-engine该命令会主动生成如下绿色高亮所示的文件: 要应用 Universal 在本地零碎中渲染你的利用,请应用如下命令: npm run dev:ssr 这个 serve-ssr 定义在 Angular.json 里: 而 server target 定义如下: 通过 routerLinks 导航时能失常工作,因为它们应用的是原生的链接标签(\<a>). 不反对除了点击 routerLink 以外的任何用户事件。你必须期待残缺的客户端利用启动并运行,或者应用 preboot 之类的库来缓冲这些事件,这样你就能够在客户端脚本加载结束后重放这些事件。 Angular Universal 能够为你生成利用的动态版本,它易搜寻、可链接,浏览时也不用借助 JavaScript。 它也让站点能够被预览,因为每个 URL 返回的都是一个齐全渲染好的页面。 ...

September 11, 2021 · 2 min · jiezi

关于angular:Angular开发小程序

Angular开发小程序通过批改Angular实现应用Angular开发小程序本我的项目实现的目标很简略也很纯正,就是通知大家.框架无高下,应用的人,有高下视频简介https://www.bilibili.com/video/BV1wh411p7bB/开发模板https://github.com/wszgrcy/angular-miniprogram-template批改内容builder 批改用于反对自定义构建component 编译时 通过提前解析取得模板与款式,转换为小程序所需的全局变量 用来反对ngZone与Angular默认全局援用platform 通过实现自定义的 platform,给予小程序的启动上下文反对renderFactory 原渲染工厂反对的是 dom 渲染,然而小程序不须要主进口重建 主进口事后加载相干依赖,为前面的 page 做筹备文件系统监听批改 须要在预处理完结时,革除文件缓存减少内容组件与页面的注册函数 只有被注册,还会主动的查问依赖关系与生成相干生命周期的传递 小程序自带的一些生命周期小程序相干 token. APP_TOKEN能够取得 App 实例COMPONENT_TOKEN,PAGE_TOKEN能够取得组件对应的小程序组件实例已实现内容变更检测Input,Output依赖注入ng-contentngIf,ngSwitch,ngFor 对于其余指令及自定义指令,暂未实现小程序大部分性能未实现可实现的性能http管道非结构型指令结构型指令的非援用传递或无限传递路由的局部实现 路由是否实现次要看小程序的应用场景需不需要路由这个货色表单自定义组件不可能实现的性能无限度的结构型指令 除非模板运行动静按需加载其余平台的反对目前性能尚未欠缺,不对多余的平台做反对目前仅反对微信小程序,然而将来重构欠缺后,会增加其余平台的小程序反对筹备做的component 的 template 重写之前是通过齐全重写实现的值绑定与更新,然而是因为有一个技术没法实现所以才采取点计划.目前曾经能够通过替换调用函数实现这个,所以从新 template重写后将会使管道,表单,非结构型指令的反对

September 10, 2021 · 1 min · jiezi

关于angular:angular-增删改查流程

1、 我的项目开发过程Eg:零碎设置 -> 居民关系治理 (system -> relationship)(1) 初始化居民关系治理模块创立模块应用shell来到src\app\system文件夹,执行ng g module relationship命令。成果:relationship└──relationship.module.ts (2) 初始化居民关系治理实体、mockapi、service层创立实体文件:web/src/entity/relationship.tsMockapi文件:web/src/api/relationship.api.ts并更新导入web/src/api/apis.ts文件Service文件:web/src/service/relationship.service.ts和web/src/service/relationship.service.spec.ts (3) 性能原型index原型,新增原型,编辑原型 eg:编辑原型① 生成组件应用shell进入src/app/system文件夹,执行创立组件命令:ng g c edit。成果:relationship├── edit│ ├── edit.component.css │ ├── edit.component.html │ ├── edit.component.spec.ts │ └── edit.component.ts ├── relationship.module.ts 并更新了模块文件relationship.module.ts。 ② edit.component.html文件编写页面 (4) 表单测验add、edit表单测验① web/src/app/system/relationship/edit/edit.component.html ② web/src/app/system/relationship/edit/edit.component.ts ③ web/src/app/system/relationship/edit/edit.component.spec.tsimport {ReactiveFormsModule} from ‘@angular/forms’; ④ web/src/app/system/relationship/relationship.module.tsimport {ReactiveFormsModule} from ‘@angular/forms’; (5) 实现原型index应用MockApi实现分页性能、index查问性能新增性能编辑性能删除性能 2、 eg:编辑性能的数据流提交前:(1)web/src/app/system/relationship/edit/edit.component.ts (2)web/src/service/relationship.service.ts (3)web/src/api/relationship.api.ts 点击保留按钮后:(1)web/src/app/system/relationship/edit/edit.component.ts (2)web/src/service/relationship.service.ts (3)web/src/api/relationship.api.ts

September 6, 2021 · 1 min · jiezi

关于angular:使用nginx起环境踩坑

前言:本周是第一次应用nginx来起环境进行测试,在开始的时候不晓得我的项目中nginx.conf文件的作用,便还是像以前一样间接ng s起前台环境,同时起后盾环境。 一、不指明后盾拜访端口:启前台和后盾环境后并未查看环境变量的更改,报错: 思考:前台端口不是4200吗,为何申请后盾的也变成4200?去查看了前台environment环境变量: 环境变量中没有指明后盾拜访地址和端口号!全局搜寻4200:三个无关的文件第一处为readme文件,能够排除它并不会起作用第二处为前台源地址,与后盾申请无关 第三处在开始并不理解,就想着将4200改成后盾端口8080试试:无反馈! 在认真看了该配置文件后开始纳闷:server { listen 8005; server_name 127.0.0.1 localhost; # 限度上传文件大小,保障该值小于等于nginx.conf -> http 中的client_max_body_size值 client_max_body_size 20M; location / { proxy_pass http://127.0.0.1:4200; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /sockjs-node/ { proxy_pass http://127.0.0.1:4200/sockjs-node/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } location /api/ { proxy_pass http://127.0.0.1:8081/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }}难道和后盾申请端口无关的不是第三个吗?因为location为定位,猜想是将/api/用如下的进行代替:http://127.0.0.1:8081/那为啥前台向后盾拜访的是4200呢? 心浮气躁:童稚的我居然把后盾端口改成了4200: 接下来就出了一系列的问题:1.拜访localhost:4200首先让我登陆2.我登陆胜利或者点勾销都会再报404如下图在后盾控制台中看到:除此之外还有 No mapping for GET /等等。。。。 ...

September 4, 2021 · 1 min · jiezi

关于angular:最好用的-Angular-甘特图组件-ngxgantt

本文由PingCode前端工程师 张文 分享一句话介绍ngx-gantt 是一款基于 Angular 框架的甘特图组件,反对多种视图展现并反对多种高级的个性,能疾速的帮忙开发者搭建本人的甘特图利用。 什么是甘特图甘特图又名横道图,是项目管理中比拟风行的一种工具。在图表的左侧显示工作列表,顶部显示适合的工夫刻度,每个工作由一个条形示意,条形的地位和长度反映了工作的开始日期、持续时间和完结日期,使我的项目管理者高深莫测。 最后基于Excel制作的甘特图的样子 传统的甘特图工具都是基于客户端的,ngx-gantt 把甘特图直观、高效的个性引入到 Web 端,不便更多的 Web 端用户疾速构建本人的甘特图工具。 个性5 种视图(日、周、月、季、年)工作分组展现树形构造数据展现并反对异步加载工作前后置依赖关联及展现工作拖拽更改工夫表格自定义滚动加载数据导出为图片可定制化开发动机2020年,PingCode 筹备做一款我的项目集治理的产品 Plan,Plan 这款产品蕴含多我的项目路线图治理,进度治理,资源跟踪以及里程碑治理,其中波及到路线图,里程碑等性能都须要基于甘特图来实现,随后咱们开始调研Github中开源的一些甘特图的组件,最终都因为不能满足咱们的需要而pass,其中次要的起因有以下几点: 不能很好的反对 Angular有一些功能强大的库仍旧依赖 JQuery不反对多层级展现默认反对的视图不满足咱们的场景不够灵便基于上述起因,咱们决定本人造轮子,做一款基于 Angular 的甘特图组件。 展现成果话不多说,先上成果 https://www.bilibili.com/vide... ngx-gantt 的特点更灵便的表格表格和甘特图一起展现是一种更好的形式,咱们反对灵便的表格。具体的实现形式是联合 Angular的模板 ng-template 来应用,这样就能够在模板中应用任何组件,指令等等,从而更灵便的自定义表格内容。除此之外,咱们还反对自定义表格列宽,表格中的每一列和整个表格都是能够拖拽批改宽度的。 示例: https://www.bilibili.com/vide... 具体应用: <ngx-gantt> <ngx-gantt-table> <ngx-gantt-column name="工作项" width="120px"> <ng-template #cell let-item="item"> <app-work-item [workItem]="item"></app-work-item> </ng-template> </ngx-gantt-column> <ngx-gantt-column name="负责人" width="120px"> ... </ngx-gantt-column> </ngx-gantt-table></ngx-gantt>树形构造数据展现树形构造能明确的展现出工作的父子关系,不便咱们用甘特图治理简单的工作。思考到性能问题,咱们同时反对了异步加载子数据。默认层级是两层,你能够通过 maxLevel 参数设置本人须要的层级数。 示例:https://www.bilibili.com/vide... 工作依赖在甘特图组件中,依赖关系的展现也尤为的重要,ngx-gantt 反对通过拖拽关联工作,展现工作依赖关系。一般来说,工作之间的依赖关系次要有以下四种:Finish to Start (FS) — 完结到开始,即A工作必须先完结,B工作能力开始。这是最常见的一种依赖关系。Start to Start (SS) — 开始到开始,即A工作必须先开始,B工作能力开始。Finish to Finish (FF) — 完结到完结,即A工作必须先完结,B工作能力完结。Start to Finish (SF) — 开始到完结,即A工作必须先完结,B工作能力完结。 ...

August 23, 2021 · 1 min · jiezi

关于angular:真实项目开发收获与总结

前言首先感激潘老师近期始终在我的学习和开发上给予的领导与帮忙,同时也为本人能参加到实在的我的项目开发中而感到非常侥幸。言归正传,联合近期我的项目开发我将别离从:1.实在我的项目开发感触;2.GitHub初步应用;3.对于Angular学习及应用,这三个方面进行总结。 实在我的项目开发1.团队单干在参加实在我的项目开发中,我感触到我的团队单干能力失去了全面的造就和锤炼。(1)团队成员根据集体状况支付工作,同时肯定要将支付的工作指定给本人,防止工作反复实现而造成的工夫节约。比方:在一次开发中,我与团队成员同时进行了雷同工作忘了进行指定,在提交时就产生了反复的问题。往小说是节约了集体的工夫,往大说就是拖慢了我的项目进度。(2)近期学习开发中,我的速度相对来说进行的比拟快,但也存在“欲速则不达”的问题。在团队开发中,我与大家互相交换,互相帮忙解决各自问题的同时也能够进一步补救有余、晋升本人,同时也防止一些相似谬误的产生。(3)正如潘老师所说“要将本人放在团队领导者的角度思考问题”。比方老师团队中张贴字母表的故事,仅仅是一张字母表就引申出团队开发问题、代码标准问题、工夫效率问题,使我深深感触到一个团队领导者的重要性。当处在一个更高地位去思考问题时,思考的方面将会更广、更深。我抵赖这一点在近期我做不是很到位,但我会将这句话记于心,并缓缓践于行。2.代码规范化和无障碍交换我认为二者是相辅相成的。代码规范化书写一方面保障了代码的健壮性缩小bug产生,一方面也加强了代码可读性来不便团队成员浏览非本人书写的代码,从而确保无障碍交换。换言之好的无障碍交换就要有肯定的标准,代码规范化就是很好的例子:(1)正文的书写 /** * 小区治理mockApi */export class VillageApi implements MockApiInterface { private baseUrl = 'village';(2)在单元测试文件中,形容分明以后组件属于谁 describe('village->EditComponent', () => {});(3)养成格式化代码的习惯 GitHub初步应用这是我第一次接触Git与GitHub,通过学习理解到:Git是一个分布式版本控制工具;GitHub是一个代码托管核心。就近期所应用的过的Git命令做一总结:1.基本操作命令 git status //查看状态git add . //将工作区的 文件 增加到暂存区(“.”示意以后文件夹及子文件夹中所有未增加的文件)git common -a -m "形容信息" //将暂存区 文件 提交到本地库git reset //版本后退或后退git branch [分支名称] //创立分支git branch -v //查看分支git checkout [分支名称] //切换分支2.与GitHub相干命令(1)开发前命令步骤 git clone [近程地址|近程地址别名] //克隆git checkout main //切换到主分支,确保本人在主分支上git pull //拉取最新代码git branch [分支名] //建设与issue号同名的分支git checkout [分支名] //切换到开发分支注:git pull = git fetch [近程分支名] + git merge [近程分支名](2)pull request命令步骤 ...

August 23, 2021 · 2 min · jiezi

关于angular:Angular组建需要以及拥有的能力

前言上周写代码始终呈现因为模块,或者其余的援用谬误而导致局部性能无奈正常化的状况,一开始老师让看教程,也是看的挺懵的,起初老师给讲了一下之后才真正晓得是怎么回事了. 组建的基本要素组建必然存在模块当中,个别状况下如果间接在命令行中输出ng g c app,则会生成名为app的一个angular组建,也就是以下四种文件 1是v层的html款式文件,2是模版的v层html代码文件,3是单元测试的代码文件,4则为组建的c层文件,咱们在外面定义了咱们的1和2文件.其中4是必选的,其余三个都是可选的.有组建必须有模块,组建肯定是生存在模块外面的,模块就是组建因素加上一个.module.ts的文件. 组建须要的能力说完组建的几因素,那当初来说说咱们从哪晓得以及咱们须要给组建提供什么能力才可能让此组建顺利跑起来. 构造函数中在4文件外面,也就是组建的c层,在4文件外面往往是一个class 类,既然有类,那么就会有构造函数吧,好的,那么构造函数就是一种路径,比方下图:能够看到,如果想要让此构造函数所在的类编一部报错,咱们就须要实例化TownService、CommonService、ActivatedRoute、Router,这四个类,而如果咱们想要实例化这四个类咱们有须要从哪去找呢,同样,也是从构造函数中去找,比方ToenService:能够看到咱们如果想要实例化TownService,那我咱们就必须提供HttpClient这个货色,从哪提供呢,或者说怎么实例化,实例化须要哪些货色呢,咱们能够在此indexComponent所在的模块中引入HttpClientModule(ng s时须要),单元测试文件中援用HttpClientTestingModule(ng t时用)从而保障咱们在类TownService的失常实例化,从而失常实例化indexComponent.下一个,同样的情理上面三个也是须要看相应构造函数中须要什么能力,此为CommonService的构造函数,那咱们就须要提供Router以及DomSanitizer了,然而呢,DomSanitizer不属于哪个模块中,所以只需呀在以后文件申明其命名空间即可.因为ActivatedRoute和Router不须要其余能力咱们就间接引他们所在的模块即可. V层代码中<div> <div class="col-12 text-right"> <a class="btn btn-primary" routerLink="add"><i class="fas fa-plus"></i>新增</a> </div></div><app-size [size]="pageData.size" (changeSize)="onSizeChange($event)"></app-size><table class="table table-striped mt-2"> <thead> <tr class="table-primary"> <th>序号</th> <th>名称</th> <th>拼音</th> <th>操作</th> </tr> </thead> <tbody> <tr *ngFor="let object of pageData.content; index as i"> <td>{{i + 1}}</td> <td>{{object.name}}</td> <td>{{object.pinyin}}</td> <td> <span class="btn btn-outline-primary btn-sm" routerLink="edit/{{object.id}}"> <i class="fas fa-pen"></i> 编辑 </span> <span class="btn btn-outline-primary btn-sm" (click)="onDelete(i, object.id)"> <i class="fas fa-trash-alt"></i> 删除 </span> </td> </tr> </tbody></table><app-page [page]="pageData.number" [size]="pageData.size" [totalElements]="pageData.totalElements" (changePage)="onPageChange($event)"></app-page>能够看到我V层代码中含有angular特有的标签属性routerLink,以及援用size和page模版的代码,如果咱们不给予组建相应的能力的话那么组建是不意识他的,天然也不会通过编译,所以咱们须要引入RouterTestingModule来赋予组建辨认routerLink的能力,当然要使得编译器不报错咱们还须要引入PageModule以及SizeModule. 最终单元测试援用代码// 申明,此处为组建 declarations: [IndexComponent], // 引入,此处为模块 imports: [ // 路由器测试模块,设置用于测试的路由器。 RouterTestingModule, // 援用了commonModule PageModule, // 援用了commonModule和FormsModule SizeModule, // ApiTestingModule中引入了HttpClientModule,HttpClientModule中提供了HttpClient, // 这使得 IndexComponet -> TownService 中的HttpClient可用 ApiTestingModule ]看到这里是不是会好奇,为什么没有提供CommonService,HttpClient...如果你好奇了那请接着往下看吧! ...

August 21, 2021 · 1 min · jiezi

关于angular:近期收获总结

1、近期,首先学会并实际了应用GitHub桌面版,从mian分支拉取更新数据,创立本人的工作分支号并进行开发,最初上传本人写的代码到GitHub上。 2、publish上传文件时,肯定要把测试用的“fit”改回“it”。 3、习惯运行时关上页面控制台,出错时,先认真看并翻译控制台报错的叙述,依据叙述找出问题所在。 4、多利用控制台打印日志来验证某文件是否正确执行。eg:要实现community的add性能,却报错如上图所示,通过排查不是第一种谬误(api文件与service文件的url雷同),现利用控制台打印日志来检测出错起因。先梳理数据流问题:add.component.ts中“this.communityService.save(newCommunity)”执行调用community.service.ts的save办法,M层调用HttpClient向模仿后盾mockApi发动申请,执行community.api.ts文件。首先在service打印日志发现控制台显示,进而在api文件打印日志,并未显示,表明api文件并未起作用,则转入下列第5点。 5、写了某文件后,要在相应的配置文件中退出申明。eg:写了community.api.ts文件,要在api.testing.module.ts中退出import,以及要在provider数组中退出CommunityApi。ps:前期,api.testing.module.ts文件改写为: @NgModule({ imports: [ HttpClientModule ], providers: [ {provide: CommonService, useClass: CommonStubService}, { provide: HTTP_INTERCEPTORS, multi: true, useClass: MockApiTestingInterceptor.forRoot(apis) }]})指向apis文件,则把写的api文件(CommunityApi)相应地退出到apis.ts文件中即可。 6、html文件中 <tr *ngFor="let object of pageData.content; index as i"> <td>{{pageData.number * pageData.size + i + 1}}</td>这样写后,分页时每一页就不单单又是1~pageData.size排序,而是从所有数据的1~n排序。即下图所示: 7、常见问题之一:ng t 后失去如下谬误:相似这种NullInjectorError: No provider for xxx,个别就是spec.ts文件中短少某个模块的import。

August 20, 2021 · 1 min · jiezi

关于angular:ngZorro中table表格头和列不对齐

状况形容: 表格的列是不固定的,目前曾经设置了nzwidth,然而宽度并不是以后想要达到的成果,并且当列过多的时候会呈现列不对齐的状况 解决办法: 设置scroll的width等于所有列宽之和 因为我的列是不固定的,所以给scroll.x设置一个变量,依据类的长度来动静的设置滚动的宽度 当设置了不同的列时,动静的跳转表格滚动的宽度————————————————原文链接:https://blog.csdn.net/an_Ran_...

August 10, 2021 · 1 min · jiezi

关于angular:微前端概述Micro-Frontends-以及相比单体应用微前端能带来什么好处

原文地址 好的前端开发很难。 扩大前端开发,让多个团队能够同时开发一个大型简单的产品就更难了。在本文中,咱们将形容将前端单体分解成许多更小、更易于治理的局部的最新趋势,以及这种架构如何进步解决前端代码的团队的效率和效率。 除了探讨各种益处和老本外,咱们还将介绍一些可用的实现选项,咱们将深入研究演示该技术的残缺示例应用程序。 近年来,微服务大受欢迎,许多组织应用这种架构格调来防止大型单体后端的局限性。尽管对于这种构建服务器端软件的格调曾经写了很多,但许多公司仍在与单体前端代码库作奋斗。 兴许您想构建一个渐进式或响应式 Web 应用程序,但找不到一个简略的中央来开始将这些性能集成到现有代码中。兴许您想开始应用新的 JavaScript 语言性能(或能够编译为 JavaScript 的有数语言之一),但您无奈将必要的构建工具放入现有的构建过程中。或者,兴许您只是想扩大您的开发,以便多个团队能够同时解决单个产品,但现有单体的耦合性和复杂性意味着每个人都在相互踩踏。这些都是真正的问题,都会对您无效地为客户提供高质量体验的能力产生负面影响。 最近,咱们看到越来越多的人关注简单的古代 Web 开发所需的整体架构和组织构造。特地是,咱们看到呈现了将前端单体合成为更小、更简略的块的模式,这些块能够独立开发、测试和部署,同时依然作为一个繁多的有凝聚力的产品呈现在客户背后。咱们称这种技术为微前端,咱们将其定义为: 一种架构格调,其中可独立交付的前端应用程序组合成一个更大的整体。咱们从微前端看到的一些次要益处是: 更小、更有凝聚力和可保护的代码库具备解耦、自治团队的更具可扩展性的组织可能以比以前更多的增量形式降级、更新甚至重写前端的某些局部这些突出劣势与微服务能够提供的劣势雷同,这并非偶合。当然,在软件架构方面没有收费的午餐——一切都是有代价的。一些微前端实现可能导致依赖项反复,减少用户必须下载的字节数。此外,团队自主性的急剧减少可能导致团队工作形式四分五裂。尽管如此,咱们置信这些危险是能够治理的,而且微前端的益处往往大于老本。 收益咱们不是依据特定的技术办法或实现细节来定义微前端,而是强调呈现的属性及其带来的益处。 增量降级对于许多组织来说,这是他们微前端之旅的开始。旧的、大型的前端单体被过来的技术堆栈或在交付压力下编写的代码所妨碍,并且曾经到了齐全重写很迷人的境地。为了防止齐全重写的危险,咱们更违心一一扼杀旧的应用程序,同时持续向咱们的客户提供新性能,而不会被单体利用连累。 这通常会导致微前端架构。一旦一个团队取得了在对旧世界简直没有批改的状况下将性能一路投入生产的教训,其余团队也将心愿退出新世界。现有的代码依然须要保护,在某些状况下,持续向其增加新性能可能是有意义的,但当初能够抉择。 最终后果是,咱们取得了更多的自在,能够对产品的各个局部进行逐案决策,并对咱们的架构、依赖项和用户体验进行增量降级。如果咱们的主框架产生重大突破性变动,每个微前端都能够在有意义的时候降级,而不是被迫进行世界并立刻降级所有内容。如果咱们想尝试新技术或新的交互模式,咱们能够以比以前更加孤立的形式进行。 简略、解耦的代码库依据定义,每个独自的微前端的源代码将比单个单体前端的源代码小得多。这些较小的代码库对于开发人员来说往往更简略、更容易应用。特地是,咱们防止了不应该相互了解的组件之间无心和不适当的耦合所带来的复杂性。通过在应用程序的有界上下文四周绘制更粗的线,咱们使这种意外耦合更难呈现。 当然,繁多的、高层次的架构决策(即“让咱们做微前端”)并不能代替良好的老式洁净代码。咱们并没有试图让本人免于思考咱们的代码并努力提高其品质。相同,咱们试图让谬误的决定变得艰难,而好的决定变得容易,从而使本人陷入胜利的陷阱。例如,跨有界上下文共享域模型变得更加艰难,因而开发人员不太可能这样做。相似地,微前端促使您明确和三思而行地理解数据和事件如何在应用程序的不同局部之间流动,无论如何咱们都应该这样做! 独立部署与微服务一样,微前端的独立部署能力是要害。这会放大任何给定部署的范畴,从而升高相干危险。 无论您的前端代码以何种形式或在哪里托管,每个微前端都应该有本人的继续交付管道,用于构建、测试和部署它始终到生产。咱们应该可能在不思考其余代码库或管道的以后状态的状况下部署每个微前端。 旧的单体利用是否处于固定的、手动的、每季度的公布周期,或者隔壁的团队是否将一个半实现或损坏的性能推送到他们的主分支中都无关紧要。 如果给定的微前端筹备投入生产,它应该可能这样做,并且该决定应该由构建和保护它的团队决定。 自治团队作为将咱们的代码库和咱们的公布周期解耦的更高层次的益处,咱们在领有齐全独立的团队方面还有很长的路要走,他们能够领有一个产品的一部分,从构思到生产再到更远。 团队能够齐全领有为客户提供价值所需的所有,这使他们可能疾速无效地口头。 为此,咱们的团队须要围绕业务性能的垂直切片组建,而不是围绕技术能力。 一种简略的办法是依据最终用户将看到的内容划分产品,因而每个微前端封装应用程序的单个页面,并由单个团队端到端领有。 与围绕技术或“横向”问题(如款式、表单或验证)组建团队相比,这为团队工作带来了更高的凝聚力。 总结简而言之,微前端就是将大而可怕的货色切成更小、更易于治理的局部,而后明确它们之间的依赖关系。 咱们的技术抉择、咱们的代码库、咱们的团队和咱们的公布流程都应该可能彼此独立地运行和倒退,而无需适度协调。 更多Jerry的原创文章,尽在:"汪子熙":

July 29, 2021 · 1 min · jiezi

关于angular:anguler报错Did-you-add-it-to-NgModuleentryComponents

angular我的项目新增的组件援用的时候报错“Did you add it to @NgModule.entryComponents?”,解决办法就是在入口文件的module中增加新增组件的component

July 27, 2021 · 1 min · jiezi

关于angular:一个用于-Angular-开发的-Chrome-扩展-Angular-Dev-Tools

该扩大装置到 Chrome 浏览器之后,Chrome 开发者工具会多出一个标签页: 能够在 Component 面板里查看 Component 的属性,或者间接对其批改: 在 Component 面板里双击某个节点,就能主动在 Angular UI 上将其对应的 DOM 节点高亮进去: 成果如下图所示: 能查看 Angular 以后版本: 点击该图标,能间接查看 Component 的实现源代码: 能够间接对 @Input 属性做编辑,并立刻失去后果。 看一个例子: 下图 Popover 对话框,右上角具备一个 close 按钮。 这个按钮显示与否,通过 Directive 实现的 cxPopoverOptions 这个 input 属性的 displayCloseButton 字段指定: 我在 Angular Dev tools 里将其批改成 false,这样对话框里就没有 close 按钮了: 更多Jerry的原创文章,尽在:"汪子熙":

July 27, 2021 · 1 min · jiezi

关于angular:Angular-应用级别的依赖-Fake

原文:Faking dependencies in Angular applications 应用 Angular 依赖注入零碎的弱小性能,咱们能够伪造特定的用例。 这对于自动化测试很有用,但在本文中,咱们将钻研一种将其用于手动测试的办法。 为了让咱们的生存更轻松,咱们将创立一个浏览器伪造组件,因为自定义构造指令,该组件仅在开发模式下启用。 为了好玩,咱们将增加文本管道以在咱们的组件模板中应用常见的字符串操作。 Simulating a browser environmentDynamically replacing a dependency using a class-based service用户代理令牌工厂只对每个模块注入器评估一次,如果它没有被先人组件或指令提供的元素注入器替换,咱们必须应用另一种技术来伪造依赖项。 咱们将应用基于类的服务依赖替换依赖注入令牌依赖。 // internet-explorer-11-banner.component.tsimport { Component } from '@angular/core';import { InternetExplorerService } from './internet-explorer.service';@Component({ selector: 'internet-explorer-11-banner', templateUrl: './internet-explorer-11-banner.component.html',})export class InternetExplorer11BannerComponent { private isDismissed = false; get isBannerVisible() { return this.internetExplorer.isInternetExplorer11State && !this.isDismissed; } constructor( private internetExplorer: InternetExplorerService, ) {} onDismiss() { this.isDismissed = true; }}// internet-explorer-service.tsimport { Inject, Injectable } from '@angular/core';import { userAgentToken } from './user-agent.token';@Injectable({ providedIn: 'root',})export class InternetExplorerService { get isInternetExplorer11State(): boolean { return this.isInternetExplorer11(this.userAgent); } constructor( @Inject(userAgentToken) private userAgent: string, ) {} isInternetExplorer11(userAgent: string): boolean { return /Trident\/7\.0.+rv:11\.0/.test(userAgent); }}首先,咱们从依赖注入令牌中提取 Internet Explorer 11 检测到咱们新创建的 InternetExplorerService 类。 Internet Explorer 11 检测令牌当初在依据用户代理评估其值时委托给服务。 ...

July 22, 2021 · 4 min · jiezi

关于angular:Angular-项目中的可摇树依赖-Treeshakable-dependencies

Tree-shakable dependencies in Angular projects Tree-shakable 依赖更容易推理和编译成更小的包。 Angular 模块 (NgModules) 已经是提供应用程序范畴依赖项(例如常量、配置、函数和基于类的服务)的次要形式。 从 Angular 版本 6 开始,咱们能够创立可摇树的依赖项,甚至能够疏忽 Angular 模块。 Angular module providers create hard dependencies当咱们应用 NgModule 装璜器工厂的 providers 选项提供依赖项时,Angular 模块文件顶部的 import 语句援用了依赖项文件。 这意味着 Angular 模块中提供的所有服务都成为包的一部分,即便是那些不被 declarable 或其余依赖项应用的服务。 让咱们称这些为硬依赖,因为它们不能被咱们的构建过程摇树。 相同,咱们能够通过让依赖文件援用 Angular 模块文件来反转依赖关系。 这意味着即便应用程序导入了 Angular 模块,它也不会援用依赖项,直到它在例如组件中应用依赖项。 Providing singleton services许多基于类的服务被称为应用程序范畴的单例服务——或者简称为单例服务,因为咱们很少在平台注入器级别应用它们。 Pre-Angular 6 singleton service providers在 Angular 版本 2 到 5 中,咱们必须向 NgModule 的 providers 选项增加单例服务。 而后咱们必须留神,只有急迫加载的 Angular 模块才会导入提供的 Angular 模块——依照常规,这是咱们应用程序的 CoreModule。 // pre-six-singleton.service.tsimport { HttpClient } from '@angular/common/http';import { Injectable } from '@angular/core';@Injectable()export class PreSixSingletonService { constructor(private http: HttpClient) {}}// pre-six.module.tsimport { NgModule } from '@angular/core';import { PreSixSingletonService } from './pre-six-singleton.service';@NgModule({ providers: [PreSixSingletonService],})export class PreSixModule {}// core.module.tsimport { HttpClientModule } from '@angular/common/http';import { NgModule } from '@angular/core';import { PreSixModule } from './pre-six.module.ts';@NgModule({ imports: [HttpClientModule, PreSixModule],})export class CoreModule {}以上是 Pre-Angular 6 singleton service. ...

July 22, 2021 · 5 min · jiezi

关于angular:Angular-依赖的测试和-Fake

原文:Testing and faking Angular dependencies 依赖注入是 Angular 的一个要害个性。这种灵便的办法使咱们的可申明和基于类的服务更容易隔离测试。 可摇树依赖项移除了间接层 即Angular 模块,但咱们如何测试它们的可摇树 provider?咱们将测试依赖于特定平台 API 的注入令牌的值工厂。 某些组件具备特定于浏览器的性能。咱们将一起测试告诉用户咱们将终止 Internet Explorer 11 反对的横幅。一个适合的测试套件能够给咱们足够的信念,咱们甚至不用在 Internet Explorer 11 中测试横幅。 咱们必须小心不要对简单的集成场景过于自信。咱们应该始终确保在尽可能靠近生产的环境中执行 QA(质量保证)测试。这意味着在实在 Internet Explorer 11 浏览器中运行应用程序。 Angular 测试实用程序使咱们可能伪造依赖项以进行测试。咱们将应用 Angular CLI 的测试框架 Jasmine 摸索在 Angular 测试环境中配置和解决依赖关系的不同选项。 通过示例,咱们将摸索组件 fixtures、组件初始化、自定义 expectations、模仿事件。咱们甚至会为十分精简但明确的测试用例创立自定义测试工具。 Faking dependency injection tokens used in token providers看个例子。 咱们创立了一个依赖注入令牌,该令牌评估为批示以后浏览器是否为 Internet Explorer 11 的标记。 // user-agent.token.tsimport { InjectionToken } from '@angular/core';export const userAgentToken: InjectionToken<string> = new InjectionToken('User agent string', { factory: (): string => navigator.userAgent, providedIn: 'root', });// is-internet-explorer-11.token.tsimport { inject, InjectionToken } from '@angular/core';import { userAgentToken } from './user-agent.token';export const isInternetExplorer11Token: InjectionToken<boolean> = new InjectionToken('Internet Explorer 11 flag', { factory: (): boolean => /Trident\/7\.0.+rv:11\.0/.test(inject(userAgentToken)), providedIn: 'root', });为了独自测试 Internet Explorer 11 标记提供程序,咱们能够用一个假值替换 userAgentToken。 ...

July 22, 2021 · 4 min · jiezi

关于angular:Angular-Component-延迟加载-Lazy-Load-的一个依赖注入的问题以及解决方案

StackOverflow上有个敌人遇到了一个问题: 在 feature module 里,对一个 Component 进行提早加载: 留神上图第 9 行,导入了 CommonModule. 这个被提早加载的 Component 的模板文件里,应用到了 async 这个 pipe,其实当初 CommonModule 里。然而,因为该 module 被提早加载,因而并未动态地定义在 feature module 的 declarations 模块里。所以,该 Component 被加载的时候,其上下文无法访问到 async pipe. 所以,最初会呈现运行时谬误: ERROR Error: The pipe 'async' could not be found! 解决方案,我曾经回复在 StackOverflow 里了: https://stackoverflow.com/que... 在被提早加载的 Component 里,将其所属的 feature module 的定义人工加上即可: import { ChangeDetectionStrategy, Component, NgModule } from '@angular/core';import { Product, provideDefaultConfig, CmsConfig } from '@spartacus/core';import { CurrentProductService, MediaModule, OutletModule, CarouselModule } from '@spartacus/storefront';import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';import { distinctUntilChanged, filter, map, tap } from 'rxjs/operators';import { CommonModule } from '@angular/common';import { RouterModule } from '@angular/router';@Component({ selector: 'app-product-images', templateUrl: './razer-product-images.component.html', changeDetection: ChangeDetectionStrategy.OnPush,})export class CustomProductImagesComponent { private mainMediaContainer = new BehaviorSubject(null); private product$: Observable<Product> = this.currentProductService .getProduct() .pipe( filter(Boolean), distinctUntilChanged(), tap((p: Product) => { this.mainMediaContainer.next(p.images?.PRIMARY ? p.images.PRIMARY : {}); }) ); thumbs$: Observable<any[]> = this.product$.pipe( map((p: Product) => this.createThumbs(p)) ); mainImage$ = combineLatest([this.product$, this.mainMediaContainer]).pipe( map(([, container]) => container) ); constructor(private currentProductService: CurrentProductService) {} openImage(item: any): void { this.mainMediaContainer.next(item); } isActive(thumbnail): Observable<boolean> { return this.mainMediaContainer.pipe( filter(Boolean), map((container: any) => { return ( container.zoom && container.zoom.url && thumbnail.zoom && thumbnail.zoom.url && container.zoom.url === thumbnail.zoom.url ); }) ); } /** find the index of the main media in the list of media */ getActive(thumbs: any[]): Observable<number> { return this.mainMediaContainer.pipe( filter(Boolean), map((container: any) => { const current = thumbs.find( (t) => t.media && container.zoom && t.media.container && t.media.container.zoom && t.media.container.zoom.url === container.zoom.url ); return thumbs.indexOf(current); }) ); } /** * Return an array of CarouselItems for the product thumbnails. * In case there are less then 2 thumbs, we return null. */ private createThumbs(product: Product): Observable<any>[] { if ( !product.images || !product.images.GALLERY || product.images.GALLERY.length < 2 ) { return []; } return (<any[]>product.images.GALLERY).map((c) => of({ container: c })); }}@NgModule({ imports: [ CommonModule, RouterModule, MediaModule, OutletModule, CarouselModule ], declarations:[CustomProductImagesComponent]})export class CustomProductImagesModule {}更多Jerry的原创文章,尽在:"汪子熙": ...

July 22, 2021 · 2 min · jiezi

关于angular:ngtemplate-ngcontent-ngcontainer-和-ngTemplateOutlet的区别

原文 明天当我在做 Angular 开发时,一个知识点引起了我的留神: 在查看 DOM 时,我看到 ngcontent 被 Angular 利用于元素。 嗯……如果它们蕴含了最终 DOM 中的元素,那么 \<ng-container> 有什么用? 过后我对 \<ng-container> 和 \<ng-content> 的区别感到困惑。 在寻求晓得我的问题的答案的过程中,我发现了 \<ng-template> 的概念。 令我诧异的是,还有另一个容易混同的概念: *ngTemplateOutlet。 我开始了我的旅程,寻求对两个概念的廓清,但当初我有四个,听起来简直一样! 你遇到过这种状况吗? 如果是,那么您来对中央了。 因而,事不宜迟,让咱们一一介绍。 1. \<ng-template>顾名思义,\<ng-template> 是一个模板元素,Angular 与构造指令(ngIf、ngFor、[ngSwitch] 和自定义指令)一起应用。 这些模板元素仅在存在构造指令时才起作用。 Angular 将宿主元素(指令所利用到的元素)包装在 \<ng-template> 中,并通过用诊断正文(diagnostic comments)替换它来应用实现的 DOM 中的 \<ng-template>。 思考一个简略的 *ngIf 示例: 下面显示的是 *ngIf 的 Angular 解释,也就是解除语法糖之后的理论代码。 Angular 将利用指令的宿主元素放在 \<ng-template> 中,并放弃宿主原样。 最终的 DOM 相似于咱们在本文结尾看到的: 2. \<ng-container> 咱们很多人编写这段代码的起因是无奈在 Angular 中的单个宿主元素上应用多个构造指令。 当初这段代码工作失常,但如果 item.id 是一个可能不须要的虚伪值,它会在 DOM 中引入几个额定的空 \<div> 。 ...

July 17, 2021 · 2 min · jiezi

关于angular:Angular-事件绑定语法在-SAP-Spartacus-Popover-Component-中的一个应用

要绑定到事件,请应用 Angular 的事件绑定语法。此语法由等号左侧括号内的指标事件名和右侧引号内的模板语句组成。在上面的示例中,指标事件名是 click ,模板语句是 onSave() 。 <button (click)="onSave()">Save</button>事件绑定侦听按钮的单击事件,并在产生单击时调用组件的 onSave()。 Spartacus 的一个例子: $event 是事件对象。 $event 对象通常蕴含该办法所需的信息,例如用户名或图片 URL。 指标事件决定了 $event 对象的状态。如果指标事件是来自原生 DOM 元素的,那么 $event 是一个DOM 事件对象,它具备 target 和 target.value 等属性。 看这个例子: <input [value]="currentItem.name" (input)="currentItem.name=getValue($event)">input 控件的 value,绑定到 Component 的 currentItem.name 属性。input 控件的 input 事件,每当触发时,会把 getValue 返回的后果,赋给 Component 属性 currentItem.name 这个绑定会在一个上下文中执行该语句,此上下文中蕴含 DOM 事件对象 $event。 Angular 会通过调用 getValue($event.target) 来获取更改后的文本,并用它更新 name 属性。 在模板中,$event.target 的类型只是 EventTarget。在 getValue() 办法中,把此指标转为 HTMLInputElement 类型,以容许对其 value 属性进行类型平安的拜访。 Spartacus 的这个例子,展现了如何通过 TypeScript 代码,判断 button 上触发的用户交互事件,到底是按钮被鼠标点击造成的,还是被键盘敲击造成的。 ...

July 15, 2021 · 1 min · jiezi

关于angular:Angular-library-学习笔记

原文 Use cases for Angular librariesAngular 库有 2 个常见用例: 构建可重用的组件库以在应用程序之间共享。构建共享服务层性能 - 例如。 用于解决内部数据源(例如 API)的客户端。尽管有很多 Angular 库非常适合我的项目的状况,但值得思考您的用例是否属于这些,因为它的确引入了一些保护开销。 请记住,您始终能够将性能编写为应用程序中共享 Angular 模块的一部分,并在必要时将其提取到库中。 Creating an Angular library project咱们将创立一个 Angular 库,以及一个应用该库的演示应用程序。 咱们能够应用以下命令创立这些: ng new example-component-library --create-application=falsecd example-component-libraryng generate library example-component-libraryng generate application example-component-library-app应用 --create-application=false 标记能够避免 Angular 创立名为“example-component-library”的应用程序,这是咱们想要给库自身而不是测试应用程序的名称。 如果咱们当初查看刚刚创立的工作区外部,咱们能够看到有一个我的项目文件夹,其中蕴含每个库(example-component-library)和应用程序(example-component-library-app)的子文件夹 咱们刚刚生成的。 还有一个蕴含 e2e 测试项目的第三个文件夹,咱们能够疏忽它。 应用上面的命令行独自 build library: ng build --project=example-component-library如果咱们查看 dist 文件夹,咱们将看到咱们的库曾经构建,并且在 build 文件夹中,咱们有许多不同的文件夹,其中蕴含实用于不同消费者的各种不同模块格局的应用程序,以及一个蕴含 TypeScript 定义。 bundles - UMD 模块格局。esm5 - 次要应用 es5 的模块格局,但也应用来自 es6 的导入/导出语法。esm2015 - 应用 es2015/es6 的模块格局。fesm5 - esm5 的扁平化版本。fesm2015 -peerDependencies esm2015 的扁平化版本。lib - 库的 TypeScript 定义。这种格局称为 Angular Package Format,它是用作 ng-packagr 输入的格局,ng-packagr 是 Angular CLI 用来编译库的工具。 ...

July 15, 2021 · 1 min · jiezi

关于angular:Angular-Package-Format-APF-v120-介绍

官网 本文档形容了 npm 上以后可用的 Angular 框架包的构造和格局。 这种格局实用于散发 Angular 组件的包(如 Angular Material)以及在@angular 命名空间下公布的外围框架包,如@angular/core 和@angular/forms。 此处形容的格局应用独特的文件布局和元数据配置,使包可能在应用 Angular 的大多数常见场景下无缝工作,并使其与 Angular 团队和社区自身提供的工具兼容。 出于这个起因,也强烈激励第三方库开发人员遵循雷同的构造。 格局的版本控制与 Angular 自身的版本控制统一,咱们心愿格局以向前兼容(forward-compatible)的形式倒退,以反对 Angular 组件和工具生态系统的需要。 Package format 的目标在当今的 JavaScript 环境中,开发人员将以多种不同的形式应用包。 例如,有些可能应用 SystemJS,有些可能应用 Webpack。 尽管如此,其他人可能会在 Node 或浏览器中应用包作为 UMD 包或通过全局变量拜访。 Angular 散发包反对所有罕用的开发工具和工作流,并强调优化,从而放大应用程序无效负载大小或放慢开发迭代周期(构建工夫)。 Library File layout库个别应该应用雷同的布局,但库中存在与 Angular 框架不同的个性。 通常,库是在组件或性能级别拆分的。咱们以 Angular 的 Material 我的项目为例。 Angular Material 公布了组件集,例如 Button(单个组件)、Tabs(一组协同工作的组件)等。共同点是将这些性能区域绑定在一起的 NgModule。 Button 有一个 NgModule,Tabs 有另一个,依此类推。 Angular Package Format 的个别规定是为最小的逻辑连贯代码集生成 FESM 文件。例如,Angular 包有一个用于@angular/core 的 FESM。当开发人员应用来自@angular/core 的 Component 符号时,他们很可能也会间接或间接应用诸如 Injectable、Directive、NgModule 等符号。因而,所有这些局部都应该捆绑在一起造成一个 FESM。对于大多数库状况,应该将单个逻辑组组合到一个 NgModule 中,并且所有这些文件应该捆绑在一起作为包中的单个 FESM 文件,代表 npm 包中的单个入口点。 ...

July 15, 2021 · 2 min · jiezi

关于angular:Angular-巧用component装饰器属性

带有 @Component() 装璜器的 TypeScript 类是 Angular 组件组成十分重要的一部分,罕用的属性有以下几种 selector: CSS 选择器,用于定义如何在模板中应用组件template或者templateUrl: HTML 模板styles或styleUrls: 一组可选的 CSS 款式还有一些不太罕用的属性,咱们一起来看看有哪些。 changeDetection应用形式: @Component({ selector: 'app-child', templateUrl: './child.component.html', styleUrls: ['./child.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush})changeDetection 用于给以后组件定义变更检测策略,当组件实例化之后,Angular 就会创立一个变更检测器,它负责流传组件各个绑定值的变动。源码中它的值为:changeDetection?: ChangeDetectionStrategy,咱们再来看看源码中ChangeDetectionStrategy是如何定义的 export declare enum ChangeDetectionStrategy { OnPush = 0, Default = 1}Default : 变更策略为 CheckAlways,默认值。这个没什么好说的,始终检测,即便组件内的属性和@Input属性都没有变动,也会一直检测变更OnPush : 变更策略为 CheckOnce(按需)。应用 ChangeDetectionStrategy.OnPush 也是优化性能的一种办法,毕竟它是按需检测嘛,不会不停的检测,然而应用它是有严格的条件的,不然一不小心就产生bug了,如果业务满足以下条件,能够放心使用: 组件的视图变动仅仅依赖 @Input 属性的变动,如果有依赖组件自身的属性则不能够当 @Input 属性为非对象的时候,或者为对象的时候的每次 @Input 属性的扭转是扭转对象自身的形式(eg: obj = xxx ),而不是扭转援用的形式( eg: obj.propertyName = xxx )。如果 @Input 属性的扭转是扭转援用的形式,还是想触发视图检测更改,还能够应用 ChangeDetectorRef 手动触发变更。哈哈,感觉越讲越多,changeDetection 能够独自写一篇了,如果大家有须要理解的,我再独自开一篇。好了,the next one~ ...

July 9, 2021 · 2 min · jiezi

关于angular:Angular工作区配置-angularjson参数配置详解以及多项目配置

Angular 工作区指的是由 Angular CLI 创立的利用或库,如果你的我的项目蕴含一些子项目能够在angular.json 的projects外面配置多个我的项目 JSON 的总体构造下列属性位于文件的顶层,用于配置工作区。CLI 在工作区级的默认设置能够被我的项目级的设置所笼罩,而我的项目级的设置能够被命令行中的设置所笼罩。 $schema:用于验证 JSON 数据格式version:该配置文件的版本(留神非我的项目版本)。newProjectRoot:用来创立新工程的地位,当应用 ng generate application/library 创立新的我的项目时,会主动放到该目录下defaultProject:默认值为用户执行 ng new projectName 时候的 projectName 的名称如果工作区存在多我的项目,defaultProject最好指定一下,不然在每个我的项目 ng serve 或 ng build 的时候须要指定项目名称 ng serve --project=projectNameprojects:对于工作区中的每个我的项目(利用或库)的配置项,key为我的项目的名称,value为具体的配置项。通过 ng new projectName 命令创立的初始利用会列在 projects 目录下 "projects": { "projectName": { ... } ...}PROJECTS-我的项目配置选项每个我的项目的 projects:<project_name> 下都有以下顶层配置属性。 "projects": { "projectName1": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "app", "schematics": {}, "architect": {} }, "projectName2": { ... }}root:我的项目的根文件夹,绝对于工作区文件夹的门路。初始利用的值为空,因为它位于工作区的顶层。sourceRoot:该我的项目源文件的根文件夹projectType:"application" 或 "library" ,application能够在浏览器中独立运行,而library则不行,library 是一个能够供很多利用共享的模块prefix:组件或指令的前缀。能够自定义它,以作为利用或功能区的标识。architect:我的项目构建器的配置选项schematics:用于定制 ng generate 子命令的默认选项, 例如: ...

July 8, 2021 · 2 min · jiezi

关于angular:深入理解-ngrx-effect-背后的工作机制

博客地址:https://indepth.dev/posts/120... an action is a constituent of a reducer, as well as of an effect. NgRx ensures that actions are first handled by the reducers, after which they will eventually be intercepted by the effects.actions 是 reducer 的组成部分,也是 effect 的组成部分。 NgRx 确保操作首先由 reducer 解决,之后它们最终会被 effect 拦挡。 Reducer 解决 action,而后被 effect 解析。 Providing the effectsforRoot 和 forFeature 接管的输出参数是其余 .ts 文件 export 的 class, 而不是具体的 class 实例。依据 class 取得 metadata. EffectsModule.forRoot 只能被调用一次,因为这个办法还会实例化其余 Ngrx 重要的服务,比方 EffectsRunner 和 EffectSources. ...

June 23, 2021 · 4 min · jiezi

关于angular:ElasticSearch启动报错-ERROR

ElasticSearch启动报错如下:ERROR: [4] bootstrap checks failed 第[1]-[2]项问题解决:应用root用户,编辑文件/etc/security/limits.conf,在文件的开端处,减少手游参数elk hard nofile 65536 #elk 为运行ElasticSearch程序的用户elk soft nofile 65536 #elk 为运行ElasticSearch程序的用户elk hard nproc 4096 #elk 为运行ElasticSearch程序的用户elk soft nproc 4096 #elk 为运行ElasticSearch程序的用户 保留并退出编辑 第[3]项问题解决:应用root用户,编辑文件/etc/sysctl.conf,在文件的开端处,减少如下参数vm.max_map_count = 655360保留并退出编辑sysctl -p //使配置失效 第[4]项问题解决:编辑elasticsearch目录下,config/elasticsearch.ymlwww.diuxie.com文件,批改如下的参数下如: cluster.initial_master_nodes: ["node-1", "node-2"]cluster.initial_master_nodes: ["node-1"]保留并退出编辑 而后应用elk用户重新启动ElasticSearch

June 22, 2021 · 1 min · jiezi

关于angular:slateangular-正式开源

本文由智能化研发管理工具PingCode前端工程师 杨振兴分享一句话介绍slate-angular 是一个基于 Angular 和 Slate.js 的编辑器视图层,帮忙开发者应用 Angular + Slate.js 构建Web富文本编辑器。 Slate.js 介绍Slate.js 是一个特地优良的富文本编辑器框架,代码整洁、架构良好、扩展性强,目前市面上基于 Slate.js 开发的富文本编辑器及产品曾经不可胜数。而且 Slate.js 足够有魔力,从开始接触富文本编辑器开发到当初两年左右的工夫,感觉 Slate.js 始终是我成长的良师,从最后的入门调研,到开发出第一个版本编辑器,而后是视图层架构的降级,再到前面的性能及稳定性的优化,每一个阶段都能从 Slate.js 身上学到很多货色,当然对它的理解也越来越深。我感觉 Slate.js 就是一个本身在一直地迭代和改良的编辑器框架,专一于视图层和模型层,架构实现始终紧跟社区支流技术的倒退,内容编辑的实现机制也在一直地向现行标准事件聚拢,曾经开源5年左右的工夫,目前社区依然十分沉闷,还在一直地扩大更多的实用场景,是十分厉害的一个存在。 自研Angular视图层咱们的前端技术栈是 Angular,开源社区中基于 Angular 开发的富文本编辑器极其稀缺,而咱们要做的 PingCode Wiki 产品又对富文本编辑器的易用性和可扩展性要求极高,调研发现Slate编辑器框架十分合乎咱们的需要,外围模型层不依赖任何前端框架,可扩展性极其高,有残缺的测试笼罩,所以咱们尝试自研基于 Angular 的视图层,能够了解为自研视图层的外围驱动来源于产品。 集体感觉开发基于 Angular 的视图层是一个很有意义的过程,并且以后开源社区中还没有应用 Angular 开发 Slate 编辑器的实现,所以咱们想把咱们的这种实际成绩开源进来,以回馈 Slate 和 Angular 社区,让更多的开发者能够基于 Angular + Slate 开发富文本编辑器。 开源之路以后 slate-angular 曾经反对企业级知识库产品 PingCode Wiki 稳固运行超过1年,最后版本是基于 Slate@0.47.0版本(JavaScript版本Slate),第二版是基于最新Slate的实现(TypeScript),以后曾经是第三版,从年初就开始筹备,包含公开Github仓储、对立底层的实现及API格调、搭建在线Demo、补充单元测试、同步降级最新 Slate 等。 Demo 性能: github:https://github.com/worktile/s...demo :http://slate-angular.ngnice.com/slate-angular 可能不是一个开箱即用的富文本编辑器,它属于Slate框架的一个视图层,对接Slate框架底层与用户交互界面的一个中间层,它仅提供根底的富文本编辑能力和性能扩大的插槽,但这也是slate-angualr的劣势,它只专一底层的实现:兼容浏览器、挪动端、代理输出事件、代理光标、反对自定义Element/Text/Leaf节点的渲染、解决根底交互等,基于它能够很快开发出像 Quill、Prosemirror 这类有肯定根底性能的富文本编辑器,并且它的可扩大下限很高,通过肯定的工夫齐全能够构建出像 Confluence、Notion、PingCode Wiki 这种性能级别的富文本编辑器。 个性反对 集成块级元素前后光标计划反对扩大指定元素渲染前后光标,不便在块级元素前后插入段落(表格Demo中曾经实现块级光标的根本交互)自定义组件/模版渲染块级元素反对多层级元素内容的自定义渲染,可不便实现像表格这类简单场景的需要,同时维持了自定义组件之间的正确的依赖注入链,也就是单元格组件能够通过依赖注入获取父级表格组件的服务自定义渲染 Text反对自定义Text节点的内容渲染,这个在 slate-react 中是不提供的,slate-angular 中独自提出来了,次要用于实现加粗、斜体、下划线、色彩、背景色等需要自定义渲染 Leaf反对自定义Leaf 节点的渲染,Leaf是对Text的拆分,每一个Text节点默认对应一个Leaf,而Text节点拆分Leaf的根据是Decoration装璜器,次要用于实现对文本的动静润饰,配合自定义Leaf组件实现搜寻高亮、划词评论等需要Decoration 装璜器提供对文本内容的动静润饰,是由内部数据驱动定位、装璜文本内容。它的特点是在不扭转原始数据的状况下实现对文本的装璜,是解决动静需要的一种形式Void元素Void意为不可编辑,所有内容属于一个整体,slate-angular 反对扩大Void元素,通过Void元素能够把任意简单的Angular组件的嵌入到编辑器中,比方图片、代码编辑器、甘特图等都能够嵌入到编辑器内容区域中。兼容浏览器Chrome、Edge、Safari、Firefox、QQ Browser ...

June 22, 2021 · 1 min · jiezi

关于angular:程序-ICS4U-Lab-1难点解析

ICS4U - Lab 1Objective This lab is designed to give you experience in creating and using objects. Part 0 – TwoByTwoMatrix Class – TwoByTwoMatrix.java You are to create a class called TwoByTwoMatrix containing fields and methods that could be used by a main method in another class to manipulate 2 by 2 matrices in various ways. A TwoByTwoMatrix is defined by the following fields: class TwoByTwoMatrix{double a; // Top left elementdouble b; // Top right elementdouble c; // Bottom left elementdouble d; // Bottom right element ...

June 14, 2021 · 6 min · jiezi

关于angular:Angular-登陆注销

前言之前始终感觉本人对登陆登记把握的很好,无非就是登陆的时候一个验证用户名明码,设置判断登陆的标记,就有点飘,始终没有认真看代码是怎么实现的,包含到上次老师让我写登陆和集体核心的时候才意识到本人还没有搞清楚很多细节(对我来说)。 登陆一、验证用户名明码首先说一下我对登陆的了解,首先说登陆须要什么,咱们通常登陆须要用户名,明码,以上两者为登陆须要的客体,想要实现登陆这个性能我还须要解决客体的办法,这就波及到了匹配用户,验证用户名明码是否正确,想要实现这个性能只须要拿着用户名( 如果用户名惟一)去数据库找相应的user信息,而后将用户所输出的明码通过与用户本人设置或者初始密码雷同的加密形式加密后比照两者一不一样即可。二、登陆状态的设定以上都很简略就是,因为波及不到多个组件,只是单纯的前台通过浏览器给后盾信息,后盾去找数据库取信息而后匹配返回后果而已,而我真正疏忽最多的是登陆的状态设置,我之前是没有认真看过登陆状态的设置的,为什么在用户登录之后咱们要设置一个用户曾经登陆的状态,为什么要存这种状态呢? 1、登陆状态存储咱们通常在浏览界面的时候必定会经常出现刷新页面的状况,而咱们每次刷新页面,浏览器都会申请一次前台,从新跑一次前台的代码,这就会导致咱们每刷新一次都必须得从新登录一次,为了防止此这种状况的产生,浏览器为咱们提供了三个内置对象document.cookie、Window.sessionStorage、Window.localStorage,这三个对象都能够长期存储一些数据,从而解决此问题。然而这三者不是齐全一样的,需依据需要选取不同的对象,区别如下:在用户未登录时咱们须要让用户拜访登陆界面,在登录之后间接进入首页V曾能够这样写咱们须要读取登录状态的时候就能够间接读取三个之中的一个对象外面保留的信息。如下:在app.component.ts初始化的时候先对Window.sessionStorage里的login属性设置为true。 2、用户信息存储再刷新页面的时候浏览器通常会从新申请服务器,比方咱们当初浏览的界面是集体核心,那么如果咱们没有保留数据,刷新界面之后 又会从新从首页开始加载,为了解决这个问题咱们须要把用户的数据保留下来,此时咱们能够用到x-auth-token,这个x-auth-token也是window.sessionStorage中的一个属性 登记登记相对来说就比拟容易了,点击登记后 ,登录状态变为false,后盾删除token即可。 版权申明本文作者:河北工业大学梦云智开发团队 - 陈丽婷

June 12, 2021 · 1 min · jiezi

关于angular:Angular-使用-Injector-API-人工获取依赖注入的实例

这个例子的残缺源代码: import { Component, OnInit, Injectable, Injector } from '@angular/core';@Injectable()class UsefulService { constructor(){ console.log("Useful Service is created"); }}@Injectable()class NeedsService { constructor(public service: UsefulService) { console.log("NeedsService is created"); }}const injector = Injector.create({ providers: [{ provide: NeedsService, deps: [UsefulService] }, { provide: UsefulService, deps: [] }]});console.log(' true or false?' , injector.get(NeedsService).service instanceof UsefulService);@Component({ selector: 'manual_di', template: '<p>Manual DI </p>'})export class ManualDIComponent implements OnInit { constructor() { } ngOnInit(): void { }}单步调试Injector.create由实现源代码可见,Angular NgModule providers 元数据反对 name 参数: ...

June 5, 2021 · 1 min · jiezi

关于angular:Angular-Reactive-Form-的一个具体使用例子

在 module 实现里,务必导入下列 module: import { ReactiveFormsModule } from '@angular/forms'; template 实现代码: <input type="text" [formControl]="jerryFormControl"><div>{{ response }}</div>其中 formControl Directive,绑定的是 FormControl 具体实例。Component 残缺的实现代码: import { Component, OnInit } from '@angular/core';import { FormControl } from '@angular/forms';import { HttpClient} from '@angular/common/http';import { throttleTime } from "rxjs/operators";// this endpoint is implemented in https://github.com/wangzixi-diablo/ui5-toolset, local.jsconst APIENDPOINT = "http://localhost:3000/echo?data=";@Component({ selector: 'jerryform', templateUrl: './react-form.component.html'})export class JerryReactFormComponent implements OnInit { constructor(private http:HttpClient){} response = ''; onValueChanged = (value)=>{ console.log('new value from live change: ' + value); const url = `${APIENDPOINT}${value}`; const options = { responseType: 'text' as 'json' } var $http = this.http.get(url, options); $http.subscribe( (response:string)=>{ console.log('response from http: ' + response); this.response = response}, (error)=>console.log('error: ' + error)); } ngOnInit(): void { // this.jerryFormControl.valueChanges.pipe(debounceTime(3000)).subscribe(this.onValueChanged); this.jerryFormControl.valueChanges.pipe(throttleTime(2000)).subscribe(this.onValueChanged); } jerryFormControl = new FormControl('');}在 Component 的实现代码里,咱们并不会间接操作 template 里的 input 标签,而是通过其绑定的 formControl 实例 jerryFormControl 暴露出的 valueChanges Observable,来注册咱们应用程序本人的逻辑,即事件响应函数 onValueChanged. ...

June 5, 2021 · 1 min · jiezi

关于angular:利用-Angular-Directive-和-HostBinding-实现输入文本框随着键盘输入自动变色效果

假如有这样一个需要:咱们须要加强 HTML 里原生的 input 标签,让其达到,随着用户输出字符时,其色彩主动切换的成果。 这是一个典型的能够应用 Angular Directive 实现的需要。 每个 Directive 都有一个 host 元素。 Decorator that marks a DOM property as a host-binding property and supplies configuration metadata. Angular automatically checks host property bindings during change detection, and if a binding changes it updates the host element of the directive.Directive 里,批改 @HostBinding 润饰的 Directive 属性,就相当于批改了 DOM 元素的属性自身。 同理,通过 @HostListener 润饰的事件处理函数,在 host 元素产生对应的事件之后,会主动被触发。 Rainbow 指令残缺的实现代码: import { Directive, HostBinding, HostListener } from '@angular/core';@Directive({ selector: '[appRainbow]'})export class RainbowDirective{ possibleColors = [ 'darksalmon', 'hotpink', 'lightskyblue', 'goldenrod', 'peachpuff', 'mediumspringgreen', 'cornflowerblue', 'blanchedalmond', 'lightslategrey' ]; @HostBinding('style.color') color: string; @HostBinding('style.borderColor') borderColor: string; @HostListener('keydown') onKeydown(){ const colorPick = Math.floor(Math.random() * this.possibleColors.length); console.log('Jerry colorPick: ' + colorPick); this.color = this.borderColor = this.possibleColors[colorPick]; }}生产这个指令的办法非常简单: ...

June 5, 2021 · 1 min · jiezi

关于angular:从-ng-build-支持的参数-prod谈谈-Angular-workspace-configuration

语法:ng build project options 作用:编译 Angular 利用到 output 文件夹里,通常名称为 dist. 必须在工作空间目录下执行。 输出参数:project, 能够为利用或者 library. 反对的参数应用 ng build --help 查看所有反对的参数。 其中这个选项值得一说:--prod Shorthand for "--configuration=production". 是 --configuration=production 的简写模式。 When true, sets the build configuration to the production target. 将 build configuration 设置成 production target. By default, the production target is set up in the workspace configuration such that all builds make use of bundling, limited tree-shaking, and also limited dead code elimination.默认状况下,production target 在工作空间配置中设置,参考官网。 ...

June 4, 2021 · 3 min · jiezi

关于angular:Angular-依赖注入学习笔记之工厂函数的用法

网址:https://angular.institute/di We can transfer any data through our apps, transform it and replace it.咱们能传递任何数据到咱们的利用里,扭转其状态,并且替换。 Another case: document and fetch can work in your browser correctly. But one day you need to build your app in SSR or precompile with nodejs. Global entities might be missing or be different in that environment.document 和 fetch 能在浏览器环境下运行。然而如果在 SSR 下 build 利用,或者用 nodejs precompile,那么这些对象在新的环境下不再可用。 Dependency Injection mechanism manages dependencies in your application. For you as an Angular developer, it is a straightforward instrument. There are two operations: you can provide something into your DI tree or take something from it.依赖注入机制治理利用的依赖。对于 Angular 开发者来说,有两种操作: ...

May 23, 2021 · 3 min · jiezi

关于angular:Angular-Universal-学习笔记-客户端渲染和服务器端渲染的区别

https://github.com/angular/un... Universal 的命名由来: We believe that using the word "universal" is correct when referring to a JavaScript Application that runs in more environments than the browser. (inspired by Universal JavaScript)参考了一个能运行在除浏览器之外的其余环境下的 JavaScript 利用。 Angular Express EngineThis is an Express Engine for running Angular Apps on the server for server side rendering.可能让 Angular 利用运行在服务器端。 应用形式: import * as express from 'express';import { ngExpressEngine } from '@nguniversal/express-engine';const app = express();// Set the engineapp.engine( 'html', ngExpressEngine({ bootstrap: ServerAppModule, // Give it a module to bootstrap }),);app.set('view engine', 'html');app.get('/**/*', (req: Request, res: Response) => { res.render('../dist/index', { req, res, });});留神:我在 server.ts 里做了批改,加上了 console.log: ...

May 23, 2021 · 2 min · jiezi

关于angular:对Angular-路由出口-routeroutlet-的理解

前言始终认为本人对路由了解的还不错,然而昨天写路由的时候发现自己对angular 中的router-outlet的了解还不透彻,在此想说一下我对router-outlet的了解。 什么是路由首先说一下什么是路由,集体了解路由就相当于一个路线的方向或者说是目的地,路由阐明了下一个跳转的链接。路由定义大部分都是在模块之间,通常利用url助手函数生成相应的路由,此外路由还能够加一些参数,比方 id、name等。 angular 路由的作用如定义所说,路由既然相当于目的地,那么路由的作用就是导航,能够实现页面的切换,通过生成地址链接,跳到下一个咱们想拜访的页面。 路由进口 router-outlet 匹配路由的办法对于router-outlet来说,他会通过门路的代码,联合路由跳到相应的组件,比方:此图中的children上面的路由的意思是多个进口,上面每一个path都对应一个组件,其中loadChildren那一行是惰性加载,就是说用到谁,就去找谁加载谁,即按需加载,这样的话能够缩小加载工夫,因为这样的话就防止了每一次起我的项目都会加载所有组件,造成缓存加大,加载工夫长的坏状况。此为v层中定义的路由进口,此写法意味着该标签的name属性值默认为primary也就是联合路由定义中children中的path和地址链接去拜访相应模块。然而当咱们手动定义name属性的时候就不一样了。如果咱们手动定义name属性的话,那么咱们往往会在路由设定时设置outlet的值,留神:outlet属性的值要和咱们v层<router-outlet>标签的name属性的值绝对应,path应为<base-path>,从而可能让angular可能晓得咱们读取到哪个文件对应标签的name属性之后应该匹配哪个path,进而跳转到咱们冀望的路由。当然,咱们还能够本人定义当路由是什么的时候,让其跳转到咱们想要的另一个链接,如下图:本图的意思是当咱们本级路由为空的时候,主动重定向跳转到本级路由为login的界面,同时我须要AuthMoudle模块,再去加载相应模块。比方咱们输出localhhost:4200,他就会间接跳转到其下的login,即显示AuthMoudle模块 路由匹配流程图一图胜万言,废话不多说间接上图吧下面说了一大堆,不如间接看流程图来的简洁明了,这就体现了流程图的重要性。 总结把本人学到的货色写进去会给本人大脑一个明确的思路,让常识更加具体化,而不是隐隐约约,在写之前我可能对路由的了解没有当初这么清晰,然而写完之后就会发现自己脑子里的货色分明了很多,这是一种思维清晰化的过程。本文可能会有了解不到位或者不正确的中央,望斧正。 版权申明本文作者:河北工业大学梦云智开发团队 - 陈丽婷

May 15, 2021 · 1 min · jiezi

关于angular:技术实践丨如何解决异步接口请求快慢不均导致的数据错误问题

摘要:实时搜寻都会面临一个通用的问题,就是浏览器申请后盾接口都是异步的,如果先发动申请的接口后返回数据,列表/表格中显示的数据就很可能会是错乱的。本文分享自华为云社区《如何解决异步接口申请快慢不均导致的数据谬误问题?》,原文作者:Kagol 。 引言搜寻性能,我想很多业务都会波及,这个性能的特点是: 用户能够在输入框中输出一个关键字,而后在一个列表中显示该关键字对应的数据;输入框是能够随时批改/删除全副或局部关键字的;如果是实时搜寻 (即输出完关键字马上出后果,不须要额定的操作或过多的期待),接口调用将会十分频繁。实时搜寻都会面临一个通用的问题,就是: 浏览器申请后盾接口都是异步的,如果先发动申请的接口后返回数据,列表/表格中显示的数据就很可能会是错乱的。 问题重现最近测试提了一个搜寻(PS:此处的搜寻 就是用 DevUI 新推出的 CategorySearch 组件实现的)相干的缺点单,就波及到了上述问题。 这个bug单大抵意思是: 搜寻的时候,间断疾速输出或者删除关键字,搜寻后果和搜寻关键字不匹配。 从缺点单的截图来看,本意是要搜寻关键字8.4.7迭代】,表格中的理论搜寻后果是8.4.7迭代】过关键字的数据。 缺点单的截图还十分贴心地贴了两次申请的信息: 作为一名“有教训的”前端开发,一看就是一个通用的技术问题: 浏览器从服务器发动的申请都是异步的;因为前一次申请服务器返回比较慢,还没等第一次申请返回后果,后一次申请就发动了,并且迅速返回了后果,这时表格必定显示后一次的后果;过了2秒,第一次申请的后果才慢悠悠地返回了,这时表格谬误地又显示了第一次申请的后果;最终导致了这个bug。怎么解决呢? 在想解决方案之前,得想方法必现这个问题,靠后盾接口是不事实的,大部分状况下后盾接口都会很快返回后果。 所以要必现这个问题,得先模仿慢接口。 模仿慢接口为了疾速搭建一个后盾服务,并模仿慢接口,咱们抉择 Koa 这个轻量的 Node 框架。 疾速开始 Koa 应用起来十分不便,只须要: 新建我的项目文件夹:mkdir koa-server创立 package.json:npm init -y装置 Koa:npm i koa编写服务代码:vi app.js启动:node app.js拜访:http://localhost:3000/编写服务代码应用以下命令创立 app.js 启动文件: vi app.js在文件中输出以下 3 行代码,即可启动一个 Koa 服务: const Koa = require('koa'); // 引入 Koaconst app = new Koa(); // 创立 Koa 实例app.listen(3000); // 监听 3000 端口拜访如果没有在3000端口启动工作服务,在浏览器拜访: http://localhost:3000/ 会显示以下页面: 启动了咱们的 Koa Server 之后,拜访: ...

May 11, 2021 · 3 min · jiezi

关于angular:Angular-项目里-angularjson-文件内容的学习笔记

看一个基于 Angular 的 SAP Spartacus 我的项目里 angular.json 的例子: version: The configuration-file version.newProjectRoot: Path where new projects are created. Absolute or relative to the workspace folder.defaultProject: Default project name to use in commands, where not provided as an argument. When you use ng new to create a new app in a new workspace, that app is the default project for the workspace until you change it here.schematics : A set of schematics that customize the ng generate sub-command option defaults for this workspace. See Generation schematics below.projects : Contains a subsection for each project (library or application) in the workspace, with the per-project configuration options. ...

May 3, 2021 · 4 min · jiezi

关于angular:SAP-Spartacus-B2B-OrgUnit-和-OrgUser-的路由映射差异比较

SAP Spartacus B2B 页面相似 SAP Fiori Launchpad,共有 6 个 tile(磁贴),点击某个磁贴,能跳转到对应的列表页面。 路由映射就是指点击某个 url 之后(例如上图所示的例子),应该激活哪一个 Angular Component. 例如上图 User tile,通过 a 标签实现,点击之后,会跳转到其 href 属性指向的 url:http://localhost:4200/powerto... 问题是,这个 url ,对应 SAP Spartacus 里哪个 Angular Component 么? 咱们能够通过查问源代码的形式自行找到答案。 和 B2B User tile 相干的配置,都保护在文件 user.config.ts 里, orgUser 的门路为 organization/users: 这里就能找到 User tile 对应的 Angular Component了。 ManageUsersListComponent 对应 ListComponent: 对于 Org Unit 来说,路由配置的格局同 User 一样: 这里同 User Mapping 实现有差别。在 User CMS mapping 里,ManageUsersListComponent 对应 ListComponent,而对于 Org Unit,Commerce 后盾 ManageUnitsListComponent,映射到 SAP Spartacus Component 是 UnitListComponent,而不是更通用的 ListComponent. ...

May 3, 2021 · 1 min · jiezi

关于angular:详解-Angular-动态视图-二-CDK-Portal

上一篇介绍了原生 API 的动静视图插入,性能上曾经能够满足大多数应用场景。不过也有一些缺憾,还没有解决在 Angular 利用外插入内容的需要,指令也不能跟动静插入的组件有输入输出的交互。这就到了 CDK(Component Dev Kit)出场的时候了 Angular 官网提供了一套组件开发套件 Component Dev Kit (CDK),作为各种 Angular 组件开发的根底工具,其中就提供 “Portal(传送门)” 来辅助动静视图的创立。 这个 ”动静视图“ 能够是组件、TemplateRef 或者 DOM 元素,别离对应三种 Portal 类型(ComponentPortal、TemplatePortal、DomPortal)。它们三个的形象泛型基类是 Portal<T>,有三个办法:attach(挂载到容器)、detach(从容器移除)、isAttached(判断视图是否是挂载状态)。 而容器也是由一个抽象类 BasePortalOutlet 定义,和视图相似,蕴含 attach(给容器挂载视图)、detach(从容器移除视图)、dispose(销毁容器)、isAttached(是否有挂载视图)。它的次要实现是 DomPortalOutlet 类。用以挂载三种类型的动静视图。 创立动静内容先来看看三种动静视图的创立。 ComponentPortal相比原生 API,要创立一个动静组件十分的简略,只须要把组件类传入 ComponentPortal 构造函数即可。 this.componentPortal = new ComponentPortal(ExampleComponent);能够传入任意自定义的组件类,用以创立 ComponentPortal 对象,再动静插入视图中。 ✨留神:Angular 9 后的版本举荐应用 Ivy 编译器,如果是老版本编译器,传入的组件类,须要在 Module 的 entryComponents 中申明,并且这个 Module 不能懒加载。 TemplatePortalTemplatePortal 的构建,相比组件,多了一个参数(ViewContainerRef)。看过前一篇应该对它十分相熟了,须要依赖它调用 createEmbeddedView() 来创立嵌入视图。这里通过结构注入,间接应用以后组件的 ViewContainerRef 实例。 <ng-template #testTemplate> <p>一些须要动静插入的内容.</p></ng-template>@ViewChild('testTemplate') templatePortalContent: TemplateRef<any>;constructor(private _viewContainerRef: ViewContainerRef) { }ngAfterViewInit() { this.templatePortal = new TemplatePortal( this.templatePortalContent, this._viewContainerRef );}除了通过构造函数,TemplatePortal 也有一个指令(CdkPortal)能够便捷创立。 ...

April 8, 2021 · 2 min · jiezi

关于angular:详解-Angular-动态视图-一-原生-API

动静渲染视图是日常我的项目开发中常见的需要,特地是通用性的工具库开发。例如弹窗服务,须要让组件的用户决定传入什么内容进行渲染,可能是一个组件,可能是一个模板(ng-template)。这里先来看看通过 Angular API 如何去实现。 要动静的插入一个视图,Angular 提供了一套 API 负责创立容器,实例化组件,以及治理视图和数据。同时,它还额定提供了一些指令,不便疾速的实现。它们各有各自实用场景,本篇具体来看看它们的应用。 残缺的示例代码能够查看 GitHub 我的项目仓库,或者在线查看成果 在线示例。 ViewContainerRef 容器动静视图的外围是视图容器,它决定了视图的插入地位,用 ViewContainerRef 类示意。要创立它很简略,假如组件视图中有:<ng-container #dynamicHost></ng-container> 通过 @ViewChild 装璜器读取即可: @ViewChild('dynamicHost', { read: ViewContainerRef }) container!: ViewContainerRef;这段代码的留神点有: @ViewChild 用来从组件视图中获取元素的援用,能够是 DOM 对象、子组件或者指令的实例、或是某个依赖注入的 Provider。第二个参数中的 read 批示具体获取哪个类型,例如从 <button mat-button> 能够获取到这个 button 元素对象,也能够是这个标签上增加的 Material 按钮指令。 要获取一个容器,并非只能应用 <ng-container>,<ng-template> 、组件或者别的 DOM 标签都能够。尽管是叫容器,不过插入的内容可不是在这个 <ng-container> 标签内,而是在它的下方(相似 <router-outlet>)。所以应用 ng-container 是为了不渲染多余的 DOM。ViewContainerRef 实例能够创立、插入、移除、挪动或是销毁它其中的视图(ViewRef)。视图代表着 Angular中可显示元素的最小分组单位,它由组件或者模板定义。多个视图结构成了 Angular 利用的视图树。 ✨扼要起见,后文都将 ViewContainerRef 实例称之为 “视图容器” 以代码形式插入视图容器有两个办法(createComponent,createEmbeddedView),用来动态创建组件视图和模板视图。 动静插入组件首先创立一个用于动静插入的组件,这个告诉组件省略了具体款式,详情能够查看源码。能够留神到,这个组件有一个输出属性,一个输入事件。以便演示动态创建的组件,如何和外界交互。 @Component({ template: ` <div class="alert-container mat-elevation-z2" [class]="classConfig()"> <span class="message">{{message}}</span> <button mat-button (click)="emitCloseEvent()">敞开</button> </div>`})export class AlertComponent { @Input() message = '空音讯提醒'; @Input() type = 'success'; @Output() closeAlert = new EventEmitter(); classConfig() { return { success: this.type === 'success', warning: this.type === 'warning' }; } const emitCloseEvent(): void { this.closeAlert.emit(); }}✨留神:Angular 9 后的版本默认应用 Ivy 编译器,如果是应用老版本编译器,这个须要动静插入的告诉组件,须要在 Module 的 entryComponents 中申明,并且这个 Module 不能懒加载。 ...

March 22, 2021 · 2 min · jiezi

关于angular:angularvuereact路由传参对比

依据router上的存储对象名分2类 paramsqueryParams依据href的展示和应用办法分3类 500/jack (params)/500;name=jack (params)/500?name=jack (queryParams)以下依照3类的传值办法提供代码样例 Angular1 500/jack // routes的配置{ path: '500/:name', component: Exception500Component }"500/jack" //地址体现//导航的两种写法<button [routerLink]="['/500','jack']">测试1</button> navigateTo(){ this.router.navigate(['/500','jack']) } //接管参数的两种写法 依据须要来抉择activatedRoute.snapshot.params // {name:'jack'}activatedRoute.params.subscribe(data=>{ //data {name:'jack'} })2 /500;name=jack //地址体现"/500;name=jack"//导航的两种写法<button [routerLink]="['/500',{name:'jack'}]">测试1</button>navigateTo(){ this.router.navigate(['/500',{name:'jack'}]) }// 接管参数的两种写法 依据须要来抉择activatedRoute.snapshot.params // {name:'jack'}activatedRoute.params.subscribe(data=>{ //data {name:'jack'} })3 /500?name=jack "/500?name=jack" //地址体现<button [routerLink]="['/500']" [queryParams]="{name: 'jack'}">测试1</button>navigateTo(){ this.router.navigate(['/500'],{queryParams:{name:'jack'}}) } // 接管参数的两种写法 依据须要来抉择activatedRoute.snapshot.queryParams // {name:'jack'}activatedRoute.queryParams.subscribe(data=>{ //data {name:'jack'}})vue-router(未完待续) 1 500/jack // routes的配置{ path: '500/:name', component: Exception500Component }"500/jack" //地址体现//导航的两种写法<button [routerLink]="['/500','jack']">测试1</button> navigateTo(){ this.$router.push(['/500/jack']) } //接管参数的两种写法 依据须要来抉择this.$route.params // {name:'jack'}2 /500;name=jack ...

March 1, 2021 · 1 min · jiezi

关于angular:Angular11自学第二天创建一个组件

在终端窗口中,导航到要搁置你利用的目录。运行 ng generate component components/news 命令,其中 news 是新组件的名字。默认会创立在app目录下同时在app.module.ts文件下申明以上都是执行ng generate component components/news后主动实现的也可手动创立组件 @Component是个装璜器装璜器装璜器是一种函数,写成@ + 函数名。它能够放在类和类办法的定义后面。留神,装璜器对类的行为的扭转,是代码编译时产生的,而不是在运行时。这意味着,装璜器能在编译阶段运行代码。也就是说,装璜器实质就是编译时执行的函数。顺便温习一手ts

February 26, 2021 · 1 min · jiezi

关于angular:Angular11自学第一天

Angular 须要 Node.js V10.9.0或更高版本。npm应用国内淘宝镜像的办法 npm install -g @angular/cling : 无奈加载文件 C:\Users\Administrator\AppData\Roaming\npm\ng.ps1,因为在此零碎上禁止运行脚本 ng new my-appcd my-appng serve --open

February 25, 2021 · 1 min · jiezi

关于angular:JSP和Servlet的性能优化

在本文中,率领你学习曾经实际和失去证实的性能调整技术,它将大大地进步你的servlet和jsp页面的性能,进而晋升J2EE的性能。这些技术的局部用于开发阶段,例如,设计和编码阶段。另一部分技术则与配置相干。 技术1:在HttpServlet init()办法中缓存数据 服务器会在创立servlet实例之后和servlet解决任何申请之前调用servlet的init()办法。该办法在servlet的生命周期中仅调用一次。为了进步性能,在init()中缓存静态数据或实现要在初始化期间实现的代价低廉的操作。例如,一个最佳实际是应用实现了 javax.sql.DataSource接口的JDBC连接池。DataSource从JNDI树中取得。每调用一次SQL就要应用JNDI查找 DataSource是十分低廉的工作,而且重大影响了利用的性能。Servlet的init()办法能够用于获取DataSource并缓存它以便之后的重用: 以下是援用片段: public class ControllerServlet extends HttpServlet { private javax.sql.DataSource testDS = null; public void init(ServletConfig config) throws ServletException { super.init(config); Context ctx = null; try { ctx = new InitialContext(); testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS"); } catch(NamingException ne) { ne.printStackTrace(); } catch(Exception e) { e.printStackTrace(); } } public javax.sql.DataSource getTestDS() { return testDS; } ... ... } 技术2:禁用servlet和Jsp的主动装载性能 当每次批改了Servlet/JSP之后,你将不得不重新启动服务器。因为主动装载性能缩小开发工夫,该性能被认为在开发阶段是十分有用的。然而,它在运行阶段是十分低廉的;servlet/JSP因为不必要的装载,减少类装载器的累赘而造成很差的性能。同样,这会使你的利用因为已被某种类装载器装载的类不能和以后类装载器装载的类不能相互协作而呈现奇怪的抵触景象。因而,在运行环境中为了失去更好的性能,敞开servlet/JSP的主动装载性能。 技术3:管制HttpSession 许多利用须要一系列客户端的申请,因而他们能相互相关联。因为HTTP协定是无状态的,所以基于Web的利用须要负责保护这样一个叫做 session的状态。为了反对必须保护状态的利用,Java servlet技术提供了治理session和容许多种机制实现session的API。HttpSession对象表演了session,然而应用它须要老本。无论何时HttpSession被应用和重写,它都由servlet读取。你能够通过应用上面的技术来进步性能: 在JSP页面中不要创立默认的HttpSession:默认状况下,JSP页面创立HttpSession。如果你在JSP页面中不必HttpSession,为了节俭性能开销,应用下边的页面指令能够防止主动创立HttpSession对象: 以下是援用片段: ...

January 25, 2021 · 1 min · jiezi

关于angular:元数据驱动的-SaaS-架构与背后的技术思考

简介: 在形象能力以及积淀了产品的根底上,把所承载和积淀的业务能力疾速输入,奉献给整个行业。道冲而用之或不盈,渊兮似万物之宗。 —老子 引言作为业务零碎技术开发同学,面向当下: 首先应该是疾速搭建业务通路,让线上业务跑起来,疾速试错,解决生存问题;第二步是在链路畅通、业务根本跑起来的根底上,如何撑持业务跑得更快,就须要解决快速增长问题;第三步,在实现撑持业务快速增长的根底上,要进行精细化晋升,通过在撑持业务快跑间隙挤时间打磨零碎性能和体验,踏踏实实花工夫去形象能力,积淀产品,晋升效力;同时咱们也必须面向未来,如何在形象能力以及积淀了产品的根底上,把所承载和积淀的业务能力疾速输入,奉献给整个行业,或为整个社会商业生态提供基座撑持。面向未来,将平台产品进行 SaaS 化降级,真正将能力进行有价值凋谢输入是咱们提前要布局的外围方向。 将平台产品进行 SaaS 输入,须要解决那些问题呢?这里尝试把外围问题列举一下: 如何依据不同用户需要进行计算能力按需调度调配?(IaaS/PaaS)如何满足用户数据安全性要求,严格隔离不同用户的数据,使用户只能看到本人的数据?(PaaS)如何反对不同用户在规范的数据对象/数据模型上按需增加自定义的数据对象/扩大模型?(PaaS & SaaS)如何依照不同用户进行按需性能搭配组合,满足不同用户从根底到专业级不同业务场景需要?(SaaS)如何对立对平台产品进行降级而不影响用户已有数据及性能?(IaaS、PaaS、SaaS)通过以上问题,咱们能够看出,产品 SaaS 化输入的要害是如何对不同的用户通过规范+扩大能力按需进行算力、数据、平安、性能无效定制,反对多用户共性和共性的问题,即多租户的问题,同时也波及到计费和服务水平等相干问题。咱们上面来聊下上述问题的解题要害和解题思路: 第1个算力问题的外围是调度问题,弹性计算提供在 IaaS 层的对立算力调度能力,而 Serverless 则能够在 PaaS 层提供更高层次的算力调度能力。第4个问题的外围是业务流程的形象和业务性能的拆分。畛域驱动设计以及服务化(微服务)在平台性能形象拆分上提供了绝对成熟的思路,催化了以纵向业务性能细分作为域划分的根据的服务化计划以及组织构造,次要诉求是在细分的业务性能服务根底上,能按需疾速灵便的组合,从而撑持不同的业务模式,提供业务敏捷性,撑持业务翻新求变。当然反过来,因为纵向性能细分,业务功能域增多,整个业务链条上的咬合点越来越多,随之产生越来越多的数据起源冗余反复或者缺失,性能或者重合且各自发散,或者缺失,最终给整体业务带来较多数据和性能的不一致性危险。这样一来,不仅横向端到端的业务串联老本高,而且要害门路的危险收敛老本比拟高,矛盾冲突点集中在各纵向域性能和数据咬合处,具体表现为: 数据上: 无主数据,有数据需要无 owner;大量反复且不统一数据;性能上: 局部业务性能缺失;域之间存在业务性能反复且行为不统一。到底是纵向切分域还是横向分业务模式拉平来做,这个问题没有标准答案,更没有最佳答案。只有依据不同的业务倒退阶段及时动静调整试错,换言之,这是一个一直寻找绝对最优解的动静过程。 弹性计算和 Serverless 解决了算力的问题,畛域驱动服务化设计解决了性能的拆分和按需搭配组合的问题,那么剩下的外围问题就是数据了:如何以一套对立的数据架构,既能撑持多租户的数据安全性需要以及通用的数据存储,也能撑持用户扩大的自定义数据对象定义和模型变更,同时也要保证数据定义层面的扩大和变更不会影响本身和其余租户业务性能的可用性。咱们来剖析下可能的计划(暂不思考按服务边界进行数据库拆分): 对立的数据库,规范数据模型和扩大数据模型间接映射到物理表和索引:很显然,对于不同租户自定义的数据对象和数据模型要求是无奈撑持的,物理数据模型会互相烦扰、互相抵触直到无以为继。即便是对于所有租户齐全规范的性能和数据存储,平台本身的规范模型降级的 DDL 也会对用户的可用性造成较大影响,所以显然是行不通的。如果为每个租户创立各自的数据库呢?各自租户领有各自的数据库,能够满足用户数据安全隔离的需要,也能够满足各租户自定义的数据需要,看上去像是一种正当的 SaaS 数据计划。然而仔细分析,会发现有两个显著的问题:如果用户须要批改或者扩大现有物理数据模型而进行的 DDL 操作,必然会影响线上业务的整体可用性,也可能会影响到规范数据模型,从而影响到线上性能应用。如果用户可自定义对物理模型进行扩大和定制,当平台进行模型降级的时候,极容易产生物理模型的抵触,导致新旧性能异样。因为用户在各自数据库存在各自定义的扩大和定制,则平台数据模型和性能降级须要针对不同的租户进行别离验证,存在极大的降级验证工作量和危险。以上两种计划可行性低,咱们从其中发现的问题是:平台业务零碎的逻辑模型到物理模型的间接映射是造成问题的次要因素。既然物理模型的变更是平台不稳固的动因,那么咱们是否能通过解耦业务逻辑模型和物理模型的映射关系来尝试解决这个问题呢? 既然问题曾经定义分明了,如何解决这个问题呢?通常咱们解决架构问题的一个“万能”的办法是:减少一个档次,咱们也来套用一次,减少一个档次(元数据层)来解耦逻辑模型到物理模型强映射的问题。 首先,咱们须要对业务进行建模,对业务进行形象,定义出业务逻辑模型,而后对模型进行二次形象,定义出逻辑模型的定义数据,实现业务模型的数据化,即模型的元数据(The Metadata of the Logic Model ),将模型构造存储为数据,而不是间接对应的物理存储构造。 其次依据定义出的元数据进行对立形象,造成元数据逻辑模型。 将元数据逻辑模型映射到元数据物理模型,对应理论存储构造。 通过对业务模型的变更,造成对元数据层的数据变更,而不是物理构造的变更,从而实现业务逻辑模型同物理模型的解耦。 很多事件说起来如同挺简略,实际上是一个十分微小的系统工程,将其付诸实践是挑战十分大的事件,而获得踏踏实实的胜利则更难。上述问题的解题思路是 Salesforce 的解题思路,而且 Salesforce 不仅获得了胜利,也靠近将其做到了极致,上面咱们站在伟人的肩膀上来看看 Salesforce 如何通过元数据驱动的架构(外围是根底数据架构)来撑持多租户的 SaaS 业务平台。留神:因为 Salesforce 并未有对外围实现逻辑进行齐全公开和阐明,所以本文所整顿的局部外围逻辑蕴含了作者的逻辑推理和解读,然而的确进行了逻辑验证和场景验证,如有纰漏和不全面的中央,欢送探讨及斧正。 元数据驱动的多租户架构Salesforce 将 Force.com 定义为 PaaS 平台,Force.com 的根底就是元数据驱动的软件架构来撑持多租户利用。首先我来解释下什么是以元数据驱动的软件架构为外围。 一、多租户意味着什么多租户的含意用一句话来形容就是:一个云平台,有数多个客户。 一个云平台的含意是:一个代码库,一个数据库,一整套共享的可扩大服务,包含数据服务、应用服务以及 Web 服务。 ...

January 14, 2021 · 6 min · jiezi

关于angular:Angular-form控件原生HTML代码里ngreflectform属性和其值的生成时机

简略的Component代码: import { Component } from '@angular/core';import { FormControl } from '@angular/forms';@Component({ selector: 'app-reactive-favorite-color', template: ` Favorite Color: <input type="text" [formControl]="favoriteColorControl"> `})export class ReactFormComponent { favoriteColorControl = new FormControl('');}如下图所示:ng-reflect-form这个属性运行时是如何生成的? bootstrap里调用_loadComponent: changeDetectorRef的策略:RootViewRef: ComponentRef指向的AppComponent,能看到Component的property: loadComponent里显式调用tick: tick函数里进行change detect: Angular Component html里加了方括号的Directive,浏览器是无奈辨认的,在Angular core.js里,在执行Component template实现函数时,会调用Angular的property函数,将中括号包裹的Angular指令开展:Update a property on a selected element. element指向input控件: 须要增加到input标签页的属性名称为form: 通过normalizeDebugBindingValue外面的正则化解决完属性form之后,返回的值: ng-reflect-form 待写入input ng-reflect-form属性的值: 为了防止value的值过于简单时,序列化生成的json字符床过大,净化了最初的原生html,在normalizeDebugBindingValue里只是简略的调用toString函数:// Limit the size of the value as otherwise the DOM just gets polluted. ...

January 6, 2021 · 1 min · jiezi

关于angular:隔离期间的爱情angular下自定义组件适用form的方法

实现细节https://segmentfault.com/a/11... 写的很分明了,十分具体然而我不太能看得懂,轻易写写,说不定写着写着就懂了根本的原理就是 实现一个组件,这个组件承受angular的 ngmodel 的模版驱动表单语法或者reactive form 响应式表单的语法。承受angular form的语法的原理就是自定义的组件要实现 AbstractControl 接口。首先明确 ngmodel 到底是做了什么事,太具体的我讲不进去事太多了,我了解就是两个,ngmodel 是一个语法糖。 [(ngModel)]="value"的意思等于<component-name [value]="value" (ngModelChange)="value = $event"></component-name>而后在你的component 中监听 value ,和你扭转了数据 value 之后触发 ngModelChange.emit(this.value) 事件告诉给父组件之类的。然而他这里提供的 api 其实是 writeValue(value){}函数,承受的参数是里面传入的value,每次value批改时会触发writeValue函数。 而后`registerOnChange(fn: any) { this.propagateChange = fn; } 中的 fn 参数其实就是 ngModelChange.emit(this.value)。 写到这里我就更纳闷了,那为什么angular要设计这么简单的API呢,是为了解决什么场景吗?无奈了解呀,好难哦,又是一篇中文垃圾

January 1, 2021 · 1 min · jiezi

关于angular:React-入门写个-TodoList-实例

React 是一个用于构建用户界面的 JavaScript 库,次要特点有: 申明式渲染:设计好数据和视图的关系,数据变动 React 主动渲染,不用亲自操作DOM组件化:页面切分成多个小部件,通过组装拼成整体页面,利于代码复用本文通过写个简略的 TodoList 实例,不求甚解,相熟下 React 的开发过程。 装置 Node.jsNode.js 是一个运行环境,相似 jdk,用以反对在服务端运行 JavaScript。 您能够在这里下载安装包: http://nodejs.cn/download/ 以绿色版装置为例,将 node-v10.16.1-win-x64.zip 解压到 E:software 并命名为 node-v10.16.1 在 Path 环境变量中减少两项: E:softwarenode-v10.16.1E:softwarenode-v10.16.1node_global 在 cmd 中应用 node -v 显示版本号,示意装置胜利。 Node.js 中有个 npm 软件包管理器,能够很不便的治理下载和应用第三方开源包,相似 maven,应用 npm -v 显示版本号,示意 npm 也没有问题。 绿色版装置实现后一些必要的配置: npm config set prefix "E:softwarenode-v10.16.1node_global" 设置全局装置的模块存储门路 npm config set cache "E:softwarenode-v10.16.1node_cache" 设置下载缓存的存储门路 npm config set registry https://registry.npm.taobao.org` 设置 npm 下载源为淘宝镜像 简略应用: ...

December 31, 2020 · 2 min · jiezi

关于angular:Mark企业级Angular-Dashboard应用程序创建Part-2

点击获取工具>> 重要提醒:应用本教程须要相熟React的基本概念和模式,要查看这些概念,请拜访angular.io 。 Step 2. 创立服务器应用程序创立一个自定义服务器应用程序来显示您的数据,请按以下步骤操作: 在Visual Studio中,创立一个ASP.NET Core 3.1应用程序,抉择 Empty template。创立将存储仪表板的App_Data / Dashboards文件夹。用以下代码替换Startup.cs文件的内容:`using DevExpress.AspNetCore;using DevExpress.DashboardAspNetCore;using DevExpress.DashboardCommon;using DevExpress.DashboardWeb;using DevExpress.DataAccess.Json;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Hosting;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.FileProviders;using System; namespace AspNetCoreDashboardBackend {public class Startup {public Startup(IConfiguration configuration, IWebHostEnvironment hostingEnvironment) {Configuration = configuration;FileProvider = hostingEnvironment.ContentRootFileProvider;} public IConfiguration Configuration { get; }public IFileProvider FileProvider { get; } public void ConfigureServices(IServiceCollection services) {services// Configures CORS policies. .AddCors(options => {options.AddPolicy("CorsPolicy", builder => {builder.AllowAnyOrigin();builder.AllowAnyMethod();builder.WithHeaders("Content-Type");});})// Adds the DevExpress middleware..AddDevExpressControls()// Adds controllers..AddControllers()// Configures the dashboard backend..AddDefaultDashboardController(configurator => {configurator.SetDashboardStorage(new DashboardFileStorage(FileProvider.GetFileInfo("App_Data/Dashboards").PhysicalPath));configurator.SetDataSourceStorage(CreateDataSourceStorage());configurator.ConfigureDataConnection += Configurator_ConfigureDataConnection;});} ...

December 30, 2020 · 1 min · jiezi

关于angular:angular学习之通俗易懂篇新建组件并调用

1、新建angular我的项目: 2、进入angulardemo1目录,并启动我的项目: 3、在浏览器关上: 4、新建组件  这就是在app文件夹下新建了目录component并创立组件componentA 此刻目录如下:  app.module.ts中会主动引入咱们新建的组件,并申明,咱们就能在我的项目其余中央应用这些组件了 5、应用组件: tips:组件相当于模板,哪里须要就能拿到哪里去用!!! 找到组件ts文件中的标签名,之后就能用这个标签名应用组件:  删除app.component.html中的代码,也就是默认启动页面中的内容: 在app.component.html中应用组件A:  重新启动我的项目,浏览器显示为:    阐明组件应用胜利!!! 用同样的办法新建组件,并调用:  

December 29, 2020 · 1 min · jiezi

关于angular:实用企业级Angular-Dashboard应用程序创建Part-1

点击获取工具>>重要提醒:应用本教程须要相熟React的基本概念和模式,要查看这些概念,请拜访angular.io 。 Web Dashboard是一个客户端控件,它应用HTTP申请与服务器局部进行通信: 客户端局部是一个JavaScript应用程序,向最终用户提供UI来设计和与仪表板进行交互,DashboardControl是根底控件。服务器局部是ASP.NET Core或ASP.NET MVC应用程序,它解决客户端数据申请,并包含各种后端性能,例如数据拜访、仪表板存储等。本教程创立并配置一个客户端Angular应用程序,该应用程序蕴含Web Dashboard和一个基于ASP.NET Core应用程序的服务器。 先决条件Node.js 8+Angular CLI 6+要求客户端上的脚本版本应与服务器上的库版本匹配。DevExpress npm软件包的版本应该雷同。Step 1. 在Angular我的项目中配置Client Dashboard控件创立一个全新的angular利用。cmd ng new dashboard-app 创立我的项目后,导航到创立的文件夹: cmd cd dashboard-app 装置具备必须的peerDependencies的仪表板软件包。npm install devexpress-dashboard@20.2-next devexpress-dashboard-angular@20.2-next @devexpress/analytics-core@20.2-next devextreme@20.2-next devextreme-angular@20.2-next --save 装置实现后,您能够在node_modules文件夹中找到所有库。 在app.module.ts文件中,导入DxDashboardControlModule模块。typescript import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core'; import { AppComponent } from './app.component';import { DxDashboardControlModule } from 'devexpress-dashboard-angular'; @NgModule({declarations: [AppComponent,],imports: [BrowserModule,DxDashboardControlModule],providers: [],bootstrap: [AppComponent]})export class AppModule { } 关上app.component.html文件,并将其内容替换为以下元素以出现仪表板组件:html <dx-dashboard-control endpoint='https://demos.devexpress.com/...'></dx-dashboard-control> ...

December 24, 2020 · 1 min · jiezi

关于angular:ngselect2发生ExpressionChangedAfterItHasBeenCheckedError异常的一种解决方法

驰名的select2终于有热心的大牛构建了angular版本,并命名为ng-select2。但(猜测)因为其外围的代码依赖于jquery,所以在联合formControl应用时,会产生如下异样:Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'ng-pristine': 'true'. Current value: 'false'. 情景再现比方咱们有以下组件树: 一个一般的A组件,一个能够实现了ControlValueAccessor接口并申明为FormControl的B组件,一个援用的ng-select2组件。 其中A组件蕴含B组件、B组件又蕴含ng-select2组件。 ng-select2组件中的数据列表是通过资源申请失去的列表,所以是异步数据,B组件V层示例如下: <ng-select2 [value]="datum" [data]="data" (valueChanged)="onChanged($event)"</ng-select2>B获取select2应用的数据列表data示例代码如下: ngOnInit(): void { this.service.getAll() .subscribe(data => { // 在这设置ng-select2的数据列表 this.data = data; });}此时在A组件将会产生如下谬误:Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'ng-pristine': 'true'. Current value: 'false'. 起因猜测咱们晓得,因为在大牛们会具体的解释异样产生的起因,所以解决问题的第一步也是最重要的一步便是翻译:严重错误:表达式被检测结束当前却产生了变更谬误:当表达式被检测结束当前却又产生了变更。检测结束时,检测的'ng-pristine'的值为'true'. 以后值为:'false'。同时pristine可译为原始的。 所以我猜错主大略是如下产生的: 也就是说:将A组件在渲染结束的状况下,发现FormControl的值产生了变动,则会产生ExpressionChangedAfterItHasBeenCheckedError异样。 解决办法ng-select2的官网demo中给出了当列表值异步时的解决方案,但遗憾的是该办法同样会引发上述异样。 该异样产生的次要起因是因为A组件处于渲染结束,使得A中做为FormControl的组件B同样处于tHasBeenChecked状态,所以解决该问题也能够如下着手: 如上图所示,当组件B在接管到异步数据时,为了避免其子组件ng-select2进行数据弹射时A组件处于渲染结束状态,咱们在此手动的触发从新渲染所有组件的办法。此时将A组件接管到最新的值时,其状态处于渲染中,当然也就不会呈现HasBeenChecked异样了。 代码如下: constructor(private service: Service, private changeDetectorRef: ChangeDetectorRef) {}ngOnInit(): void { this.service.getAll() .subscribe(data => { // 在这设置ng-select2的数据列表 this.data = data; // 手动调用组件渲染办法,从新渲染各组件 this.changeDetectorRef.detectChanges(); });总结排错的路千万条,翻译、瞎猜第一条。 ...

December 17, 2020 · 1 min · jiezi

关于angular:Angular-组件-性能优化changeDetectionOnPush

Angular Component 性能优化changeDetection?:ChangeDetectionStrategy#OnPush

December 7, 2020 · 1 min · jiezi

关于angular:Angular-组件怎么检测Input为引用类型的变化

Angular 组件怎么检测Input为援用类型的变动

December 6, 2020 · 1 min · jiezi

关于angular:Angular如何对包含了HTTP请求的服务类进行单元测试

本文应用到的所有代码在Github这个文件夹上面:https://github.com/wangzixi-d... 服务类实现: import { Injectable } from '@angular/core';import { HttpClient, HttpRequest } from '@angular/common/http';@Injectable()export class DataService { url = 'https://jsonplaceholder.typicode.com/users'; constructor(private http: HttpClient) {} getData() { const req = new HttpRequest('GET', this.url, { reportProgress: true }); return this.http.request(req);}}首先,从@angular/common/http里倒入HttpClientTestingModule,注入到TestBed的TestingModule中去。 将HttpTestingController注入单元测试代码里,用变量httpMock示意: 粉红色小括号蕴含起的这段代码内,调用了dataService的getData办法。 HttpTestingController.expectOne: 冀望一个基于传入参数url的HTTP申请曾经被发动,并且返回其mock. 咱们能够基于mockReq进行各种断言解决。 expect(mockReq.cancelled).toBeFalsy();确认该申请没有被cancel expect(mockReq.request.responseType).toEqual('json');确保响应类型是JSON mockReq.flush(mockUsers)应用flush传入的参数作为HTTP申请的返回参数: flush执行完之后,才会触发getData返回的Observable的subscribe回调函数。 运行时时序: (1) 先执行service.getData 真的调用到service的getData代码里了: 此时event.type = 0: (2) 拿到HTTP申请的mock对象: 筹备flush: ...

December 5, 2020 · 1 min · jiezi

关于angular:Angular的constructor和ngOnInit里写代码有什么区别

参考这个StackOverflow探讨Difference between Constructor and ngOnInit 得赞超过1000的答案: The Constructor is a default method of the class that is executed when the class is instantiated and ensures proper initialisation of fields in the class and its subclasses. Angular, or better Dependency Injector (DI), analyses the constructor parameters and when it creates a new instance by calling new MyClass() it tries to find providers that match the types of the constructor parameters, resolves them and passes them to the constructor like当class被实例化时,constructor是默认被执行的办法,确保类和其子类都被正确地初始化。Angular依赖注入机制,会剖析constructor的输出参数,当应用new MyClass创立class实例时,会试着去查找能匹配构造函数类型的providers,解析providers并将后果传递到类的构造函数里。 ...

December 5, 2020 · 2 min · jiezi

关于angular:一个好用的查看Angular应用ngrx状态的Chrome扩展Redux-devTools

Redux DevTools: https://chrome.google.com/web... 装置结束后,在Chrome开发者工具里会多出一个Redux面板: 以及在Chrome右上角的扩大工具栏里,会点亮Redux DevTools对应的图标。 此时在redux面板里即可不便的查看ngrx相干的state和action: 能够输出关键字进行过滤,比方查看和Currency加载相干的action: action蕴含type和payload: 把这个type复制下来,即可到对应源代码里依据关键字进行搜寻:[Site-context] Load Currencies Success Load Product Data时,state里的loading标记位是true: 加载胜利后,loading从true变为false,success从false变为true: state栏能看到以后action触发时,利用的state状态,很不便: 更多Jerry的原创文章,尽在:"汪子熙":

December 5, 2020 · 1 min · jiezi

关于angular:Angular-Material-Datepicker-组件自定义日期格式

在Angular Material 组件文档中datepicker组件可反对应用Moment自定义格局;官网文档和链接如下 mat-datepicker:咱们依照官网文档开发是有可能遇到相似这样的谬误: × Compiling TypeScript sources through NGCERROR: xxx/datepicker.ts:15:10 - error TS2305: Module '"xxx/moment"' has no exported member 'default'.解决办法是: 在tsconfig.json中compilerOptions退出"allowSyntheticDefaultImports": true,即可

November 26, 2020 · 1 min · jiezi

关于angular:Angular单元测试如何只执行指定的测试用例提高测试速度

Angular我的项目的规模一旦变大,待执行的单元测试的数目可能是海量的。此时在开发新的单元测试时,会遇到须要屏蔽到零碎里曾经十分稳固的测试,而只执行正在开发的新单元测试。这个需要如何实现呢? 每个Angular我的项目文件夹下都有test.ts, 外面有一行语句,指定了该我的项目下哪些ts文件里的单元测试会执行: const context = require.context('./', true, /\.spec\.ts$/); 默认状况下,src目录下所有以.spec.ts结尾的文件里,蕴含的单元测试都会被执行。 如果我想只执行正在开发的新单元测试,而屏蔽到以前开发好的所有单元测试,能够在require.context返回的构造上做文章。 只须要增加如下两行语句: const FILE = ['./app/ngrxdemo/service/unittest-study/demo.spec.ts'];context.keys().filter( name => !!FILE.includes(name)).map(context);将须要执行的单元测试文件门路放到FILE数组里: 命令行运行ng test, 即可察看到当初只有FILE数组里指定的一个单元测试文件demo.spec.ts里的测试用例被执行了: 要获取更多Jerry的原创文章,请关注公众号"汪子熙":

November 23, 2020 · 1 min · jiezi

关于angular:JNPF云平台之多租户的探索

在云畛域咱们经常会听到一个词:多租户。这个词在不同的语境中有着不同的含意。本文将介绍云平台中的多租户的概念以及实现多租户反对的思路。 什么是租户刚开始接触这个概念时,你必定感觉“租户”这个词怪怪的。但假如咱们换个词,我置信你立刻就有感觉了。这个词就是“客户”(这里的客户指的就是商业下面的客户)。 一个租户就是一个客户,比如咱们开发的服务是给 XXX 企业应用的,那该企业就是咱们的一个客户/租户;假如这个服务是面向互联网的,那么应用该服务的每一个互联网用户都是一个客户/租户。 为什么须要多租户反对开发人员辛辛苦苦开发出一个服务。提供给了集体/企业应用,这样就完事了么?当然不应该仅仅是这样。咱们开发出一个服务。最好是能够同一时候提供给多个集体/企业应用。并且这些客户最好是共享同一套服务执行时(Runtime),这样能够大大减少服务的运维老本: 服务执行时假如离开,则运维的老本与客户数成正比(比如更新部署大量客户的场景)节俭资源(将服务所需资源利用最大化:运维团队对立、硬件应用)另外,这样也可能缩小服务的开发成本: 咱们仅仅须要思考怎么实现单用户的服务逻辑:业务逻辑相应其全副客户都是同样的,不论什么客户来应用,程序提供的服务都是一样的。进一步说,在业务层面咱们开发这个服务时实践上不须要思考多客户反对,咱们仅仅用关注该服务的业务逻辑怎么实现多客户的治理性能可能进行对立:开发人员应该不必思考客户治理性能,这部分应该是由云平台对立提供的多租户场景举例 如果咱们要开发的服务是一个博客平台,这个服务是面向互联网用户的,每一个互联网用户都是咱们的客户(一个用户就是一个租户)。 在不反对多租户的环境中,为了隔离每一个用户的数据,至多咱们在设计数据库表时会思考大多数表都存在一个 user_id 字段。用于 CRUD 数据时应用该字段进行用户隔离。 比如现在的业务是“颁布文章”。须要将文章数据保留在 article 表中,在实现时实际上咱们关注了两件事件: CRUD:这是业务逻辑实现的一部分用户隔离:须要减少 user_id。做业务关联1 是“纯”业务逻辑局部的实现。这是必须实现的; 2 则是为了多用户博客平台而须要思考的,这并非博客平台自身的业务逻辑。 这里假设能失去平台的多租户反对,就不必思考第 2 点了。这样可能将注意力集中于第 1 点业务逻辑实现上,这是很典型的一个多租户场景。 多租户反对咱们可能这样了解多租户反对: 从服务提供的角度看。咱们开发的一个服务执行时可能同一时候提供给多个客户应用。而且客户之间的数据/状态是放弃隔离的从服务应用的角度看,我和你可能作为不同的客户同一时候应用同一个执行的服务,此时咱们应用该服务结束的业务是互相不影响的,就如同咱们在应用本人独享的服务一样那么这个服务就是反对多“客户”的,即该服务反对多租户。这里的“服务”可能是利用,可能是 SaaS 平台,也可能是 PaaS 平台。只是按眼下咱们相熟的云平台看,利用的多租户反对应该是最惯例的。这是因为利用面向的是用户,这个群体是十分宏大的。 多租户反对从实现的角度看。“是一种软件架构技术”,之所以强调它是属于架构层面是因为要实现它必须在做技术架构时就要将其思考在内。 一种租户模型 本文一开始咱们提到应用“客户”来置换“租户”来了解租户的含意。再从“商业”这个方面来看的话,咱们不难发现租户事实上就是其云环境中的商业模式实现的一部分。商业模式是多样的。这意味着租户的划分也是多样的。这里咱们刻画叙述当中一种可能的租户栈: 应用程序是提供给用户应用的,对于利用来说,用户就是它的租户(这一点业界比較对立)SaaS 提供的服务是给利用开发商应用的,对于 SaaS 来说,利用开发商就是它的租户PaaS 提供的服务是给利用零碎应用的,对于 PaaS 来说。相干利用的组合就是它的租户SaaS 和 PaaS 面向的是开发商、零碎等非端用户角色。这一部分通常是由云平台开发人员决定的(捆绑商业模式)。特地是公有/企业云平台个别不会思考形如“在 PaaS 平台上反对执行多个 SaaS 平台”这种场景。所以以下咱们很多其它的是盘绕“利用对多租户反对”进行探讨。 利用多租户利用多租户的应用场景后面曾经介绍过了。现在如果咱们是一个云平台开发人员,为了满足反对利用反对多租户的需要,在云平台中咱们须要提供以下几个反对: 租户治理:CRUD,统计租户隔离/共享的服务:队列、缓存、数据库等租户隔离的统计:日志、配额这些反对可能分为两类: 租户的治理:不会间接面向利用的端用户。面向的是利用的运维。平台应该提供具体实现租户数据/状态的隔离:从申请開始就应该可能辨别这个申请是来自于哪个租户,申请解决时在调用链路上也须要带上租户上下文。数据的存取是按照租户隔离的。调用平台提供的服务时也是租户隔离的第 1 点比拟easy实现。这是一个业务模型方面的问题,可能根据业务域来形象租户模型,比如企业应用通常是按照“组织机构”来辨别租户的; 第 2 点是一个纯技术的需要。须要在平台技术实现上反对按“租户”的执行时隔离,咱们强调的是隔离,因为在实现时咱们要达到的指标就是隔离,仅仅只是这里是按租户(租户仅仅是一个商业概念,技术层面咱们最好可能将其进行形象。尽量减小商业模式多样化对技术架构的冲击)。咱们可能将租户映射到一个抽象概念上,这个抽象概念可能实现咱们的隔离需要。 命名空间后面咱们探讨多租户反对都是自上而下的:从利用多租户需要到数据隔离实现;现在咱们再换种视角,自下而上:先通过命名空间隔离数据,再将命名空间提供给利用多租户的实现应用。自下而上的目标次要是在平台外部,咱们能够通过“命名空间”来进行数据/状态隔离的形象。终于的现实状况是命名空间不仅能够反对利用多租户实现,还能够可选择性地裸露命名空间 APIs。让利用能够进行某些数据的隔离(比如缓存)。不便业务实现。 隔离的实现 租户申请从开始到完结平台都须要通晓这个申请映射的命名空间。从申请解决栈咱们可能这样大抵划分一下: 负载均衡器(LB)利用容器(APP)平台服务接口(RPC)平台服务实现(DB/Cache/MQ....)在这个栈中每一层平台都是须要晓得这个申请相应的命名空间的。平台可能提供一个对立登录的服务,将租户信息映射为命名空间并保留到用户会话中,这样每次该用户的申请: 过 LB 时就可能辨别出命名空间来在 APP 容器中可能通过会话RPC 时传递命名空间根据服务的不同进行命名空间实现(比方 DB 根据命名空间应用不同的 Schema,MQ 根据命名空间应用不同的队列)这里咱们应用的隔离实现基本思路是“Shared application”,即多租户共享一个利用,相应一套基础设施。 ...

November 19, 2020 · 1 min · jiezi

关于angular:过时的技术ng-library静态打包实现

钻研起因ng library生成的模块,尽管有构建过程,实际上仅仅进行了一次繁难的包装,在我的项目中还要走一遍构建流程(尽管有metadata,然而还要剖析一遍...)冀望相似jquery那种,引入一个链接就能够应用,缩小编译时的工夫改版阐明仅仅是为了反对aot模式的library打包,启动ivy会间接构建能够用的模块,所以此我的项目的钻研,应该有点过期了原意是将library打包输入为构建好的ngfactory模块目前绝大部分曾经胜利,惟一bug(已知)应该是ngstyle也就是style不能应用,无奈输入ngstylejs间接引入 能够实现的就是近程路由技术,近程模块技术传统引入办法,被引入构建时,依然会从新构建一遍ngfactory,如果要批改,预计要间接批改angular局部包进行反对应用阐明tsconfig.json{ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/lib", "target": "es2015", "declaration": true, "inlineSources": true, "types": [], "lib": [ "dom", "es2018" ] }, // 这里参考设置 "angularCompilerOptions": { // 必须 "annotateForClosureCompiler": false, // 必须 "skipTemplateCodegen": false, "strictMetadataEmit": true, "fullTemplateTypeCheck": true, "strictInjectionParameters": true, "enableResourceInlining": true, // 必须 "enableIvy":false }, "exclude": [ "src/test.ts", "**/*.spec.ts" ]}将此分支构建当前npm link替换掉原来的ng-packagr后,就能够应用了(失常构建流程)实现原理首先下面的tsconfig设置是要保障代码应用默认的emit形式,既默认输入形式而后在代码中(本我的项目中)将es5的默认配置正文掉,使得和es2015输入统一(umd包是会依据es5打包的)最初通过逻辑,将输入的ngfactory文件退出到导出中(如果不退出,那么umd构建依然不蕴含)调用构建包间接通过js引入,而后相似动静生成模块那样就Ok了/**LibAotModuleNgFactory 这个就是通过引入的umd包中的导出*/ const ref = LibAotModuleNgFactory.create(this.inject); console.log(ref); const fac = ref.componentFactoryResolver.resolveComponentFactory( ref.instance.entry ); console.log(fac); this.viewContainerRef.createComponent(fac);通过路由援用loadChildren形式,间接援用ngfactory未测试,然而ng源码的测试用例中能够应用已知问题(因为占用工夫过多,曾经没精力解决了,违心搞的大牛能够试试)不能应用style,因为没有导出ngstyle文件援用构建好的library后,依然会在构建时生成ngfactory,不晓得是ngfactory有非凡的援用办法,还是须要改ng源码,进行一些重定向或者移除替换操作(因为externals只会移除局部,html模板依然会打进去)代码地址地址

November 15, 2020 · 1 min · jiezi

关于angular:使用MockHttpClientModule替换HttpClientModule学习心得

前言之前的我的项目测试采纳的是应用Stub替换原有的组件进行测试,现在的问卷零碎采纳了新的思维,就是应用应用MockHttpClientModule替换HttpClientModule,前后台接口齐全对立,更靠近于实在申请,本文以总结学习心得为主,总结一下该办法的思路。 办法首先看一下要测试的办法: /** * 通过试卷ID获取答卷 * 1. 如果存在尚未实现的答卷,则返回尚未实现的答卷 * 2. 如果不存在尚未实现的答卷,则新建一个答卷返回 * @param id 试卷ID */getByPaperId(id: number): Observable<AnswerSheet> { return this.httpClient.get<AnswerSheet>(`${this.baseUrl}/${id}`);}测试方法: beforeEach(() => { TestBed.configureTestingModule({ imports: [ MockApiModule ], providers: [ MockHttpClient ] }); service = TestBed.inject(AnswerSheetService);});it('测试模仿接口服务是否失效', () => { expect(service).toBeTruthy(); let called = false; service.getByPaperId(123).subscribe(data => { expect(data.id).toEqual(123); called = true; }); getTestScheduler().flush(); expect(called).toBeTrue();});MockHttpClientexport class MockHttpClient { constructor(private mockApiService: MockApiService) { } get<T>(url: string, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; }; params?: HttpParams | { [param: string]: string | string[]; }; }): Observable<T> { return this.mockApiService.get<T>(url, options); }MockApiServiceget办法/** * get办法 * @param url 申请地址 * @param options 选项 */ get<T>(url: string, options = {} as { headers?: HttpHeaders | { [header: string]: string | string[]; }; params?: HttpParams | { [param: string]: string | string[]; }; }): Observable<T> { return this.request<T>('get', url, { observe: 'response', responseType: 'json', headers: options.headers, params: options.params }); }}request/** * 所有的GETPOSTDELETEPUTPATCH办法最终均调用request办法。 * 如果以后request不可能满足需要,则请移步angular官网提供的HttpClient * * 该办法先依据method进行匹配,接着依据URL进行正则表达式的匹配。 * 匹配胜利后将参数传入接口并获取模仿接口的返回值 * * @param method 申请办法 * @param url 申请地址 * @param options 选项 */ request<R>(method: string, url: string, options: { body?: any; headers?: HttpHeaders | { [header: string]: string | string[]; }; reportProgress?: boolean; observe: 'response'; params?: HttpParams | { [param: string]: string | string[]; }; responseType?: 'json'; withCredentials?: boolean;}): Observable<R> { let result = null as R; let foundCount = 0; const urlRecord = this.routers[method] as Record<string, RequestCallback<any>>; for (const key in urlRecord) { if (urlRecord.hasOwnProperty(key)) { const reg = new RegExp(key); if (reg.test(url)) { const callback = urlRecord[key] as RequestCallback<R>; callback(url.match(reg), options.params, options.headers, (body) => { result = body; foundCount++; if (foundCount > 1) { throw Error('匹配到了多个URL信息,请检定注入服务的URL信息,URL信息中存在匹配抵触'); } }); } } } if (null === result) { throw Error('未找到对应的模仿返回数据,请查看url、method是否正确,模仿注入服务是否失效'); } return testingObservable(result);}registerMockApi/** * 注册模仿接口 * @param url 申请地址 * @param method 申请办法 * @param callback 回调 */registerMockApi<T>(method: RequestMethodType, url: string, callback: RequestCallback<T>): void { if (undefined === this.routers[method] || null === this.routers[method]) { this.routers[method] = {} as Record<string, RequestCallback<T>>; } if (isNotNullOrUndefined(this.routers[method][url])) { throw Error(`在地址${url}已存在${method}的路由记录`); } this.routers[method][url] = callback;}AnswerSheetApiregisterGetByPaperId()private baseUrl = '/answerSheet';/** * 注册GetByPaperId接口 * 注册实现后,当其它的服务尝试httpClient时 * 则会按此时注册的办法、URL地址进行匹配 * 匹配胜利后则会调用在此申明的回调函数,同时将申请地址、申请参数、申请header信息传过来 * 咱们最初依据接管的参数返回特定的模仿数据,该数据与后盾的实在接口放弃严格对立 */ registerGetByPaperId(): void { this.mockHttpService.registerMockApi<AnswerSheet>( `get`, `^${this.baseUrl}/(d+)$`, (urlMatches, httpParams, httpHeaders, callback) => { const id = urlMatches[1]; callback({ id: +id }); } );}injectMockHttpService/** * MOCK服务。 */mockHttpService: MockApiService; /** * 注入MOCK服务 ** @param mockHttpService 模仿HTTP服务 */injectMockHttpService(mockHttpService: MockApiService): void { this.mockHttpService = mockHttpService; this.registerGetByPaperId();}MockApiServiceconstructor()/** * 注册模仿接口 * @param clazz 接口类型 */ static registerMockApi(clazz: Type<Api>): void { this.mockApiRegisters.push(clazz);}/** * 循环调用从而实现所有的接口注册 */ constructor() { MockApiService.mockApiRegisters.forEach(api => { const instance = new api(); instance.injectMockHttpService(this); });}// AnswerSheetApiMockApiService.registerMockApi(AnswerSheetApi); ...

November 7, 2020 · 3 min · jiezi

关于angular:阅读记录

1. Angular ElementRef 简介(完)ElementRef 咱们就能够封装不同平台下视图层中的 native 元素 (在浏览器环境中,native 元素通常是指 DOM 元素)console.dir()能够显示一个对象的所有属性和办法操作dom第一种办法constructor(private elementRef: ElementRef) {//先获取 my-app元素,而后利用 querySelector API 就能获取页面中 div 元素 let divEle = this.elementRef.nativeElement.querySelector('div'); console.dir(divEle); }操作dom第二种办法 @ViewChild('greet') greetDiv: ElementRef; ngAfterViewInit() { this.greetDiv.nativeElement.style.backgroundColor = 'red'; }操作dom第三种办法:跨平台constructor(private elementRef: ElementRef, private renderer: Renderer2) { } ngAfterViewInit() { // this.greetDiv.nativeElement.style.backgroundColor = 'red'; this.renderer.setStyle(this.greetDiv.nativeElement, 'backgroundColor', 'red'); }2. Angular 6 HttpClient 疾速入门(未完)设置查问参数办法https://jsonplaceholder.typicode.com/todos?_page=1&_limit=10//HttpParams 对象是不可变的,想要操作的话要保留set的返回值。也能够应用链式语法const params = new HttpParams().set("_page", "1").set("_limit", "10");const params = new HttpParams({fromString: "_page=1&_limit=10"});const params = new HttpParams({ fromObject: { _page: "1", _limit: "10" } });this.http.get("https://jsonplaceholder.typicode.com/todos",{params})options的参数options: { headers?: HttpHeaders | {[header: string]: string | string[]}, observe?: 'body' | 'events' | 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'arraybuffer'|'blob'|'json'|'text', withCredentials?: boolean, }// options 对象的 observe 属性值为 response 来获取残缺的响应对象

November 2, 2020 · 1 min · jiezi

关于angular:阅读记录

1. Angular ElementRef 简介ElementRef 咱们就能够封装不同平台下视图层中的 native 元素 (在浏览器环境中,native 元素通常是指 DOM 元素)console.dir()能够显示一个对象的所有属性和办法操作dom第一种办法constructor(private elementRef: ElementRef) {//先获取 my-app元素,而后利用 querySelector API 就能获取页面中 div 元素 let divEle = this.elementRef.nativeElement.querySelector('div'); console.dir(divEle); }操作dom第二种办法 @ViewChild('greet') greetDiv: ElementRef; ngAfterViewInit() { this.greetDiv.nativeElement.style.backgroundColor = 'red'; }操作dom第三种办法:跨平台constructor(private elementRef: ElementRef, private renderer: Renderer2) { } ngAfterViewInit() { // this.greetDiv.nativeElement.style.backgroundColor = 'red'; this.renderer.setStyle(this.greetDiv.nativeElement, 'backgroundColor', 'red'); }

November 2, 2020 · 1 min · jiezi

关于angular:自定义管道

创立管道ng g p play-count实现管道import { Pipe, PipeTransform } from '@angular/core';//@Pipe将类标记为一个管道,name为调用该管道时应用的符号@Pipe({ name: 'playCount'})export class PlayCountPipe implements PipeTransform { /* 1. transfrom中传入要转换的值 2. 返回值为number或者string */ transform(value: number): number | string { if (value > 10000) { return Math.floor(value / 10000) + '万'; } else { return value; } }}应用管道{{sheet.playCount | playCount}}管道定义管道是一些简略的函数,能够在模板表达式中(双大括号)用来承受输出值并返回一个转换后的值。管道类首字母全大写。name名首字母小写,其余首字母大写。 创立管道用@Pipe将类标记,并给定一个含有name字段的对象实现PipeTransform接口

November 1, 2020 · 1 min · jiezi

关于angular:angular指令中带有ViewContainerRef以及其它服务时该如何进行单元测试

angular提供十分敌对的单元测试,特地是对于组件。应用ng g命令即可生成一个高度能够测试的组件。而指令的单元测试样板代码便显得有些简陋了。 面临问题angular对指令测试的样板代码更靠近于service的样板测试代码: describe('TestDirective', () => { it('should create an instance', () => { const directive = new TestDirective(); expect(directive).toBeTruthy(); });});这如同是在说:你应该像测试service一样来测试指令。而指令的作用更多的是对宿主进行一些变更,所以咱们在单元测试时须要一个获取到这么一个宿主。 当查阅angular在官网文档预在指令测试上获取更多信息时却提到以下提示信息: 那么问题来了,在进行指令测试时,是应该听从ng g生成的样本代码进行指令实例的测试呢?还是应该听从官网文档构建人造测试组件,由对组件的测试间接实现对指令的测试呢。 剖析问题官网文档只所以提出创立人造测试组件,其起因是:只有构建一个实在的组件,才可能获取到指令要操作的DOM。 比方有如下指令: @Directive({ selector: '[appQuestion]'})export class QuestionDirective { @Input() set appQuestion(question: any) { this.setQuestion(question); } constructor(private elementRef: ElementRef) { }}构造函数中须要的elementRef是个DOM的援用,尽管咱们能够手动创立一个ElementRef对象进去,但却无奈间接的感触指令对其产生的影响。 解决方案咱们以后两个根本的诉求: 获取一个可用可察看的ElementRef。实例化被测指令指令依赖于ElementRef,ElementRef的获取形式有多种: 间接创立能够应用document对象间接创立一个dom对象进去,而后再实例化出一个ElementRef供指令实例化: fit('手动创立', () => { expect(component).toBeTruthy(); const nativeElement = document.createElement('div'); nativeElement.innerHTML = '<h1>Hello World</h1>'; const elementRef = new ElementRef(nativeElement); const directive = new QuestionDirective(elementRef); expect(directive).toBeTruthy(); }); ...

October 30, 2020 · 2 min · jiezi

关于angular:angular共享依赖解决方案

webpack-ng-dll-pluginng版本可用的dll插件,路子比拟野用处进步打包速度代码复用(微前端依赖共享)应用首先依据集体相熟水平抉择@angular-devkit/build-webpack,@angular-builders/custom-webpack,ngx-build-plus第一个是官网的,后两个是第三方的,然而确认你有练过之前,请不要抉择官网的...作者在测试的时候抉择的是@angular-builders/custom-webpack先构建dll,倡议应用空我的项目来创立dll,因为目前开发中并没思考到一些简单逻辑的实现及相干第三方包的依赖关系保留(full模式应该能够实现,实践)而后在构建时援用援用就是webpack的失常援用插件就ok了尝鲜上面的函数过滤了index.html,styles,polyfills,License的输入,并且禁用了runtimeChunk setNgDllPlugin( config, { //webpack 的out相干配置 output: { filename: 'dll.js', }, ngDllPluginOptions: { // dll的资源清单导出配置 path: path.join(__dirname, 'dist', 'manifest.json'), name: 'TLIB', format: true, filter: { // 过滤模式,full全量,auto绝对于我的项目,manual 手动指定过滤项(须要设置map) mode: 'auto', }, }, }, options );自定义相干配置须要参考(临时没写文档,须要查看源码) config.plugins.push(new NgDllPlugin(option.ngDllPluginOptions));援用// 这里的context能够了解为代码(利用代码)绝对于哪个文件夹解析(不是打包进去的dll.js,如果正确援用,你会发现把dll.js删掉,也不会影响打包),如果发现打包进去的货色没有应用这个,应该就是这个配置错了 config.plugins.push( new webpack.DllReferencePlugin({ context: path.resolve(__dirname), manifest: require('./dist/manifest.json'), }) );演示地址https://github.com/wszgrcy/ng-cli-plugin-demo可能解锁的技术分体式路由加载失常状况下,哪怕是动静加载的路由,也是与我的项目一起打包,只不过是打包为两个文件主体我的项目先打包,而后再独自开发懒加载路由模块web-component的使用率回升尽管ng曾经实现了这个,然而因为每次一大包,就相当于打了一个独自我的项目,十分宏大,应用dll后则会放大到一个可怕的水平,副作用靠近0目前(可能)存在的问题资源清单输入的是全量的援用,然而实际上,只有mode:'full'时,才等价没批改之一次要是影响不大,加上调试须要如果生成dll的我的项目中有动静加载模块,可能有未知影响dll在设计的时候基本没思考过动静模块之类的货色,齐全就是只打一个大包尽量应用空我的项目生成dllauto只代表以后生成我的项目能够达到齐全援用,如果你批改了我的项目,那么必须从新构建我的项目(额.看起来比拟废物的一个模式)其实如果我的项目代码足够多(各种品种),批改代码是不影响的,然而比方有些引入第一次应用,或者html模板中应用了一些新的货色,都须要从新构建待改良被动排除一部分永远无奈应用的导出为什么dll比间接打包大即便dll打包当初应用到了ng的aot,摇树等相干优化技术,然而依然有个致命问题,就是导出名,默认打包时,所有名字都会被优化(混同),而dll打包就必须裸露这个名字,当齐全裸露时,就会呈现体积增长目前用空我的项目生成出的dll(包含rxjs,router,common,core),全量暴力是440k(也就是说当其余包应用时这些文件都会在dll中查找),选择性导出最小化启动在216k作用,最终预计应该均匀在300k左右目前应用的技术,只能1.全量导出,2.抉择可用导出,这其实就有一个副作用存在,全量导出时.不仅一些不应用的依赖被导出了,还有些外部援用的(比方angular_packages_core_core_h)也被强制导出了,从而减少了包大小前期,其实能够整顿一个永不导出的列表,进行排除,从而减小体积传统打包是多个模块打包一个模块,两头很多依赖都是属于外部依赖,所以精简了很多代码,dll的这种打包属于多模块,因而每个模块都有进口,之间的援用也是用的模块之间的援用,所以即便最小化dll也会比打包的多40k左右

October 9, 2020 · 1 min · jiezi

关于angular:Cannot-instantiate-cyclic-dependency

angualr:8.0.6产生的起因是,旧的版本会呈现循环援用依赖谬误;呈现场景:user.service.ts import {Injectable} from '@angular/core'; import {of} from 'rxjs'; import {ActivatedRoute, Router} from '@angular/router'; import {tap} from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class UserService { constructor( private router: Router, private route: ActivatedRoute ) { } loginByToken() { console.log('init start'); return of('111').pipe(tap(() => { setTimeout(() => { this.router.navigateByUrl('/login'); }, 2000); })); } }解决方案是,去掉上面的依赖项 private router: Router, private route: ActivatedRouteangular9 和 angular10 曾经解决了这个问题。不必去掉路由的局部;

September 10, 2020 · 1 min · jiezi

关于angular:复宏汉霖Angular-Ionic-TS

背景: 新接手复宏汉霖我的项目,记一下须要后期相熟的货色,不便前期保护.首次开始Angular+ionic我的项目.给本人打气!加油!文章有点长,须要急躁看~~ 先放张图片,安抚一下眼睛. 打包地址的地位:两个都要替换对应的地址再进行打包.ios打包须要苹果电脑. 先相熟一个简略的集体设置页面:页面理论图如下: 看一下页面文件夹的目录构造: setup.html : 页面setup.scss : css款式setup.ts : 解决逻辑setup.module.ts : model层staff.service.ts : services层 我发现这个我的项目它们是把service都放在一起的.我之前写的其余我的项目是每个文件夹下有本人的service.... 来钻研一下集体设置这个页面是怎么画进去的:先钻研下页面实现HTML:来看下人家的代码是怎么写的: 第一局部发现了<ion-header>`<ion-title>`的标签.从名字看了解就是写title的标签.果然找到了零碎设置四个字.就是页面的头部地位.第二局部,整体用<ion-content>标签包起来,就是页面的内容持续往下看,发现了<ion-icon>`<h2>标签用来展现头像和姓名.用<div>`略微调整了下布局.持续往下看,发现了<ion-list>标签包裹的内容.对照页面看.果然有批改手势明码,对于,客服热线等一个个item.这样的item用list标签是最合适的.没故障.外面就是用一个个div把头像和文字写到一排.而后设置了一个点击办法.持续往下看,在<ion-list>完结标签前面.写了一个div标签.用来绘制页面底部的登记账号的地位.div里面包个button,加个点击事件就好了.这样一条条理进去整个页面的布局就清晰可见了.setup.html内容:<ion-header> <ion-navbar color="sky"> <ion-title>零碎设置</ion-title> </ion-navbar></ion-header><ion-content class="gray-bg"> <div class="setting-top" padding-top> <ion-item tappable (tap)="toProfile()"> <ion-icon item-start> <img src="assets/icon/avatar_duel_126.png" width="50"> </ion-icon> <h2>{{currentStaff?.UserName}}</h2> <p></p> </ion-item> </div> <ion-list> <button ion-item (click)="changeGestureCode()"> <ion-icon item-start> <img src="assets/icon/pattern_yellow_58.png" width="30"> </ion-icon> <h3>批改手势明码</h3> </button> <button ion-item (click)="aboutPage()"> <ion-icon item-start> <img src="assets/icon/info_blue_58.png" width="30"> </ion-icon> <h3>对于</h3> </button> <button ion-item (click)="ToCallNumber()"> <ion-icon item-start> <img src="assets/icon/phone_green_58.png" width="30"> </ion-icon> <h3>客服热线 <span class="color-blue">400-XXX-0800</span></h3> </button> </ion-list> <div padding> <button ion-button block color="danger" (click)="logout()">登记账号</button> </div></ion-content>钻研完HTML页面后,下一步就要看,点击事件的背地做了什么事件.先来看下逻辑页面的解决: ...

September 4, 2020 · 2 min · jiezi

关于angular:Angular前后端分离项目如何企业微信网页认证

1、想要干什么在最近的Angular+Sping boot的学习利用中,想要在企业微信获取企业微信用户的userid,实现网页认证。具体可参考企业微信网页认证api。2、企业微信网页认证原理本人的了解留神:这里的生产code的过程,必须由服务后盾实现申请。3、遇到的坑我在应用的过程中,试图应用Angular在前端实现身份认证的过程,过后的流程图:因为在微信开发中,微信内嵌的浏览器并没有控制台让咱们打印日志,只晓得产生了谬误,但具体谬误无所不知。试图通过alert办法,将谬误的对象打印进去,但看不到谬误对象的详细信息。4、vConsole可能腾讯早就收到微信开发者的投诉,没有控制台,微信开发出先谬误,齐全靠猜测本人哪里除了问题,效率太低,于是悄悄的提供了vConsole给开发者调试代码。vConsole是一个虚构的控制台。应用办法:在页面的head中退出如下代码 <script src="http://wechatfe.github.io/vconsole/lib/vconsole.min.js"></script><script>// 初始化 vConsolevar vConsole = new VConsole();console.log('Hello world');</script>这样咱们的页面就会减少一个虚构的控制台,console.log或其余调试办法均能够在虚构控制台中展示。5、论断通过vConsole调试,失去了问题的要害:呈现跨域谬误,企业微信的API不容许跨域申请。也就是生产code的过程中,我应用angular发动get申请是不被容许的,反思之后得出正确的流程图。

August 29, 2020 · 1 min · jiezi

关于angular:Angular如何自定义attribute指令

需要:实现一个自定义的attribute directive,当施加到某个html element时,鼠标hover下来,会批改其背景色彩。 <p appHighlight>Highlight me!</p>上面是具体做法。 (1) 应用命令行创立directive: ng generate directive highlight主动生成的文件: import { Directive } from '@angular/core';@Directive({ selector: '[appHighlight]'})export class HighlightDirective { constructor() { }}中括号语法标注了这是一个attribute指令。Angular在解决模板里的html元素时,如果发现某个元素具备appHighlight属性,就会将该指令的行为施加给该元素。 这里的selector之所以不取名为highlight,是为了防止和html规范的属性抵触。同样,不应用ng作为前缀,为了防止和Angular预置的attribute指令抵触。应用app代表这是利用开发人员自定义的attribute指令。 指令的具体实现放在highlight.directive.ts里: 通过结构函数参数注入形式,将被施加attribute指令的DOM元素注入,这样指令能够通过nativeElement操作该DOM元素。 (2) 在html里生产该指令: 最初的成果: It created an instance of the HighlightDirective class and injected a reference to the <p> element into the directive's constructor which sets the <p> element's background style to yellow.在运行时,Angular找到模板里标注了appHighlight指令的element后,创立一个HighlightDirective class的实例,将这个element注入到directive实例的构造函数里。 ...

August 29, 2020 · 1 min · jiezi

关于angular:angular集成bootstrap4

1、关上终端,输出命令新建一个angular app ng new app2、集成bootstrap装置ngx-bootstrap 和 Bootstrap在新建的我的项目中关上终端,运行如下命令 npm install ngx-bootstrap bootstrap --save3、应用bootstrap款式配置我的项目:必须将我的项目其配置为包含Bootstrap CSS,能力应用bootstrap的款式。 在angular.json中减少bootstrap的款式:从我的项目的根目录关上文件angular.json,找到Style配置项,指定bootstrap.min.css的门路。实现后,它应如下所示: "styles": [ "src/styles.sass", "./node_modules/bootstrap/dist/css/bootstrap.min.css" ],留神:对angular.json进行更改时,您将须要重新启动ng服务以获取配置更改。4、在app.module.ts中引入要应用的ngx-bootstrap module关上src/app/app.module.ts 并增加想要应用的组件module,例如BsDropdownModule.forRoot()。 import { BsDropdownModule } from 'ngx-bootstrap/dropdown';...@NgModule({ ... imports: [BsDropdownModule.forRoot(), ... ], ...})具体应用哪个bootstrap组件,点击https://valor-software.com/ngx-bootstrap/#/documentation查看

August 15, 2020 · 1 min · jiezi

关于angular:angular集成bootstrap4

1、关上终端,输出命令新建一个angular app ng new app2、集成bootstrap装置ngx-bootstrap 和 Bootstrap在新建的我的项目中关上终端,运行如下命令 npm install ngx-bootstrap bootstrap --save3、应用bootstrap款式配置我的项目:必须将我的项目其配置为包含Bootstrap CSS,能力应用bootstrap的款式。 在angular.json中减少bootstrap的款式:从我的项目的根目录关上文件angular.json,找到Style配置项,指定bootstrap.min.css的门路。实现后,它应如下所示: "styles": [ "src/styles.sass", "./node_modules/bootstrap/dist/css/bootstrap.min.css" ],留神:对angular.json进行更改时,您将须要重新启动ng服务以获取配置更改。4、在app.module.ts中引入要应用的ngx-bootstrap module关上src/app/app.module.ts 并增加 import { BsDropdownModule } from 'ngx-bootstrap/dropdown';...@NgModule({ ... imports: [BsDropdownModule.forRoot(), ... ], ...})具体应用哪个bootstrap组件,点击https://valor-software.com/ngx-bootstrap/#/documentation查看

August 15, 2020 · 1 min · jiezi

关于angular:译关于Angular脏值检查你应该知道的最新指南

原文 Angular脏值查看 本文提供了您须要理解的无关变更检测的所有必要信息。通过应用本文构建的演示我的项目来解释angular 的变更检测机制。Angular的变更检测是该框架的外围机制,但(至多以我的教训)很难了解。更可怜的是,官方网站上没有对于此主题的官网指南。 What Is Change DetectionAngular的两个次要指标是可预测和高效。框架须要通过组合状态和模板来在UI上复制应用程序的状态: 如果状态产生任何更改,也必须更新DOM。将HTML与咱们的数据同步的机制称为“更改检测”。每个前端框架都应用其实现,例如React应用虚构DOM,Angular应用更改检测等等。我能够举荐文章“ JavaScript框架中的更改及其检测”,该文章很好地概述了此主题。 更改检测:数据更改后更新DOM的过程作为开发人员,大多数时候咱们不须要关怀变更检测,除非咱们须要优化应用程序的性能。如果处理不当,更改检测会升高大型应用程序的性能。 How Change Detection Works 变更检测是如何工作的变更检测周期能够分为两个局部: 开发人员更新应用程序模型Angular通过从新渲染来同步DOM中的更新模型让咱们更具体地看一下这个过程: 开发人员更新数据模型,例如通过更新组件绑定angular 检测变动变更检测从上到下查看组件树中的每个组件,以查看相应的模型是否已更改如果有新值,它将更新组件的视图(DOM)以下GIF以简化的形式演示了此过程: 该图显示了Angular组件树及其在应用程序疏导过程中为每个组件创立的更改检测器(CD)。该检测器将以后值与属性的先前值进行比拟。如果该值已更改,它将==isChanged==设置为==true==。查看框架代码中的实现,这只是与NaN的非凡解决进行的===比拟。 Zone.js个别状况下,zone能够跟踪并拦挡任何异步工作。 Zone 通常具备以下阶段: 开始稳固如果工作在区域中运行,它将变得不稳固,如果工作实现,它将再次变得稳固Angular在启动时修补了几个低级浏览器API,以便可能检测到应用程序中的更改。这是应用zone.js实现的,该区域修补了EventEmitter,DOM事件侦听器,XMLHttpRequest,Node.js中的fs API等API。 简而言之,如果产生以下事件之一,则框架将触发更改检测 任何浏览器事件(单击,键入等)setInterval() and setTimeout()HTTP 申请Angular应用其称为NgZone的区域。仅存在一个NgZone,并且仅针对此区域中触发的异步操作触发更改检测。 Performance 性能默认状况下,如果模板值已更改,则“Angular Change Detection ”将从上至下查看所有组件。Angular对每个组件执行更改检测的速度十分快,因为它能够应用内联缓存在毫秒内执行数千次查看,内联缓存可生成VM优化代码。 如果您想对此主题有更深刻的阐明,建议您观看Victor Savkin对于“重塑变化检测”的演讲。 只管Angular在后盾进行了大量优化,然而在大型应用程序上性能依然会降落。在下一章中,您将学习如何通过应用不同的变更检测策略来被动进步Angular性能。 Change Detection Strategies 变更检测策略Angular提供了两种策略来运行更改检测: DefaultOnPush让咱们看一下每种变化检测策略。 Default Change Detection Strategy默认状况下,Angular应用ChangeDetectionStrategy.Default更改检测策略。每当事件触发更改检测(例如用户事件,计时器,XHR,promise等)时,此默认策略都会从上到下查看组件树中的每个组件。这种不对组件的依赖项做任何假如的激进查看办法称为脏查看。它可能会对蕴含许多组件的大型应用程序的性能产生负面影响。 OnPush Change Detection Strategy通过将changeDetection属性增加到组件装璜器元数据中,咱们能够切换到ChangeDetectionStrategy.OnPush更改检测策略: @Component({ selector: 'hero-card', changeDetection: ChangeDetectionStrategy.OnPush, template: ...})export class HeroCard { ...}这种更改检测策略能够跳过对此组件及其所有子组件的不必要查看。下一个GIF演示了应用OnPush更改检测策略跳过组件树的各个局部: 应用此策略,Angular晓得仅在以下状况下才须要更新组件: ...

August 10, 2020 · 2 min · jiezi

关于angular:Angular弹珠测试中由于未获取路由参数导致数据不返回的问题

概述最近在进行angular单元测试在组件初始化渲染方面的测试,应用的是RxJS提供的弹珠测试来模仿http申请提早。 然而在某些编辑组件中,ngOnInit办法中应用了router来获取路由参数。在单元测试中,组件不会接管真的路由参数,因而并没有接管到测试数据,初始化时,渲染的组件是空数据。 本文的目标,是通过手动发送路由参数,来使组件胜利获取测试数据。 本文应用的技术基于:angularu在单元测试中如何模仿HTTP申请提早 问题复现在未呈现问题的状况下,当咱们为服务层设置好测试桩、在测试文件中模仿好返回值之后,启动测试之后,组件会失常渲染,并且会填入模仿返回的随机数据。如果在断言非空的语句Assert.isDefined前面退出console.log,控制台能够输入字符串。 如下: 然而,在起初测试的这几个组件中,依照示例代码写完、测试之后,渲染的组件并没有模仿数据,而是空组件。尽管测试也能通过,但通过是因为断言的代码基本没有执行,代码中退出console.log,控制台没有输入。如下: 只管在这种状况下,单元测试也能通过,但事实上,因为基本没有接管到返回值,咱们无奈验证服务层的返回值是否正确,这种做法对我的项目来说,是不负责任的,这增大了生产环境出错的危险。 问题剖析先上组件的ngOnInit初始化代码: ngOnInit() { this.getEditCollege(); } /** * 获取要编辑的学院 */ public getEditCollege() { // 发动订阅,获取路由参数,取得参数后执行回调 this.route.params.subscribe((params: {id: number}) => { console.log("subscribe"); this.collegeService.getCollegeById(params.id).subscribe((data) => { Assert.isDefined(data.id, 'id'); Assert.isDefined(data.name, 'name'); Assert.isDefined(data.code, 'code'); Assert.isDefined(data.number, 'number'); console.log("college->edit"); this.initForm(data); }); }); }通过演绎发现,所有出错的组件都有用route获取路由参数的过程:发动订阅,当后果返回时执行回调办法,向服务层获取对象。 用打断点的形式得出结论,route发动的订阅基本没有返回,因而前面的回调办法也就没有执行。 因为route是通过路由的变动,来获取参数路由参数的,但在单元测试中,路由并不会发生变化。 所以须要用一个假的ActiveRouteStub来代替真的ActiveRoute实现单元测试。 ActiveRouteStub/** * ActiveRouteStub * 路由性能服务桩 */import { Observable, Subject } from 'rxjs';export class ActivatedRouteStub { paramsSubject = new Subject<any>(); params: Observable<any>; parent: any; snapshot = { paramMap: { get: () => { return 0; } } }; constructor() { this.params = this.paramsSubject.asObservable(); }}而后从Provider引入(也能够引入到单元测试专用的辅助模块中,例如ServiceTestingModule): ...

August 6, 2020 · 1 min · jiezi

关于angular:Angular弹珠测试中由于未获取路由参数导致数据不返回的问题

概述最近在进行angular单元测试在组件初始化渲染方面的测试,应用的是RxJS提供的弹珠测试来模仿http申请提早。 然而在某些编辑组件中,ngOnInit办法中应用了router来获取路由参数。在单元测试中,组件不会接管真的路由参数,因而并没有接管到测试数据,初始化时,渲染的组件是空数据。 本文的目标,是通过手动发送路由参数,来使组件胜利获取测试数据。 本文应用的技术基于:angularu在单元测试中如何模仿HTTP申请提早 问题复现在未呈现问题的状况下,当咱们为服务层设置好测试桩、在测试文件中模仿好返回值之后,启动测试之后,组件会失常渲染,并且会填入模仿返回的随机数据。如果在断言非空的语句Assert.isDefined前面退出console.log,控制台能够输入字符串。 如下: 然而,在起初测试的这几个组件中,依照示例代码写完、测试之后,渲染的组件并没有模仿数据,而是空组件。尽管测试也能通过,但通过是因为断言的代码基本没有执行,代码中退出console.log,控制台没有输入。如下: 只管在这种状况下,单元测试也能通过,但事实上,因为基本没有接管到返回值,咱们无奈验证服务层的返回值是否正确,这种做法对我的项目来说,是不负责任的,这增大了生产环境出错的危险。 问题剖析先上组件的ngOnInit初始化代码: ngOnInit() { this.getEditCollege(); } /** * 获取要编辑的学院 */ public getEditCollege() { // 发动订阅,获取路由参数,取得参数后执行回调 this.route.params.subscribe((params: {id: number}) => { console.log("subscribe"); this.collegeService.getCollegeById(params.id).subscribe((data) => { Assert.isDefined(data.id, 'id'); Assert.isDefined(data.name, 'name'); Assert.isDefined(data.code, 'code'); Assert.isDefined(data.number, 'number'); console.log("college->edit"); this.initForm(data); }); }); }通过演绎发现,所有出错的组件都有用route获取路由参数的过程:发动订阅,当后果返回时执行回调办法,向服务层获取对象。 用打断点的形式得出结论,route发动的订阅基本没有返回,因而前面的回调办法也就没有执行。 因为route是通过路由的变动,来获取参数路由参数的,但在单元测试中,路由并不会发生变化。 所以须要用一个假的ActiveRouteStub来代替真的ActiveRoute实现单元测试。 ActiveRouteStub/** * ActiveRouteStub * 路由性能服务桩 */import { Observable, Subject } from 'rxjs';export class ActivatedRouteStub { paramsSubject = new Subject<any>(); params: Observable<any>; parent: any; snapshot = { paramMap: { get: () => { return 0; } } }; constructor() { this.params = this.paramsSubject.asObservable(); }}而后从Provider引入(也能够引入到单元测试专用的辅助模块中,例如ServiceTestingModule): ...

August 6, 2020 · 1 min · jiezi

关于angular:Angular弹珠测试中由于未获取路由参数导致数据不返回的问题

概述最近在进行angular单元测试在组件初始化渲染方面的测试,应用的是RxJS提供的弹珠测试来模仿http申请提早。 然而在某些编辑组件中,ngOnInit办法中应用了router来获取路由参数。在单元测试中,组件不会接管真的路由参数,因而并没有接管到测试数据,初始化时,渲染的组件是空数据。 本文的目标,是通过手动发送路由参数,来使组件胜利获取测试数据。 本文应用的技术基于:angularu在单元测试中如何模仿HTTP申请提早 问题复现在未呈现问题的状况下,当咱们为服务层设置好测试桩、在测试文件中模仿好返回值之后,启动测试之后,组件会失常渲染,并且会填入模仿返回的随机数据。如果在断言非空的语句Assert.isDefined前面退出console.log,控制台能够输入字符串。 如下: 然而,在起初测试的这几个组件中,依照示例代码写完、测试之后,渲染的组件并没有模仿数据,而是空组件。尽管测试也能通过,但通过是因为断言的代码基本没有执行,代码中退出console.log,控制台没有输入。如下: 只管在这种状况下,单元测试也能通过,但事实上,因为基本没有接管到返回值,咱们无奈验证服务层的返回值是否正确,这种做法对我的项目来说,是不负责任的,这增大了生产环境出错的危险。 问题剖析先上组件的ngOnInit初始化代码: ngOnInit() { this.getEditCollege(); } /** * 获取要编辑的学院 */ public getEditCollege() { // 发动订阅,获取路由参数,取得参数后执行回调 this.route.params.subscribe((params: {id: number}) => { console.log("subscribe"); this.collegeService.getCollegeById(params.id).subscribe((data) => { Assert.isDefined(data.id, 'id'); Assert.isDefined(data.name, 'name'); Assert.isDefined(data.code, 'code'); Assert.isDefined(data.number, 'number'); console.log("college->edit"); this.initForm(data); }); }); }通过演绎发现,所有出错的组件都有用route获取路由参数的过程:发动订阅,当后果返回时执行回调办法,向服务层获取对象。 用打断点的形式得出结论,route发动的订阅基本没有返回,因而前面的回调办法也就没有执行。 因为route是通过路由的变动,来获取参数路由参数的,但在单元测试中,路由并不会发生变化。 所以须要用一个假的ActiveRouteStub来代替真的ActiveRoute实现单元测试。 ActiveRouteStub/** * ActiveRouteStub * 路由性能服务桩 */import { Observable, Subject } from 'rxjs';export class ActivatedRouteStub { paramsSubject = new Subject<any>(); params: Observable<any>; parent: any; snapshot = { paramMap: { get: () => { return 0; } } }; constructor() { this.params = this.paramsSubject.asObservable(); }}而后从Provider引入(也能够引入到单元测试专用的辅助模块中,例如ServiceTestingModule): ...

August 6, 2020 · 1 min · jiezi

关于angular:动态懒加载组件解决方案

这是什么失常的应用,是先申明组件,而后在模板中引入组件,这就导致了一个问题,如果一个组件的应用次数非常少,那么这个模块依然会把组件打包进去,使得模块增大本我的项目先将组件当做失常标签写入,而后应用两个装璜器,一个为结构化懒加载指令,一个为自定义表单控件指令用来帮助加载须要前置常识结构型指令属性型指令自定义表白控件ngModel实现原理实用版本ng10(100%)ng9(靠近100%)ng9和ng10没太大改变,所以ng9应该没什么问题ng8(如果不能够须要依赖路由实现)ng7以下(须要依赖路由实现)与8的路由实现形式不同,然而总体是依赖路由实现的成果靠近失常的开发只不过须要多个指令反对只在应用时,会动静申请相干组件input完全相同output 会变成CustomEvent类型,值再detail属性中表单控件在逻辑上应该齐全一样思路通过动静加载并创立的web-component元素,实质上与一般标签齐全一样所以说他就是个元素,无奈响应双向绑定,须要通过指令来代替input,select等类型都是通过指令实现的双向绑定,这也是本次组件的实现思路通过指令的直达,在须要懒加载的组件中退出一个事件,在初始化时发射事件,值为这个组件的实例,通过拿到实例,将自定义表白控件相干的实现办法手动设置逻辑代码地址地址

August 1, 2020 · 1 min · jiezi

关于angular:动态懒加载组件解决方案

这是什么失常的应用,是先申明组件,而后在模板中引入组件,这就导致了一个问题,如果一个组件的应用次数非常少,那么这个模块依然会把组件打包进去,使得模块增大本我的项目先将组件当做失常标签写入,而后应用两个装璜器,一个为结构化懒加载指令,一个为自定义表单控件指令用来帮助加载须要前置常识结构型指令属性型指令自定义表白控件ngModel实现原理实用版本ng10(100%)ng9(靠近100%)ng9和ng10没太大改变,所以ng9应该没什么问题ng8(如果不能够须要依赖路由实现)ng7以下(须要依赖路由实现)与8的路由实现形式不同,然而总体是依赖路由实现的成果靠近失常的开发只不过须要多个指令反对只在应用时,会动静申请相干组件input完全相同output 会变成CustomEvent类型,值再detail属性中表单控件在逻辑上应该齐全一样思路通过动静加载并创立的web-component元素,实质上与一般标签齐全一样所以说他就是个元素,无奈响应双向绑定,须要通过指令来代替input,select等类型都是通过指令实现的双向绑定,这也是本次组件的实现思路通过指令的直达,在须要懒加载的组件中退出一个事件,在初始化时发射事件,值为这个组件的实例,通过拿到实例,将自定义表白控件相干的实现办法手动设置逻辑代码地址地址

August 1, 2020 · 1 min · jiezi

关于angular:Angular入口组件entry-component和声明式组件的区别

转:entry component 示意 angular 的入口组件。 它次要能够分为疏导入口组件和路由到的入口组件。 可疏导组件是一个入口组件,Angular 会在疏导过程中把它加载到 DOM 中。 其它入口组件是在其它机会动静加载的,比方用路由器。 入口组件是在entryComponents 数组中申明的。 然而通常咱们不须要显示的在entryComponents 数组中申明,因为angular足够聪慧,它会主动的把bootStrap 中的组件以及路由器导航到的组件主动的加载到entryComponents 数组中去。尽管这种机制能实用大多数状况,然而如果是一些非凡的命令式的疏导或者动静的加载某个组件(比方对话框组件),那么你必须被动的把这个组件申明到entryComponents 数组中去。 angular编译器会为那些能够从entryComponents 数组中获得的或者能够间接获得的组件生成生产环境的代码。因而,你能够只将必须应用的组件申明在entryComponents 数组中。 Angular的申明式组件和入口组件的区别体现在两者的加载形式不同。 申明式组件是通过组件申明的selector加载入口组件(entry component)是通过组件的类型动静加载申明式组件申明式组件会在模板里通过组件申明的selector加载组件。 示例 @Component({  selector: 'a-cmp',  template: `  <p>这是A组件</p>  `})export class AComponent {}@Component({  selector: 'b-cmp',  template: `  <p>在B组件里内嵌A组件:</p>  <a-cmp></a-cmp>  `})export class BComponent {}在BComponent的模板里,应用selector<a-cmp></a-cmp>申明加载AComponent。入口组件(entry component)入口组件是通过指定的组件类加载组件。 次要分为三类: 在@NgModule.bootstrap里申明的启动组件,如AppComponent。在路由配置里援用的组件其余通过编程应用组件类型加载的动静组件启动组件 app.component.ts @Component({  selector: 'app-root',  templateUrl: './app.component.html',  styleUrls: ['./app.component.scss']})export class AppComponent{}app.module.ts @NgModule({  declarations: [    AppComponent  ],  imports: [    BrowserModule,    BrowserAnimationsModule,    AppRoutingModule  ],  providers: [],  bootstrap: [AppComponent]})export class AppModule { }在bootstrap里申明的AppComponent为启动组件。尽管咱们会在index.html里应用组件的selector<app-root></app-root>的地位,然而Angular并不是依据此selector来加载AppComponent。这是容易让人误会的中央。因为index.html不属于任何组件模板,Angular须要通过编程应用bootstrap里申明的AppComponent类型加载组件,而不是应用selector。 因为Angular动静加载AppComponent,所有AppComponent是一个入口组件。 路由配置援用的组件 @Component({  selector: 'app-nav',  template: `  <nav>    <a  routerLink="/home" routerLinkActive #rla="routerLinkActive" selected="#rla.isActive">首页</a>    <a routerLink="/users" routerLinkActive #rla="routerLinkActive" selected="#rla.isActive">用户</a>  </nav>  <router-outlet></router-outlet>  `})export class NavComponent {}咱们须要配置一个路由 const routes: Routes = [  {    path: "home",    component: HomeComponent  },  {    path: "user",    component: UserComponent  }];@NgModule({  imports: [RouterModule.forRoot(routes)],  exports: [RouterModule]})export class AppRoutingModule { }Angular依据配置的路由,依据路由指定的组件类来加载组件,而不是通过组件的selector加载。 配置入口组件在Angular里,对于入库组件须要在@NgModule.entryComponents里配置。 因为启动组件和路由配置里援用的组件都为入口组件,Angular会在编译时主动把这两种组件增加到@NgModule.entryComponents里。对于咱们本人编写的动静组件须要手动增加到@NgModule.entryComponents里。 @NgModule({   declarations: [     AppComponent   ],   imports: [     BrowserModule,     BrowserAnimationsModule,     AppRoutingModule   ],   providers: [],   entryComponents:[DialogComponent],   declarations:[]   bootstrap: [AppComponent] }) export class AppModule { }

July 24, 2020 · 1 min · jiezi

关于angular:Angular7-http代理proxy配置

前后端拆散开发时,须要进行http申请后端,这时刚会遇上跨域问题。解决办法之一就是应用proxy代理ng proxy是基于webpack proxy, 更详尽阐明:https://webpack.js.org/config...1. proxy.conf.json在我的项目根目下增加文件:proxy.conf.json 示例: { "/api": { "target": "http://localhost:8089/", "secure": false, "pathRewrite": { "^/api": "" }, "changeOrigin": true, "loglevel": "debug" }}示例阐明:对所有/api/*的申请,转发到http://localhost:8089/上 target,个别是后端服务地址pathRewrite,重写url门路。成果就是前端对立申请后端时应用/api/,而理论代理时则无此关键字。changeOrigin,如果你的后端服务不是localhost,则需把此项设为trueloglevel,日志级别。包含 debug, info, warn, error, and silent (默认 info)2. 启动代理ng cli 启动我的项目时会查看是否存在代理文件proxy.conf.json,所以可不需配置启动我的项目 $ ng serve如果你新增了其余代理文件,也能够指定文件进行启动 $ ng serve --proxy-config proxy.conf.json这就实现了代理后端的配置了,应用代理也解决了跨域拜访的问题。

July 22, 2020 · 1 min · jiezi

关于SegmentFault:Angular-NullInjectorError-错误消息的产生根源和处理方式

服务是一个狭义的概念,它包含利用所需的任何值、函数或个性。广义的服务是一个明确定义了用处的类。它应该做一些具体的事,并做好。 Angular 把组件和服务区离开,以进步模块性和复用性。 通过把组件中和视图无关的性能与其它类型的解决分来到,你能够让组件类更加精简、高效。 现实状况下,组件的工作只管用户体验,而不必顾及其它。 它应该提供用于数据绑定的属性和办法,以便作为视图(由模板渲染)和应用逻辑(通常蕴含一些模型的概念)的中介者。 组件应该把诸如从服务器获取数据、验证用户输出或间接往控制台中写日志等工作委托给各种服务。通过把各种解决工作定义到可注入的服务类中,你能够让它被任何组件应用。 通过在不同的环境中注入同一种服务的不同提供者,你还能够让你的利用更具适应性。 Angular 不会强制你遵循这些准则。Angular 只会通过依赖注入来帮你更容易地将应用逻辑合成为服务,并让这些服务可用于各个组件中。

July 20, 2020 · 1 min · jiezi

关于angular:Angular-8降级到Angular-7

降级Angular 8和CLI后,Node版本也须要降级,10.x以上。这时候老我的项目就会出问题了,比方应用cli等命令时,会提醒node版本或ng的版本存在一些问题。这时候降级是最好的解决方案降级步骤Angular降级1. 卸载# 查看以后版本ng --version# 卸载以后CLInpm uninstall -g @angular/cli# 革除缓存npm cache clean --force2. 装置# 装置指定版本npm install -g @angular/cli@7.2.12# 查看以后版本ng --versionNode版本抉择如何应用n来治理Nodejs版本应用Nodejs的 n 工作进行治理,装置与版本抉择。请查看我在segmentfault发的一篇文章(约20K浏览量) 在centos7装置nodejs并降级nodejs到最新版本。

July 18, 2020 · 1 min · jiezi

关于angular:一周小结

前言这周开始接触到了非常正式的我的项目开发,感觉本人间隔能实战真的差太多了,有一些小问题可能要半天或者更久能力解决,单元测试还是硬伤,效率低的不行,早起九点开始写代码,早晨十一点多完结,甚至有一次肝到一点多,然而解决的问题不多,感觉本人有程序员加班的潜质,还没有写好代码的程度,跟代码交换挺有意思的,只是当初能力无限,有些问题还不能无效地解决,这一周的问题还真不少,总结性的整顿了一下。 带有param的GET申请单元测试之前对单元测试的了解是路由对上了就能过,即申请的url与预测的url对应上就能够了,殊不知并非所有的预测url与申请url统一就能够,比方GET办法,上面是一个GET办法的申请: public getUserByUsername(username: string): Observable<boolean> { return this.httpClient.get<boolean>(`${this.baseUrl}/getUserByUsername`, {params: {username}}); }上面是测试: it('getUserByUsername', () => { const username = Random.nextString ('', 11); let result; /* 进行订阅,发送数据后将called置true */ let called = false; service.getUserByUsername(username).subscribe ((data) => { called = true; result = data; }); const request = httpController.expectOne ( `${baseUrl}/getUserByUsername`); expect (request.request.method).toEqual ('GET'); req.flush(of(undefined)); expect (called).toBe (true); });而后运行测试:过后不是很了解为何报错,起初问了一下潘老师,而后老师说教程上有:5 测试HTTP申请【前】,就看到了这: const req = httpTestingController.expectOne('http://localhost:8080/Klass?name=');我认为加上参数就好了,而后就改成了这样: const request = httpController.expectOne ( `${baseUrl}/getUserByUsername?username=`);后果可想而知,还是ERROR,而后启动我的项目,关上控制台看了一下理论申请的:注:该办法并非我的项目原有的办法,只是为了演示,所以申请时会产生谬误。理论申请的url带有参数名和参数,而后就改成了这样: ...

July 18, 2020 · 1 min · jiezi

Angular使用插件导出表格Excel

当初前端都能够进行excel文件的简略导入导出操作。上面是应用插件导出表格成excel文件示例组件是基于ng-alain封装的 XlsxService,XlsService是基于sheetjs开发的。文未附相干资源示例代码 import { Component } from '@angular/core';import { STColumn, XlsxService } from '@delon/abc';@Component({ selector: 'components-xlsx-export', template: ` <button nz-button (click)="download()">Export</button> <!-- 为了方便使用了ng-alain表格组件,也能够用ng-zorro或者其余库实现的表格。展示是主要的,重点是数据 --> <st [data]="users" [ps]="3" [columns]="columns" class="mt-sm"></st> `,})export class ComponentsXlsxExportComponent { constructor(private xlsx: XlsxService) {} // 表格数据-模仿数据 users: any[] = Array(100) .fill({}) .map((_item: any, idx: number) => { return { id: idx + 1, name: `name ${idx + 1}`, age: Math.ceil(Math.random() * 10) + 20, }; }); columns: STColumn[] = [ { title: '编号', index: 'id', type: 'checkbox' }, { title: '姓名', index: 'name' }, { title: '年龄', index: 'age' }, ]; download() { // 组装要导出的数据 const data = [this.columns.map(i => i.title)]; this.users.forEach(i => data.push(this.columns.map(c => i[c.index as string])), ); // 应用组件XlsxService导出数据为xls文件 this.xlsx.export({ filename: '自定义命名列表.xlsx', sheets: [ { data: data, name: 'sheet name', }, ], }); }}相干资源:ng-alain XlsxService https://ng-alain.com/components/xlsx/zhsheetjs https://sheetjs.com/ ...

July 14, 2020 · 1 min · jiezi

angular中delaydebounceTime等时间相关操作符单元测试的一种方法

在上篇文章中咱们讲述了如何在angular中的应用弹珠测试来模仿http异步申请。 应用弹珠测试的办法尽管很官网很正统,但因为其调度器的失效周期的设置起因,若要在单元测试中联合fixture.detectChanges();在某个测试用例结束后持续与组件进行交互,则会产生No test scheduler initialized!错语。 在单元测试中手动的与组件进行交互虽不正规,但该计划无疑会让新成员感触到单元测试敌对性的一面,升高对其的排挤水平。sample比方以后有一组件的性能是当用户在input中输出相应的内容时,先应用500ms防抖阻止冗余的申请,在进行后盾的模仿异步申请: 组件相干代码: // 当输出发生变化时,500ms稳固后从新由后盾拉取数据 this.input.valueChanges.pipe( debounceTime(500), distinctUntilChanged(), switchMap(value => { this.tagName = value; // 申请后盾 return this.tagService.findTop20ByCourseAndNameLike(this.state.courseId, value); }) ).subscribe((tags: Array<Tag>) => { this.tags = tags; });应用弹珠测试的服务层tagService相干代码: /** * 模仿实在后盾,异步返回数据 */ public findTop20ByCourseAndNameLike(courseId: number, name: string): Observable<Array<Tag>> { Assert.notNull(courseId, '课程ID未定义'); const tags = new Array<Tag>(); for (let i = 0; i < 20; i++) { tags.push(new Tag({ id: randomNumber(), name: randomString('name'), course: new Course({id: randomNumber()}) })); } // 应用弹珠测试返回tags return cold('---(x|)', {x: tags}); }基于上述代码,在单元测试中若仅把单元测试的指标定格为单元测试,则不会有任何问题。 ...

July 13, 2020 · 1 min · jiezi

Angular使用HTTP-POST下载流文件

Angular / Vue HTTP POST下载流文件HTTP POST 申请流文件转成excel在应用Angular开发我的项目时,通常会有下载文件的性能项。个别是后盾返回下载地址,通过<a>题目或者应用window关上下载地址新窗口,浏览器则会辨认出流文件进行文件下载。 然而,有时候进行http异步申请,后盾返回的并不是下载地址,而是间接返回一个文件流,这时如何应用http申请回来的文件流转换成文件下载? 其实并非Angular框架存地这样的状况,其余PWA如Vue,React甚至Jquery都通过http xhr进行申请而获取的流文件,浏览器也并不会自动识别并主动下载。 那当然,必定有解决方案。计划思路: http申请应用blob的返回类型,获取文件流后,对数据进行Blob,再提交给浏览器进行辨认下载。上面是代码示例 /** * 导出excel */exportExcel(){ const params = {}; // body的参数 const queryParams = undefined; // url query的参数 this.http.post(this.exportUrl, params, queryParams, { responseType: "blob", headers: new HttpHeaders().append("Content-Type", "application/json") }).subscribe(resp=>{ // resp: 文件流 this.downloadFile(resp); })}/** * 创立blob对象,并利用浏览器关上url进行下载 * @param data 文件流数据 */downloadFile(data) { // 下载类型 xls const contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; // 下载类型:csv const contentType2 = 'text/csv'; const blob = new Blob([data], { type: contentType }); const url = window.URL.createObjectURL(blob); // 关上新窗口形式进行下载 // window.open(url); // 以动态创建a标签进行下载 const a = document.createElement('a'); const fileName = this.datePipe.transform(new Date(), 'yyyyMMdd'); a.href = url; // a.download = fileName; a.download = fileName + '.xlsx'; a.click(); window.URL.revokeObjectURL(url);}

July 12, 2020 · 1 min · jiezi

Angular-之路

Angular 概念function () { return null}

July 11, 2020 · 1 min · jiezi

angularu在单元测试中如何模拟HTTP请求延迟

随着对angular利用学习的深刻,如何在单元测试中模仿http申请提早便提上了日程。在没有http申请提早以前,单元测试中咱们都是应用of()来手动发送数据的。of()办法在单元测试中无疑带来了微小的便利性,但因为同步的机制,使其未能齐全的模仿中在生成环境中http申请提早可能对组件带来的冲击,所以在启用of()进行单元测试后无奈保障该组件在生产环境中是100%牢靠运行的。 浏览本文须要对angular单元测试有肯定理解。sample简略举个of()的例子来查看其如何成为异步申请单元测试中的不牢靠元素。 V层显示学生的姓名 <h1>{{student.name}}</h1>C层初始化学生的值为undefined /** * 该值初始化为undefined */ student: {name: string}; ngOnInit() { // 调用服务来获取ID为1的学生 this.studentService.getById(1) .subscribe(student => { console.log('1接管到了订阅的数据'); this.student = student; }) console.log('2ngOnInit执行结束,开始渲染V层');用于单元测试的测试桩StudentStubService getById(id: number): Observable<{name: string}> { const student = {name: 'hebut yunzhi'}; // 应用of()办法来返回可观察者,该观察者在被订阅时将同步发送数据 return of(student); }控制台打印后果如下: 1接管到了订阅的数据2ngOnInit执行结束,开始渲染V层对应的程序执行流程如下: 生产环境而生产环境中因为进行真正的http申请,该申请是异步的且必然有提早,所以实在的控制台状况如下: 2ngOnInit执行结束,开始渲染V层1接管到了订阅的数据就便成了这样: 也就是说:在有异步申请的状况下,此单元测试并没能保障该组件在生产环境中的正确运行。 接下来,本文将提供两种模仿http申请提早的办法。 没有service的DEMO:[https://stackblitz.com/edit/a...](https://stackblitz.com/edit/a...delay操作符RxJS提供了delay操作符来提早异步发送数据,所以模仿http申请提早的最简略的办法便是在of()办法的根底上退出delay操作符。比方咱们将后面的测试桩修改为: getById(id: number): Observable<{name: string}> { const student = {name: 'hebut yunzhi'}; // 提早500MS异步发送数据 return of(student).delay(500); }此时便起到了提早500MS异步发送数据的目标,所以在单元测试中执行相应的测试代码执行流程如下: ...

July 9, 2020 · 2 min · jiezi

angular的post请求处理

angular的post请求处理。项目angular中使用jQuery请求,想替换为angular自身请求,结果发现后台没法获取參数,所以,查询资料分析一下,做个总结。首先,angular和jQuery中请求是不同的。如下: jQuery:请求contentType是: application/x-www-form-urlencoded; charset=UTF-8该类型数据被编码成以 '&' 分隔的键-值对, 同时以 '=' 分隔键和值. 非字母或数字的字符会被百分比编码: 这也就是为什么这种类型不支持二进制数据(应使用 multipart/form-data 代替)。data参数是处理过的: // json对象{ a : 3, b : 2 }// 将json对象处理为"a=3&b=2"Angular:请求contentType: application/jsondata参数: // json对象{a: 3,c: 2}综上来看,angular提交后台是json,不是表单数据。我们需要把json对象转换为参数拼接,提交后台时就是表单数据了: /** * 将application/json转换为application/x-www-form-urlencoded * @param data */ handlerPostParams(data) { const params = []; for (const key in data) { if (data[key] && !isNull(data[key])) { if (data[key] instanceof Array) { for (let i = 0; i < data[key].length; i++) { if (data[key][i] && !isNull(data[key][i])) { const value = data[key][i]; const name = key + '[' + i + ']'; const innerObj = {}; innerObj[name] = value; params.push(this.handlerPostParams(innerObj)); } } } else if (data[key] instanceof Object) { for (const k in data[key]) { if (data[key][k] && !isNull(data[key][k])) { const value = data[key][k]; const name = key + '[' + k + ']'; const innerObj = {}; innerObj[name] = value; params.push(this.handlerPostParams(innerObj)); } } } else { const param = encodeURIComponent(key) + '=' + encodeURIComponent(data[key]); params.push(param); } } } return params.join('&'); }

June 28, 2020 · 1 min · jiezi

angularjs-多图上传删除及拖拽排序

需求:上传多张图片后,需要手动拖拽排序,传给java后台 file用angularjs,sortablejs 简单的demo需要引入的js文件 <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script><script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script><script src="https://cdn.staticfile.org/angular.js/1.6.6/angular.min.js"></script><script src="sortable/sortable.js"></script>html <body ng-app="app"> <div ng-controller="sortCtrl"> <ul class="list_img clearfix" ui-sortable="sortableOptions" ng-model="imgshows"> <li ng-repeat="imageSrc in imgshows track by $index" > <!--//显示图片--> <img ng-src="{{imageSrc}}" alt="" /> <!--//删除按钮--> <i ng-click="uploadimg_del($index, imgshows)" style="display: inline-block;position: absolute; top: -10px; right: -2px; cursor: pointer;">×</i> </li> <li class="add_btn"> <label class="bgimg" for="fileImg"></label> <div class="file-box"> <img id="imgShow" onclick="$('#fileImg').click();" src="img/systemicon_nav_img_18.png"/> <input type="file" style="display: none;" name="upload_img" file="upload_img" accept="image/*" class="file-btn" id="fileImg" /> </div> </li> </ul> </div></body>style样式 <style> .list_img{ list-style: none; } .list_img li{ position: relative; float: left; margin-right: 20px; } .list_img li img{ width: 100px; height: 80px; }</style>js内容 ...

June 18, 2020 · 2 min · jiezi