fix: merge code & fix some issues
This commit is contained in:
parent
8136953a09
commit
f7a6ccbb5d
@ -97,7 +97,7 @@ The `@Injectable` decorator is an essential ingredient in every Angular service
|
||||
The rest of the class has been rewritten to expose a `getHeroes` method
|
||||
that returns the same mock data as before.
|
||||
|
||||
[`@Injectable` 装饰器](#injectable)是定义每个 Angular 服务时的必备部分。
|
||||
`@Injectable` 装饰器是定义每个 Angular 服务时的必备部分。
|
||||
把该类的其它部分改写为暴露一个返回和以前一样的 mock 数据的 `getHeroes` 方法。
|
||||
|
||||
<code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" title="src/app/heroes/hero.service.3.ts">
|
||||
|
@ -7,56 +7,31 @@ Angular is a platform that makes it easy to build applications with the web. Ang
|
||||
Angular 是一个开发平台。它能帮你更轻松的构建 Web 应用。Angular 集声明式模板、依赖注入、端到端工具和一些最佳实践于一身,为你解决开发方面的各种挑战。Angular 为开发者提升构建 Web、手机或桌面应用的能力。
|
||||
|
||||
<div class="card-container">
|
||||
|
||||
<a href="generated/live-examples/toh-pt1/stackblitz.html" target="_blank" class="docs-card"
|
||||
title="Experience Angular in a live coding environment">
|
||||
|
||||
<section>Get a Glimpse of Angular</section>
|
||||
|
||||
<section>Angular 走马观花</section>
|
||||
|
||||
<p>A quick look at an Angular "hello world" application.</p>
|
||||
|
||||
<p>快速体验 Angular 的 "hello world" 应用。</p>
|
||||
|
||||
<p class="card-footer">Angular in Action</p>
|
||||
|
||||
<p class="card-footer">体验 Angular</p>
|
||||
|
||||
</a>
|
||||
|
||||
<a href="guide/quickstart" class="docs-card" title="Angular Quickstart">
|
||||
|
||||
<section>Get Going with Angular</section>
|
||||
|
||||
<section>开始使用 Angular</section>
|
||||
|
||||
<p>Get going on your own environment with the Quickstart.</p>
|
||||
|
||||
<p>跟随"快速上手"构建你的开发环境</p>
|
||||
|
||||
<p class="card-footer">Quickstart</p>
|
||||
|
||||
<p class="card-footer">快速上手</p>
|
||||
|
||||
</a>
|
||||
|
||||
<a href="guide/architecture" class="docs-card" title="Angular Architecture">
|
||||
|
||||
<section>Fundamentals</section>
|
||||
|
||||
<section>基本原理</section>
|
||||
|
||||
<p>Learn Angular application fundamentals, starting with an architecture overview.</p>
|
||||
|
||||
<p>学习 Angular 应用的基本原理。<br/>从架构概览开始。</p>
|
||||
|
||||
<p class="card-footer">Architecture</p>
|
||||
|
||||
<p class="card-footer">架构</p>
|
||||
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
## Assumptions
|
||||
@ -74,8 +49,9 @@ Most Angular code can be written with just the latest JavaScript,
|
||||
using [types](https://www.typescriptlang.org/docs/handbook/classes.html "TypeScript Types") for dependency injection,
|
||||
and using [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html "Decorators") for metadata.
|
||||
|
||||
|
||||
本文档假设你已经熟悉了 [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript "Learn JavaScript") 和来自 [最新标准](https://babeljs.io/learn-es2015/ "Latest JavaScript standards") 的一些知识,比如 [类](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes "ES2015 Classes") 和 [模块](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import "ES2015 Modules")。
|
||||
下列代码范例都是用最新版本的 JavaScript 写的,利用 [类型](https://www.typescriptlang.org/docs/handbook/classes.html "TypeScript Types") 实现依赖注入,并使用[装饰器](https://www.typescriptlang.org/docs/handbook/decorators.html "Decorators")来提供元数据。
|
||||
下列代码范例都是用最新版本的 [TypeScript](https://www.typescriptlang.org/ "TypeScript") 写的,利用 [类型](https://www.typescriptlang.org/docs/handbook/classes.html "TypeScript Types") 实现依赖注入,并使用[装饰器](https://www.typescriptlang.org/docs/handbook/decorators.html "Decorators")来提供元数据。
|
||||
|
||||
## Feedback
|
||||
|
||||
|
@ -5,6 +5,8 @@ import { AsyncSubject, Observable, of } from 'rxjs';
|
||||
import { catchError, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
import { DocumentContents } from './document-contents';
|
||||
import { Logger } from '../shared/logger.service';
|
||||
import { LocationService } from '../shared/location.service';
|
||||
|
||||
export { DocumentContents } from './document-contents';
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Component, ElementRef, EventEmitter, Input, OnDestroy, Output } from '@angular/core';
|
||||
import { HostListener } from '@angular/core';
|
||||
import { Title, Meta } from '@angular/platform-browser';
|
||||
import { Component, ElementRef, EventEmitter, HostListener, Input, OnDestroy, Output } from '@angular/core';
|
||||
import { Meta, Title } from '@angular/platform-browser';
|
||||
|
||||
import { Observable, of, timer } from 'rxjs';
|
||||
import { catchError, switchMap, takeUntil, tap } from 'rxjs/operators';
|
||||
|
||||
import { DocumentContents, FILE_NOT_FOUND_ID, FETCHING_ERROR_ID } from 'app/documents/document.service';
|
||||
import { DocumentContents, FETCHING_ERROR_ID, FILE_NOT_FOUND_ID } from 'app/documents/document.service';
|
||||
import { Logger } from 'app/shared/logger.service';
|
||||
import { TocService } from 'app/shared/toc.service';
|
||||
import { ElementsLoader } from 'app/custom-elements/elements-loader';
|
||||
@ -79,10 +78,10 @@ export class DocViewerComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
this.docContents$
|
||||
.pipe(switchMap(newDoc => this.render(newDoc)),
|
||||
.pipe(switchMap(newDoc => this.render(newDoc)),
|
||||
takeUntil(this.onDestroy$),
|
||||
)
|
||||
.subscribe();
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@ -133,23 +132,23 @@ export class DocViewerComponent implements OnDestroy {
|
||||
this.setNoIndex(doc.id === FILE_NOT_FOUND_ID || doc.id === FETCHING_ERROR_ID);
|
||||
|
||||
return this.void$.pipe(
|
||||
// Security: `doc.contents` is always authored by the documentation team
|
||||
// and is considered to be safe.
|
||||
tap(() => this.nextViewContainer.innerHTML = doc.contents || ''),
|
||||
tap(() => swapOriginAndResult(this.nextViewContainer))
|
||||
.do(() =>addTitleAndToc = this.prepareTitleAndToc(this.nextViewContainer, doc.id)),
|
||||
switchMap(() => this.elementsLoader.loadContainingCustomElements(this.nextViewContainer)),
|
||||
tap(() => this.docReady.emit())
|
||||
,
|
||||
switchMap(() => this.swapViews(addTitleAndToc)),
|
||||
tap(() => this.docRendered.emit()),
|
||||
catchError(err => {
|
||||
const errorMessage = (err instanceof Error) ? err.stack : err;
|
||||
this.logger.error(new Error(`[DocViewer] Error preparing document '${doc.id}': ${errorMessage}`));
|
||||
this.nextViewContainer.innerHTML = '';
|
||||
this.setNoIndex(true);
|
||||
return this.void$;
|
||||
}),
|
||||
// Security: `doc.contents` is always authored by the documentation team
|
||||
// and is considered to be safe.
|
||||
tap(() => this.nextViewContainer.innerHTML = doc.contents || ''),
|
||||
tap(() => swapOriginAndResult(this.nextViewContainer)),
|
||||
tap(() => addTitleAndToc = this.prepareTitleAndToc(this.nextViewContainer, doc.id)),
|
||||
switchMap(() => this.elementsLoader.loadContainingCustomElements(this.nextViewContainer)),
|
||||
tap(() => this.docReady.emit())
|
||||
,
|
||||
switchMap(() => this.swapViews(addTitleAndToc)),
|
||||
tap(() => this.docRendered.emit()),
|
||||
catchError(err => {
|
||||
const errorMessage = (err instanceof Error) ? err.stack : err;
|
||||
this.logger.error(new Error(`[DocViewer] Error preparing document '${doc.id}': ${errorMessage}`));
|
||||
this.nextViewContainer.innerHTML = '';
|
||||
this.setNoIndex(true);
|
||||
return this.void$;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@ -174,7 +173,8 @@ export class DocViewerComponent implements OnDestroy {
|
||||
* entering animation has been completed. This is useful for work that needs to be done as soon as
|
||||
* the element has been attached to the DOM.
|
||||
*/
|
||||
protected swapViews(onInsertedCb = () => {}): Observable<void> {
|
||||
protected swapViews(onInsertedCb = () => {
|
||||
}): Observable<void> {
|
||||
const raf$ = new Observable<void>(subscriber => {
|
||||
const rafId = requestAnimationFrame(() => {
|
||||
subscriber.next();
|
||||
@ -192,26 +192,27 @@ export class DocViewerComponent implements OnDestroy {
|
||||
return 1000 * seconds;
|
||||
};
|
||||
const animateProp =
|
||||
(elem: HTMLElement, prop: keyof CSSStyleDeclaration, from: string, to: string, duration = 200) => {
|
||||
const animationsDisabled = !DocViewerComponent.animationsEnabled
|
||||
|| this.hostElement.classList.contains(NO_ANIMATIONS);
|
||||
if (prop === 'length' || prop === 'parentRule') {
|
||||
// We cannot animate length or parentRule properties because they are readonly
|
||||
return this.void$;
|
||||
}
|
||||
elem.style.transition = '';
|
||||
return animationsDisabled
|
||||
? this.void$.pipe(tap(() => elem.style[prop] = to))
|
||||
: this.void$.pipe(
|
||||
// In order to ensure that the `from` value will be applied immediately (i.e.
|
||||
// without transition) and that the `to` value will be affected by the
|
||||
// `transition` style, we need to ensure an animation frame has passed between
|
||||
// setting each style.
|
||||
switchMap(() => raf$), tap(() => elem.style[prop] = from),
|
||||
switchMap(() => raf$), tap(() => elem.style.transition = `all ${duration}ms ease-in-out`),
|
||||
switchMap(() => raf$), tap(() => (elem.style as any)[prop] = to),
|
||||
switchMap(() => timer(getActualDuration(elem))),switchMap(() => this.void$),
|
||||
);};
|
||||
(elem: HTMLElement, prop: keyof CSSStyleDeclaration, from: string, to: string, duration = 200) => {
|
||||
const animationsDisabled = !DocViewerComponent.animationsEnabled
|
||||
|| this.hostElement.classList.contains(NO_ANIMATIONS);
|
||||
if (prop === 'length' || prop === 'parentRule') {
|
||||
// We cannot animate length or parentRule properties because they are readonly
|
||||
return this.void$;
|
||||
}
|
||||
elem.style.transition = '';
|
||||
return animationsDisabled
|
||||
? this.void$.pipe(tap(() => elem.style[prop] = to))
|
||||
: this.void$.pipe(
|
||||
// In order to ensure that the `from` value will be applied immediately (i.e.
|
||||
// without transition) and that the `to` value will be affected by the
|
||||
// `transition` style, we need to ensure an animation frame has passed between
|
||||
// setting each style.
|
||||
switchMap(() => raf$), tap(() => elem.style[prop] = from),
|
||||
switchMap(() => raf$), tap(() => elem.style.transition = `all ${duration}ms ease-in-out`),
|
||||
switchMap(() => raf$), tap(() => (elem.style as any)[prop] = to),
|
||||
switchMap(() => timer(getActualDuration(elem))), switchMap(() => this.void$),
|
||||
);
|
||||
};
|
||||
|
||||
const animateLeave = (elem: HTMLElement) => animateProp(elem, 'opacity', '1', '0.1');
|
||||
const animateEnter = (elem: HTMLElement) => animateProp(elem, 'opacity', '0.1', '1');
|
||||
@ -220,26 +221,26 @@ export class DocViewerComponent implements OnDestroy {
|
||||
|
||||
if (this.currViewContainer.parentElement) {
|
||||
done$ = done$.pipe(
|
||||
// Remove the current view from the viewer.
|
||||
switchMap(() => animateLeave(this.currViewContainer)),
|
||||
tap(() => this.currViewContainer.parentElement!.removeChild(this.currViewContainer)),
|
||||
tap(() => this.docRemoved.emit()),
|
||||
// Remove the current view from the viewer.
|
||||
switchMap(() => animateLeave(this.currViewContainer)),
|
||||
tap(() => this.currViewContainer.parentElement!.removeChild(this.currViewContainer)),
|
||||
tap(() => this.docRemoved.emit()),
|
||||
);
|
||||
}
|
||||
|
||||
return done$.pipe(
|
||||
// Insert the next view into the viewer.
|
||||
tap(() => this.hostElement.appendChild(this.nextViewContainer)),
|
||||
tap(() => onInsertedCb()),
|
||||
tap(() => this.docInserted.emit()),
|
||||
switchMap(() => animateEnter(this.nextViewContainer)),
|
||||
// Update the view references and clean up unused nodes.
|
||||
tap(() => {
|
||||
const prevViewContainer = this.currViewContainer;
|
||||
this.currViewContainer = this.nextViewContainer;
|
||||
this.nextViewContainer = prevViewContainer;
|
||||
this.nextViewContainer.innerHTML = ''; // Empty to release memory.
|
||||
}),
|
||||
// Insert the next view into the viewer.
|
||||
tap(() => this.hostElement.appendChild(this.nextViewContainer)),
|
||||
tap(() => onInsertedCb()),
|
||||
tap(() => this.docInserted.emit()),
|
||||
switchMap(() => animateEnter(this.nextViewContainer)),
|
||||
// Update the view references and clean up unused nodes.
|
||||
tap(() => {
|
||||
const prevViewContainer = this.currViewContainer;
|
||||
this.currViewContainer = this.nextViewContainer;
|
||||
this.nextViewContainer = prevViewContainer;
|
||||
this.nextViewContainer.innerHTML = ''; // Empty to release memory.
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { ScrollSpyInfo, ScrollSpyService } from 'app/shared/scroll-spy.service';
|
||||
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
|
||||
|
||||
export interface TocItem {
|
||||
|
Loading…
x
Reference in New Issue
Block a user