├── .gitignore
├── README.md
├── angular.json
├── e2e
├── protractor.conf.js
├── src
│ ├── app.e2e-spec.ts
│ └── app.po.ts
└── tsconfig.e2e.json
├── package.json
├── src
├── app
│ ├── accessibility
│ │ ├── active-descendant
│ │ │ ├── active-item-option
│ │ │ │ └── item-active-option.component.ts
│ │ │ ├── cdk-active-descendant.component.html
│ │ │ ├── cdk-active-descendant.component.less
│ │ │ └── cdk-active-descendant.component.ts
│ │ ├── cdk-accessibility-routing.module.ts
│ │ ├── cdk-accessibility.component.html
│ │ ├── cdk-accessibility.component.less
│ │ ├── cdk-accessibility.component.ts
│ │ ├── cdk-accessibility.module.ts
│ │ ├── filter.pipe.ts
│ │ ├── focus-monitor
│ │ │ ├── cdk-focus-monitor.component.html
│ │ │ ├── cdk-focus-monitor.component.less
│ │ │ └── cdk-focus-monitor.component.ts
│ │ ├── focus-trap-factory
│ │ │ ├── cdk-focus-trap-factory.component.html
│ │ │ ├── cdk-focus-trap-factory.component.less
│ │ │ └── cdk-focus-trap-factory.component.ts
│ │ ├── focus
│ │ │ ├── cdk-focus.component.html
│ │ │ ├── cdk-focus.component.less
│ │ │ ├── cdk-focus.component.ts
│ │ │ └── focus-item-option
│ │ │ │ └── item-focus-option.component.ts
│ │ ├── interactivity-checker
│ │ │ ├── cdk-interactivity-checker.component.html
│ │ │ ├── cdk-interactivity-checker.component.less
│ │ │ └── cdk-interactivity-checker.component.ts
│ │ └── live-announcer
│ │ │ ├── cdk-live-announcer.component.html
│ │ │ ├── cdk-live-announcer.component.less
│ │ │ └── cdk-live-announcer.component.ts
│ ├── app-routing.module.ts
│ ├── app.component.html
│ ├── app.component.less
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── bidi
│ │ ├── cdk-bidi-routing.module.ts
│ │ ├── cdk-bidi.component.html
│ │ ├── cdk-bidi.component.less
│ │ ├── cdk-bidi.component.ts
│ │ └── cdk-bidi.module.ts
│ ├── coercion
│ │ ├── cdk-coercion-routing.module.ts
│ │ ├── cdk-coercion.component.html
│ │ ├── cdk-coercion.component.less
│ │ ├── cdk-coercion.component.ts
│ │ └── cdk-coercion.module.ts
│ ├── drag-drop
│ │ ├── cdk-drag-drop-routing.module.ts
│ │ ├── cdk-drag-drop.component.html
│ │ ├── cdk-drag-drop.component.less
│ │ ├── cdk-drag-drop.component.ts
│ │ ├── cdk-drag-drop.module.ts
│ │ ├── controlling-with-item
│ │ │ ├── drag-drop-controlling-with-item.component.html
│ │ │ ├── drag-drop-controlling-with-item.component.less
│ │ │ └── drag-drop-controlling-with-item.component.ts
│ │ ├── customizing-drag-place-holder
│ │ │ ├── drag-drop-customizing-drag-place-holder.component.html
│ │ │ ├── drag-drop-customizing-drag-place-holder.component.less
│ │ │ └── drag-drop-customizing-drag-place-holder.component.ts
│ │ ├── customizing-drag-preview
│ │ │ ├── drag-drop-customizing-drag-preview.component.html
│ │ │ ├── drag-drop-customizing-drag-preview.component.less
│ │ │ └── drag-drop-customizing-drag-preview.component.ts
│ │ ├── disable-drag
│ │ │ ├── drag-drop-disable-drag.component.html
│ │ │ ├── drag-drop-disable-drag.component.less
│ │ │ └── drag-drop-disable-drag.component.ts
│ │ ├── drag-dialog
│ │ │ ├── drag-drop-drag-dialog.component.html
│ │ │ ├── drag-drop-drag-dialog.component.less
│ │ │ └── drag-drop-drag-dialog.component.ts
│ │ ├── drop-directive
│ │ │ ├── drag-drop-drop.component.html
│ │ │ ├── drag-drop-drop.component.less
│ │ │ └── drag-drop-drop.component.ts
│ │ ├── drop-list-directive
│ │ │ ├── drag-drop-drop-list.component.html
│ │ │ ├── drag-drop-drop-list.component.less
│ │ │ └── drag-drop-drop-list.component.ts
│ │ ├── handle-drag-area
│ │ │ ├── drag-drop-handle-drag-area.component.html
│ │ │ ├── drag-drop-handle-drag-area.component.less
│ │ │ └── drag-drop-handle-drag-area.component.ts
│ │ ├── orientation-drag
│ │ │ ├── drag-drop-orientation-drag.component.html
│ │ │ ├── drag-drop-orientation-drag.component.less
│ │ │ └── drag-drop-orientation-drag.component.ts
│ │ ├── restricting-move-area
│ │ │ ├── drag-drop-restricting-move-area.component.html
│ │ │ ├── drag-drop-restricting-move-area.component.less
│ │ │ └── drag-drop-restricting-move-area.component.ts
│ │ └── transferring-item
│ │ │ ├── drag-drop-transferring-item.component.html
│ │ │ ├── drag-drop-transferring-item.component.less
│ │ │ └── drag-drop-transferring-item.component.ts
│ ├── keycodes
│ │ ├── cdk-key-codes-routing.module.ts
│ │ ├── cdk-key-codes.component.html
│ │ ├── cdk-key-codes.component.less
│ │ ├── cdk-key-codes.component.ts
│ │ └── cdk-key-codes.module.ts
│ ├── layout
│ │ ├── cdk-layout-routing.module.ts
│ │ ├── cdk-layout.component.html
│ │ ├── cdk-layout.component.less
│ │ ├── cdk-layout.component.ts
│ │ └── cdk-layout.module.ts
│ ├── observers
│ │ ├── cdk-observers-routing.module.ts
│ │ ├── cdk-observers.component.html
│ │ ├── cdk-observers.component.less
│ │ ├── cdk-observers.component.ts
│ │ ├── cdk-observers.module.ts
│ │ └── child
│ │ │ ├── observers-child.component.html
│ │ │ ├── observers-child.component.less
│ │ │ └── observers-child.component.ts
│ ├── overlay
│ │ ├── cdk-overlay-routing.module.ts
│ │ ├── cdk-overlay.component.html
│ │ ├── cdk-overlay.component.less
│ │ ├── cdk-overlay.component.ts
│ │ ├── cdk-overlay.module.ts
│ │ └── panel
│ │ │ └── overlay-panel.component.ts
│ ├── platform
│ │ ├── cdk-platform-routing.module.ts
│ │ ├── cdk-platform.component.html
│ │ ├── cdk-platform.component.less
│ │ ├── cdk-platform.component.ts
│ │ └── cdk-platform.module.ts
│ ├── portal
│ │ ├── cdk-portal-routing.module.ts
│ │ ├── cdk-portal.component.html
│ │ ├── cdk-portal.component.less
│ │ ├── cdk-portal.component.ts
│ │ ├── cdk-portal.module.ts
│ │ ├── portal-child-component
│ │ │ └── portal-child.component.ts
│ │ ├── portal-component
│ │ │ └── portal-component.component.ts
│ │ ├── portal-template
│ │ │ └── portal-template.component.ts
│ │ └── portal-tool-tip
│ │ │ ├── tool-tip.component.ts
│ │ │ └── tool-tip.directive.ts
│ ├── scrolling
│ │ ├── cdk-scrolling-routing.module.ts
│ │ ├── cdk-scrolling.component.html
│ │ ├── cdk-scrolling.component.less
│ │ ├── cdk-scrolling.component.ts
│ │ ├── cdk-scrolling.module.ts
│ │ ├── drag-scrolling
│ │ │ ├── drag-scrolling.component.html
│ │ │ ├── drag-scrolling.component.less
│ │ │ └── drag-scrolling.component.ts
│ │ ├── virtual-scroll-data-source
│ │ │ ├── customer-data-source.ts
│ │ │ ├── virtual-scroll-data-source.component.html
│ │ │ ├── virtual-scroll-data-source.component.less
│ │ │ └── virtual-scroll-data-source.component.ts
│ │ ├── virtual-scroll-horizontal
│ │ │ ├── virtual-scroll-horizontal.component.html
│ │ │ ├── virtual-scroll-horizontal.component.less
│ │ │ └── virtual-scroll-horizontal.component.ts
│ │ ├── virtual-scroll-strategies
│ │ │ ├── custom-virtual-scroll-strategies.ts
│ │ │ ├── virtual-scroll-strategies.component.html
│ │ │ ├── virtual-scroll-strategies.component.less
│ │ │ └── virtual-scroll-strategies.component.ts
│ │ └── virtual-scroll
│ │ │ ├── virtual-scroll.component.html
│ │ │ ├── virtual-scroll.component.less
│ │ │ └── virtual-scroll.component.ts
│ ├── table
│ │ ├── cdk-base-table-routing.module.ts
│ │ ├── cdk-base-table.component.html
│ │ ├── cdk-base-table.component.less
│ │ ├── cdk-base-table.component.ts
│ │ └── cdk-base-table.module.ts
│ ├── text-field
│ │ ├── cdk-text-field-routing.module.ts
│ │ ├── cdk-text-field.component.html
│ │ ├── cdk-text-field.component.less
│ │ ├── cdk-text-field.component.ts
│ │ └── cdk-text-field.module.ts
│ ├── tip
│ │ ├── tip.component.html
│ │ ├── tip.component.less
│ │ ├── tip.component.ts
│ │ └── tip.directive.ts
│ └── workflow-stepper
│ │ ├── cdk-workflow-stepper-routing.module.ts
│ │ ├── cdk-workflow-stepper.component.html
│ │ ├── cdk-workflow-stepper.component.less
│ │ ├── cdk-workflow-stepper.component.ts
│ │ ├── cdk-workflow-stepper.module.ts
│ │ └── stepper
│ │ ├── stepper-animations.ts
│ │ ├── stepper-header.component.html
│ │ ├── stepper-header.component.less
│ │ ├── stepper-header.component.ts
│ │ ├── stepper.component.html
│ │ ├── stepper.component.less
│ │ └── stepper.component.ts
├── assets
│ └── .gitkeep
├── browserslist
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── karma.conf.js
├── main.ts
├── polyfills.ts
├── styles.less
├── test.ts
├── tsconfig.app.json
├── tsconfig.spec.json
└── tslint.json
├── tsconfig.json
└── tslint.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | package-lock.json
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AngularCdkStudy
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.8.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
28 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "angular-cdk-study": {
7 | "root": "",
8 | "sourceRoot": "src",
9 | "projectType": "application",
10 | "prefix": "app",
11 | "schematics": {
12 | "@schematics/angular:component": {
13 | "styleext": "less"
14 | }
15 | },
16 | "architect": {
17 | "build": {
18 | "builder": "@angular-devkit/build-angular:browser",
19 | "options": {
20 | "outputPath": "dist/angular-cdk-study",
21 | "index": "src/index.html",
22 | "main": "src/main.ts",
23 | "polyfills": "src/polyfills.ts",
24 | "tsConfig": "src/tsconfig.app.json",
25 | "assets": [
26 | "src/favicon.ico",
27 | "src/assets"
28 | ],
29 | "styles": [
30 | "src/styles.less"
31 | ],
32 | "scripts": []
33 | },
34 | "configurations": {
35 | "production": {
36 | "fileReplacements": [
37 | {
38 | "replace": "src/environments/environment.ts",
39 | "with": "src/environments/environment.prod.ts"
40 | }
41 | ],
42 | "optimization": true,
43 | "outputHashing": "all",
44 | "sourceMap": false,
45 | "extractCss": true,
46 | "namedChunks": false,
47 | "aot": true,
48 | "extractLicenses": true,
49 | "vendorChunk": false,
50 | "buildOptimizer": true
51 | }
52 | }
53 | },
54 | "serve": {
55 | "builder": "@angular-devkit/build-angular:dev-server",
56 | "options": {
57 | "browserTarget": "angular-cdk-study:build"
58 | },
59 | "configurations": {
60 | "production": {
61 | "browserTarget": "angular-cdk-study:build:production"
62 | }
63 | }
64 | },
65 | "extract-i18n": {
66 | "builder": "@angular-devkit/build-angular:extract-i18n",
67 | "options": {
68 | "browserTarget": "angular-cdk-study:build"
69 | }
70 | },
71 | "test": {
72 | "builder": "@angular-devkit/build-angular:karma",
73 | "options": {
74 | "main": "src/test.ts",
75 | "polyfills": "src/polyfills.ts",
76 | "tsConfig": "src/tsconfig.spec.json",
77 | "karmaConfig": "src/karma.conf.js",
78 | "styles": [
79 | "src/styles.less"
80 | ],
81 | "scripts": [],
82 | "assets": [
83 | "src/favicon.ico",
84 | "src/assets"
85 | ]
86 | }
87 | },
88 | "lint": {
89 | "builder": "@angular-devkit/build-angular:tslint",
90 | "options": {
91 | "tsConfig": [
92 | "src/tsconfig.app.json",
93 | "src/tsconfig.spec.json"
94 | ],
95 | "exclude": [
96 | "**/node_modules/**"
97 | ]
98 | }
99 | }
100 | }
101 | },
102 | "angular-cdk-study-e2e": {
103 | "root": "e2e/",
104 | "projectType": "application",
105 | "architect": {
106 | "e2e": {
107 | "builder": "@angular-devkit/build-angular:protractor",
108 | "options": {
109 | "protractorConfig": "e2e/protractor.conf.js",
110 | "devServerTarget": "angular-cdk-study:serve"
111 | },
112 | "configurations": {
113 | "production": {
114 | "devServerTarget": "angular-cdk-study:serve:production"
115 | }
116 | }
117 | },
118 | "lint": {
119 | "builder": "@angular-devkit/build-angular:tslint",
120 | "options": {
121 | "tsConfig": "e2e/tsconfig.e2e.json",
122 | "exclude": [
123 | "**/node_modules/**"
124 | ]
125 | }
126 | }
127 | }
128 | }
129 | },
130 | "defaultProject": "angular-cdk-study"
131 | }
--------------------------------------------------------------------------------
/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | const { SpecReporter } = require('jasmine-spec-reporter');
5 |
6 | exports.config = {
7 | allScriptsTimeout: 11000,
8 | specs: [
9 | './src/**/*.e2e-spec.ts'
10 | ],
11 | capabilities: {
12 | 'browserName': 'chrome'
13 | },
14 | directConnect: true,
15 | baseUrl: 'http://localhost:4200/',
16 | framework: 'jasmine',
17 | jasmineNodeOpts: {
18 | showColors: true,
19 | defaultTimeoutInterval: 30000,
20 | print: function() {}
21 | },
22 | onPrepare() {
23 | require('ts-node').register({
24 | project: require('path').join(__dirname, './tsconfig.e2e.json')
25 | });
26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
27 | }
28 | };
--------------------------------------------------------------------------------
/e2e/src/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 |
3 | describe('workspace-project App', () => {
4 | let page: AppPage;
5 |
6 | beforeEach(() => {
7 | page = new AppPage();
8 | });
9 |
10 | it('should display welcome message', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('Welcome to angular-cdk-study!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/e2e/src/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "module": "commonjs",
6 | "target": "es5",
7 | "types": [
8 | "jasmine",
9 | "jasminewd2",
10 | "node"
11 | ]
12 | }
13 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-cdk-study",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "test": "ng test",
9 | "lint": "ng lint",
10 | "e2e": "ng e2e"
11 | },
12 | "private": true,
13 | "dependencies": {
14 | "@angular/animations": "^6.0.3",
15 | "@angular/cdk": "^7.0.4",
16 | "@angular/common": "^6.0.3",
17 | "@angular/compiler": "^6.0.3",
18 | "@angular/core": "^6.0.3",
19 | "@angular/forms": "^6.0.3",
20 | "@angular/http": "^6.0.3",
21 | "@angular/platform-browser": "^6.0.3",
22 | "@angular/platform-browser-dynamic": "^6.0.3",
23 | "@angular/router": "^6.0.3",
24 | "core-js": "^2.5.4",
25 | "rxjs": "^6.0.0",
26 | "zone.js": "^0.8.26"
27 | },
28 | "devDependencies": {
29 | "@angular/compiler-cli": "^6.0.3",
30 | "@angular-devkit/build-angular": "~0.6.8",
31 | "typescript": "~2.7.2",
32 | "@angular/cli": "~6.0.8",
33 | "@angular/language-service": "^6.0.3",
34 | "@types/jasmine": "~2.8.6",
35 | "@types/jasminewd2": "~2.0.3",
36 | "@types/node": "~8.9.4",
37 | "codelyzer": "~4.2.1",
38 | "jasmine-core": "~2.99.1",
39 | "jasmine-spec-reporter": "~4.2.1",
40 | "karma": "~1.7.1",
41 | "karma-chrome-launcher": "~2.2.0",
42 | "karma-coverage-istanbul-reporter": "~2.0.0",
43 | "karma-jasmine": "~1.1.1",
44 | "karma-jasmine-html-reporter": "^0.2.2",
45 | "protractor": "~5.3.0",
46 | "ts-node": "~5.0.1",
47 | "tslint": "~5.9.1"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/app/accessibility/active-descendant/active-item-option/item-active-option.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, HostBinding, Input} from '@angular/core';
2 | import {Highlightable} from "@angular/cdk/a11y";
3 |
4 | @Component({
5 | selector: 'app-item-active-option',
6 | template: `
7 |
8 |
9 |
10 | `,
11 | styles: [`
12 | .active {
13 | background-color: lightblue;
14 | color: #fff;
15 | }
16 |
17 | .disabled {
18 | opacity: 0.3;
19 | }
20 | `]
21 | })
22 | export class ItemActiveOptionComponent implements Highlightable {
23 | @Input() item;
24 | @Input() disabled = false;
25 | private _isActive = false;
26 |
27 | @HostBinding('class.active') get isActive() {
28 | return this._isActive;
29 | }
30 |
31 | setActiveStyles() {
32 | this._isActive = true;
33 | }
34 |
35 | setInactiveStyles() {
36 | this._isActive = false;
37 | }
38 |
39 | getLabel() {
40 | return this.item.name;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/app/accessibility/active-descendant/cdk-active-descendant.component.html:
--------------------------------------------------------------------------------
1 | ActiveDescendantKeyManager使用
2 |
3 |
4 |
5 |
6 |
7 |
9 | {{user.name}}
10 |
11 |
12 |
13 | Model: {{model}}
--------------------------------------------------------------------------------
/src/app/accessibility/active-descendant/cdk-active-descendant.component.less:
--------------------------------------------------------------------------------
1 | .form-control {
2 | display: block;
3 | width: 100%;
4 | height: calc(2.25rem + 2px);
5 | padding: .375rem .75rem;
6 | font-size: 1rem;
7 | line-height: 1.5;
8 | color: #495057;
9 | background-color: #fff;
10 | background-clip: padding-box;
11 | border: 1px solid #ced4da;
12 | border-radius: .25rem;
13 | transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
14 | }
15 |
16 | .form-control:focus {
17 | color: #495057;
18 | background-color: #fff;
19 | border-color: #80bdff;
20 | outline: 0;
21 | box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
22 | }
23 |
24 |
25 | .list-group-item:first-child {
26 | margin-top: 1rem;
27 | border-top-left-radius: .25rem;
28 | border-top-right-radius: .25rem;
29 | }
30 |
31 | .list-group-item {
32 | position: relative;
33 | display: block;
34 | padding: .75rem 1.25rem;
35 | margin-bottom: -1px;
36 | background-color: #fff;
37 | border: 1px solid rgba(0, 0, 0, .125);
38 | }
39 |
40 | .list-group-item:last-child {
41 | margin-bottom: 0;
42 | border-bottom-right-radius: .25rem;
43 | border-bottom-left-radius: .25rem;
44 | }
45 |
46 | .list-group-item.active {
47 | z-index: 2;
48 | color: #fff;
49 | background-color: #007bff;
50 | border-color: #007bff;
51 | }
--------------------------------------------------------------------------------
/src/app/accessibility/active-descendant/cdk-active-descendant.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, QueryList, ViewChildren} from '@angular/core';
2 | import {ItemActiveOptionComponent} from "./active-item-option/item-active-option.component";
3 | import {ActiveDescendantKeyManager} from "@angular/cdk/a11y";
4 | import {ENTER} from "@angular/cdk/keycodes";
5 |
6 | @Component({
7 | selector: 'app-cdk-active-descendant',
8 | templateUrl: './cdk-active-descendant.component.html',
9 | styleUrls: ['./cdk-active-descendant.component.less']
10 | })
11 | export class CdkActiveDescendantComponent implements AfterViewInit {
12 |
13 | @ViewChildren(ItemActiveOptionComponent) items: QueryList;
14 | users = [
15 | {
16 | "id": "5b902934d965e7501f4e1c6f",
17 | "name": "Caroline Hodges"
18 | },
19 | {
20 | "id": "5b9029348f7eed8b6f5f02db",
21 | "name": "Delores Rivas"
22 | },
23 | {
24 | "id": "5b9029346f48c8407c64d0d5",
25 | "name": "Darlene Franklin"
26 | },
27 | {
28 | "id": "5b9029341eff315fa87f9e21",
29 | "name": "Alfreda Love"
30 | },
31 | {
32 | "id": "5b9029342e8917c6ccdb9865",
33 | "name": "Marcy Ratliff"
34 | },
35 | {
36 | "id": "5b9029349dbb48013460e01f",
37 | "name": "Beulah Nielsen"
38 | },
39 | {
40 | "id": "5b902934f4f1586e5e72d74a",
41 | "name": "Morton Kerr"
42 | },
43 | {
44 | "id": "5b9029347918bb204bf7014e",
45 | "name": "Autumn Tillman"
46 | },
47 | {
48 | "id": "5b902934b86f80e1fc60c626",
49 | "name": "Diane Bennett"
50 | },
51 | {
52 | "id": "5b9029348999f59215020349",
53 | "name": "June Eaton"
54 | }
55 | ];
56 |
57 | private keyManager: ActiveDescendantKeyManager;
58 | model = '';
59 |
60 | ngAfterViewInit() {
61 | this.keyManager = new ActiveDescendantKeyManager(this.items).withWrap()
62 | .withTypeAhead();
63 |
64 | }
65 |
66 | onKeyDown(event) {
67 | if (event.keyCode === ENTER) {
68 | this.model = this.keyManager.activeItem.item.name;
69 | } else {
70 | this.keyManager.onKeydown(event);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/app/accessibility/cdk-accessibility-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkAccessibilityComponent} from './cdk-accessibility.component';
5 |
6 |
7 | const routes: Routes = [
8 | {
9 | path: '',
10 | component: CdkAccessibilityComponent
11 | }
12 | ];
13 |
14 | @NgModule({
15 | imports: [
16 | RouterModule.forChild(routes),
17 | CommonModule
18 | ],
19 | exports: [
20 | RouterModule
21 | ],
22 | providers: []
23 | })
24 | export class CdkAccessibilityRoutingModule { }
25 |
--------------------------------------------------------------------------------
/src/app/accessibility/cdk-accessibility.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/app/accessibility/cdk-accessibility.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/accessibility/cdk-accessibility.component.less
--------------------------------------------------------------------------------
/src/app/accessibility/cdk-accessibility.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-cdk-accessibility',
5 | templateUrl: './cdk-accessibility.component.html',
6 | styleUrls: ['./cdk-accessibility.component.less']
7 | })
8 | export class CdkAccessibilityComponent {
9 | }
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/app/accessibility/cdk-accessibility.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule} from '@angular/router';
4 | import {CdkAccessibilityRoutingModule} from './cdk-accessibility-routing.module';
5 | import {CdkAccessibilityComponent} from './cdk-accessibility.component';
6 | import {ItemActiveOptionComponent} from './active-descendant/active-item-option/item-active-option.component';
7 | import {FilterPipe} from "./filter.pipe";
8 | import {A11yModule} from "@angular/cdk/a11y";
9 | import {CdkActiveDescendantComponent} from './active-descendant/cdk-active-descendant.component';
10 | import {CdkFocusComponent} from './focus/cdk-focus.component';
11 | import {ItemFocusOptionComponent} from './focus/focus-item-option/item-focus-option.component';
12 | import { CdkFocusTrapFactoryComponent } from './focus-trap-factory/cdk-focus-trap-factory.component';
13 | import { CdkFocusMonitorComponent } from './focus-monitor/cdk-focus-monitor.component';
14 | import { CdkInteractivityCheckerComponent } from './interactivity-checker/cdk-interactivity-checker.component';
15 | import { CdkLiveAnnouncerComponent } from './live-announcer/cdk-live-announcer.component';
16 |
17 | @NgModule({
18 | imports: [
19 | CommonModule,
20 | RouterModule,
21 | A11yModule,
22 | CdkAccessibilityRoutingModule
23 | ],
24 | declarations: [
25 | CdkAccessibilityComponent,
26 | ItemActiveOptionComponent,
27 | FilterPipe,
28 | CdkActiveDescendantComponent,
29 | CdkFocusComponent,
30 | ItemFocusOptionComponent,
31 | CdkFocusTrapFactoryComponent,
32 | CdkFocusMonitorComponent,
33 | CdkInteractivityCheckerComponent,
34 | CdkLiveAnnouncerComponent
35 | ]
36 | })
37 | export class CdkAccessibilityModule {
38 | }
39 |
--------------------------------------------------------------------------------
/src/app/accessibility/filter.pipe.ts:
--------------------------------------------------------------------------------
1 | import {Pipe, PipeTransform} from '@angular/core';
2 |
3 | @Pipe({
4 | name: 'filter'
5 | })
6 | export class FilterPipe implements PipeTransform {
7 |
8 | transform(items: any[], field: string, value: string): any[] {
9 | if (!items) {
10 | return [];
11 | }
12 | if (!value || value.length === 0) {
13 | return items;
14 | }
15 | return items.filter(it =>
16 | it[field].toLowerCase().indexOf(value.toLowerCase()) !== -1);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/app/accessibility/focus-monitor/cdk-focus-monitor.component.html:
--------------------------------------------------------------------------------
1 | FocusMonitor使用(监控元素focus状态,以及focus来源是什么)
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/app/accessibility/focus-monitor/cdk-focus-monitor.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/accessibility/focus-monitor/cdk-focus-monitor.component.less
--------------------------------------------------------------------------------
/src/app/accessibility/focus-monitor/cdk-focus-monitor.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, ElementRef, OnDestroy, OnInit, Renderer2} from '@angular/core';
2 | import {FocusMonitor} from "@angular/cdk/a11y";
3 |
4 | @Component({
5 | selector: 'app-cdk-focus-monitor',
6 | templateUrl: './cdk-focus-monitor.component.html',
7 | styleUrls: ['./cdk-focus-monitor.component.less']
8 | })
9 | export class CdkFocusMonitorComponent implements AfterViewInit, OnDestroy {
10 |
11 | constructor(private _elementRef: ElementRef,
12 | private _focusMonitor: FocusMonitor) {
13 | }
14 |
15 | ngAfterViewInit() {
16 | this._focusMonitor.monitor(this._elementRef.nativeElement, true).subscribe(mode => {
17 | console.log('元素获取到焦点 focused 来源 ' + mode);
18 | });
19 | }
20 |
21 | ngOnDestroy() {
22 | this._focusMonitor.stopMonitoring(this._elementRef.nativeElement);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/accessibility/focus-trap-factory/cdk-focus-trap-factory.component.html:
--------------------------------------------------------------------------------
1 | FocusTrapFactory使用(给元素添加cdkFocusTrap指令)
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/app/accessibility/focus-trap-factory/cdk-focus-trap-factory.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/accessibility/focus-trap-factory/cdk-focus-trap-factory.component.less
--------------------------------------------------------------------------------
/src/app/accessibility/focus-trap-factory/cdk-focus-trap-factory.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, ElementRef} from '@angular/core';
2 | import {FocusTrap, FocusTrapFactory} from "@angular/cdk/a11y";
3 |
4 | @Component({
5 | selector: 'app-cdk-focus-trap-factory',
6 | templateUrl: './cdk-focus-trap-factory.component.html',
7 | styleUrls: ['./cdk-focus-trap-factory.component.less']
8 | })
9 | export class CdkFocusTrapFactoryComponent implements AfterViewInit {
10 |
11 | private _focusTrap: FocusTrap;
12 |
13 | constructor(private _elementRef: ElementRef,
14 | private _focusTrapFactory: FocusTrapFactory) {
15 | }
16 |
17 | ngAfterViewInit() {
18 | this._focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/app/accessibility/focus/cdk-focus.component.html:
--------------------------------------------------------------------------------
1 | FocusKeyManager使用
2 |
3 |
4 |
7 | {{user.name}}
8 |
9 |
--------------------------------------------------------------------------------
/src/app/accessibility/focus/cdk-focus.component.less:
--------------------------------------------------------------------------------
1 | .form-control {
2 | display: block;
3 | width: 100%;
4 | height: calc(2.25rem + 2px);
5 | padding: .375rem .75rem;
6 | font-size: 1rem;
7 | line-height: 1.5;
8 | color: #495057;
9 | background-color: #fff;
10 | background-clip: padding-box;
11 | border: 1px solid #ced4da;
12 | border-radius: .25rem;
13 | transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
14 | }
15 |
16 | .form-control:focus {
17 | color: #495057;
18 | background-color: #fff;
19 | border-color: #80bdff;
20 | outline: 0;
21 | box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
22 | }
23 |
24 |
25 | .list-group-item:first-child {
26 | margin-top: 1rem;
27 | border-top-left-radius: .25rem;
28 | border-top-right-radius: .25rem;
29 | }
30 |
31 | .list-group-item {
32 | position: relative;
33 | display: block;
34 | padding: .75rem 1.25rem;
35 | margin-bottom: -1px;
36 | background-color: #fff;
37 | border: 1px solid rgba(0, 0, 0, .125);
38 | }
39 |
40 | .list-group-item:last-child {
41 | margin-bottom: 0;
42 | border-bottom-right-radius: .25rem;
43 | border-bottom-left-radius: .25rem;
44 | }
45 |
46 | .list-group-item.focus {
47 | z-index: 2;
48 | color: #fff;
49 | background-color: #007bff;
50 | border-color: #007bff;
51 | }
--------------------------------------------------------------------------------
/src/app/accessibility/focus/cdk-focus.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, QueryList, ViewChildren} from '@angular/core';
2 | import {FocusKeyManager} from "@angular/cdk/a11y";
3 | import {ItemFocusOptionComponent} from "./focus-item-option/item-focus-option.component";
4 |
5 | @Component({
6 | selector: 'app-cdk-focus',
7 | templateUrl: './cdk-focus.component.html',
8 | styleUrls: ['./cdk-focus.component.less']
9 | })
10 | export class CdkFocusComponent implements AfterViewInit {
11 |
12 | @ViewChildren(ItemFocusOptionComponent) items: QueryList;
13 | users = [
14 | {
15 | "id": "5b902934d965e7501f4e1c6f",
16 | "name": "Caroline Hodges"
17 | },
18 | {
19 | "id": "5b9029348f7eed8b6f5f02db",
20 | "name": "Delores Rivas"
21 | },
22 | {
23 | "id": "5b9029346f48c8407c64d0d5",
24 | "name": "Darlene Franklin"
25 | },
26 | {
27 | "id": "5b9029341eff315fa87f9e21",
28 | "name": "Alfreda Love"
29 | },
30 | {
31 | "id": "5b9029342e8917c6ccdb9865",
32 | "name": "Marcy Ratliff"
33 | },
34 | {
35 | "id": "5b9029349dbb48013460e01f",
36 | "name": "Beulah Nielsen"
37 | },
38 | {
39 | "id": "5b902934f4f1586e5e72d74a",
40 | "name": "Morton Kerr"
41 | },
42 | {
43 | "id": "5b9029347918bb204bf7014e",
44 | "name": "Autumn Tillman"
45 | },
46 | {
47 | "id": "5b902934b86f80e1fc60c626",
48 | "name": "Diane Bennett"
49 | },
50 | {
51 | "id": "5b9029348999f59215020349",
52 | "name": "June Eaton"
53 | }
54 | ];
55 |
56 | private keyManager: FocusKeyManager;
57 |
58 | ngAfterViewInit() {
59 | this.keyManager = new FocusKeyManager(this.items).withWrap()
60 | .withTypeAhead();
61 |
62 | }
63 |
64 | onKeyDown(event) {
65 | this.keyManager.onKeydown(event);
66 | }
67 |
68 | selectItem(index: number) {
69 | this.keyManager.setActiveItem(index);
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/app/accessibility/focus/focus-item-option/item-focus-option.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ElementRef, HostBinding, Input} from '@angular/core';
2 | import {FocusableOption, FocusOrigin} from "@angular/cdk/a11y";
3 |
4 | @Component({
5 | selector: 'app-item-focus-option',
6 | template: `
7 |
8 | `,
9 | styles: [
10 | `:host:focus {
11 | background: lightblue;
12 | color: #fff;
13 | }`
14 | ]
15 | })
16 |
17 | export class ItemFocusOptionComponent implements FocusableOption {
18 | @Input() item;
19 |
20 | /**
21 | * 屏蔽掉默认的键盘事件,js里面自己控制键盘事件
22 | */
23 | @HostBinding('tabindex') tabindex = '-1';
24 |
25 | constructor(private host: ElementRef) {
26 | }
27 |
28 | getLabel() {
29 | return this.item.name;
30 | }
31 |
32 | focus(origin?: FocusOrigin): void {
33 | this.host.nativeElement.focus();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/app/accessibility/interactivity-checker/cdk-interactivity-checker.component.html:
--------------------------------------------------------------------------------
1 | InteractivityChecker使用
2 |
3 | 上面button是否disable: {{disable}}
4 | 上面button是否visible: {{visible}}
5 | 上面button是否可以tabable: {{tabable}}
6 | 上面button是否可以focusable: {{focusable}}
7 |
--------------------------------------------------------------------------------
/src/app/accessibility/interactivity-checker/cdk-interactivity-checker.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/accessibility/interactivity-checker/cdk-interactivity-checker.component.less
--------------------------------------------------------------------------------
/src/app/accessibility/interactivity-checker/cdk-interactivity-checker.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
2 | import {InteractivityChecker} from "@angular/cdk/a11y";
3 |
4 | @Component({
5 | selector: 'app-cdk-interactivity-checker',
6 | templateUrl: './cdk-interactivity-checker.component.html',
7 | styleUrls: ['./cdk-interactivity-checker.component.less']
8 | })
9 | export class CdkInteractivityCheckerComponent implements OnInit {
10 |
11 | @ViewChild('interactivityCheckerButton') button: ElementRef;
12 | disable: boolean;
13 | visible: boolean;
14 | tabable: boolean;
15 | focusable: boolean;
16 |
17 | constructor(private _interactivityChecker: InteractivityChecker) {
18 | }
19 |
20 | ngOnInit() {
21 | this.disable = this._interactivityChecker.isDisabled(this.button.nativeElement);
22 | this.visible = this._interactivityChecker.isVisible(this.button.nativeElement);
23 | this.tabable = this._interactivityChecker.isTabbable(this.button.nativeElement);
24 | this.focusable = this._interactivityChecker.isFocusable(this.button.nativeElement);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/app/accessibility/live-announcer/cdk-live-announcer.component.html:
--------------------------------------------------------------------------------
1 | LiveAnnouncer使用(在body上append一个内容,一般在做html aria的时候用到)
--------------------------------------------------------------------------------
/src/app/accessibility/live-announcer/cdk-live-announcer.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/accessibility/live-announcer/cdk-live-announcer.component.less
--------------------------------------------------------------------------------
/src/app/accessibility/live-announcer/cdk-live-announcer.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 | import {LiveAnnouncer} from "@angular/cdk/a11y";
3 |
4 | @Component({
5 | selector: 'app-cdk-live-announcer',
6 | templateUrl: './cdk-live-announcer.component.html',
7 | styleUrls: ['./cdk-live-announcer.component.less']
8 | })
9 | export class CdkLiveAnnouncerComponent {
10 |
11 | index = 1;
12 |
13 | constructor(private liveAnnouncer: LiveAnnouncer) {
14 | liveAnnouncer.announce("Hey Google");
15 | setTimeout(() => {
16 | this.timerTask();
17 | }, 3000);
18 | }
19 |
20 | timerTask() {
21 | this.index = this.index + 1;
22 | this.liveAnnouncer.announce("Hey Google " + this.index.toString(), "assertive");
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkCoercionModule} from './coercion/cdk-coercion.module';
4 | import {RouterModule, Routes} from '@angular/router';
5 | import {CdkLayoutModule} from './layout/cdk-layout.module';
6 | import {CdkKeyCodesModule} from './keycodes/cdk-key-codes.module';
7 | import {CdkAccessibilityModule} from './accessibility/cdk-accessibility.module';
8 | import {CdkBidiModule} from './bidi/cdk-bidi.module';
9 | import {CdkScrollingModule} from './scrolling/cdk-scrolling.module';
10 | import {CdkLPortalModule} from './portal/cdk-portal.module';
11 | import {CdkOverlayModule} from './overlay/cdk-overlay.module';
12 | import {TipComponent} from './tip/tip.component';
13 | import {CdkPlatformModule} from './platform/cdk-platform.module';
14 | import {CdkObserversModule} from './observers/cdk-observers.module';
15 | import {CdkDragDropModule} from './drag-drop/cdk-drag-drop.module';
16 | import {CdkTextFieldModule} from "./text-field/cdk-text-field.module";
17 | import {CdkWorkflowStepperModule} from "./workflow-stepper/cdk-workflow-stepper.module";
18 | import {CdkBaseTableModule} from './table/cdk-base-table.module';
19 |
20 | const appRoutes: Routes = [
21 | {
22 | path: 'coercion',
23 | loadChildren: () => CdkCoercionModule
24 | }, {
25 | path: 'layout',
26 | loadChildren: () => CdkLayoutModule
27 | }, {
28 | path: 'keycodes',
29 | loadChildren: () => CdkKeyCodesModule
30 | }, {
31 | path: 'accessibility',
32 | loadChildren: () => CdkAccessibilityModule
33 | }, {
34 | path: 'bidi',
35 | loadChildren: () => CdkBidiModule
36 | }, {
37 | path: 'scrolling',
38 | loadChildren: () => CdkScrollingModule
39 | }, {
40 | path: 'portal',
41 | loadChildren: () => CdkLPortalModule
42 | }, {
43 | path: 'overlay',
44 | loadChildren: () => CdkOverlayModule
45 | }, {
46 | path: 'platform',
47 | loadChildren: () => CdkPlatformModule
48 | }, {
49 | path: 'observers',
50 | loadChildren: () => CdkObserversModule
51 | }, {
52 | path: 'dragDrop',
53 | loadChildren: () => CdkDragDropModule
54 | }, {
55 | path: 'stepper',
56 | loadChildren: () => CdkWorkflowStepperModule
57 | }, {
58 | path: 'table',
59 | loadChildren: () => CdkBaseTableModule
60 | }, {
61 | path: 'textField',
62 | loadChildren: () => CdkTextFieldModule
63 | }, {
64 | path: 'tip',
65 | component: TipComponent
66 | }, {
67 | path: '',
68 | redirectTo: '/coercion',
69 | pathMatch: 'full'
70 | },
71 | ];
72 |
73 | @NgModule({
74 | imports: [
75 | RouterModule.forRoot(appRoutes),
76 | CommonModule
77 | ],
78 | exports: [
79 | RouterModule
80 | ],
81 | providers: []
82 | })
83 | export class AppRoutingModule {
84 | }
85 |
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 | @angular/cdk 内容学习
2 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/app/app.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/app.component.less
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.less']
7 | })
8 | export class AppComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import {BrowserModule} from '@angular/platform-browser';
2 | import {NgModule} from '@angular/core';
3 |
4 | import {AppComponent} from './app.component';
5 | import {CdkLayoutModule} from './layout/cdk-layout.module';
6 | import {CdkCoercionModule} from './coercion/cdk-coercion.module';
7 | import {AppRoutingModule} from './app-routing.module';
8 | import {FormsModule} from '@angular/forms';
9 | import {RouterModule} from '@angular/router';
10 | import {CdkKeyCodesModule} from './keycodes/cdk-key-codes.module';
11 | import {CdkOverlayModule} from './overlay/cdk-overlay.module';
12 | import {CdkScrollingModule} from './scrolling/cdk-scrolling.module';
13 | import {TipDirective} from './tip/tip.directive';
14 | import {TipComponent} from './tip/tip.component';
15 | import {CdkPlatformModule} from './platform/cdk-platform.module';
16 | import {CdkObserversModule} from './observers/cdk-observers.module';
17 | import {CdkDragDropModule} from './drag-drop/cdk-drag-drop.module';
18 | import {CdkTextFieldModule} from "./text-field/cdk-text-field.module";
19 | import {CdkWorkflowStepperModule} from "./workflow-stepper/cdk-workflow-stepper.module";
20 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
21 | import {FullscreenOverlayContainer, OverlayContainer} from '@angular/cdk/overlay';
22 | import {CdkBaseTableModule} from './table/cdk-base-table.module';
23 |
24 | @NgModule({
25 | declarations: [
26 | AppComponent,
27 | TipDirective,
28 | TipComponent
29 | ],
30 | imports: [
31 | RouterModule,
32 | FormsModule,
33 | BrowserModule,
34 | BrowserAnimationsModule,
35 | CdkCoercionModule,
36 | CdkLayoutModule,
37 | CdkKeyCodesModule,
38 | CdkScrollingModule,
39 | CdkOverlayModule,
40 | CdkPlatformModule,
41 | CdkObserversModule,
42 | CdkDragDropModule,
43 | CdkTextFieldModule,
44 | CdkWorkflowStepperModule,
45 | CdkBaseTableModule,
46 | AppRoutingModule
47 | ],
48 | providers: [
49 | {provide: OverlayContainer, useClass: FullscreenOverlayContainer},
50 |
51 | ],
52 | bootstrap: [AppComponent]
53 | })
54 | export class AppModule {
55 | }
56 |
--------------------------------------------------------------------------------
/src/app/bidi/cdk-bidi-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkBidiComponent} from './cdk-bidi.component';
5 |
6 |
7 | const routes: Routes = [
8 | {
9 | path: '',
10 | component: CdkBidiComponent
11 | }
12 | ];
13 |
14 | @NgModule({
15 | imports: [
16 | RouterModule.forChild(routes),
17 | CommonModule
18 | ],
19 | exports: [
20 | RouterModule
21 | ],
22 | providers: []
23 | })
24 | export class CdkBidiRoutingModule {
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/bidi/cdk-bidi.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 从左到右排列
4 |
5 |
6 |
7 | 从右到左排列
8 |
9 |
10 |
11 |
第一个位置--内容靠左
13 |
14 |
第二个位置--内容靠右
16 |
17 |
18 |
19 |
20 |
21 | 可以动态切换方向
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/app/bidi/cdk-bidi.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/bidi/cdk-bidi.component.less
--------------------------------------------------------------------------------
/src/app/bidi/cdk-bidi.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, Inject, OnDestroy, OnInit} from '@angular/core';
2 | import {DIR_DOCUMENT, Directionality} from '@angular/cdk/bidi';
3 | import {Subscription} from "rxjs";
4 |
5 | @Component({
6 | selector: 'app-cdk-bidi',
7 | templateUrl: './cdk-bidi.component.html',
8 | styleUrls: ['./cdk-bidi.component.less']
9 | })
10 | export class CdkBidiComponent implements OnInit, OnDestroy {
11 | dir = "rtl";
12 | /** Subscription to the Directionality change EventEmitter. */
13 | private _dirChangeSubscription = Subscription.EMPTY;
14 |
15 | constructor(
16 | @Inject(DIR_DOCUMENT) public dirDoc: any,
17 | public directionality: Directionality
18 | ) {
19 | this._dirChangeSubscription = directionality.change.subscribe(() => {
20 | });
21 | }
22 |
23 | ngOnInit() {
24 | // 获取document
25 | console.log(this.dirDoc);
26 | // ltr 获取当前值
27 | const dir = this.directionality.value;
28 | console.log("dir is ", dir);
29 | }
30 |
31 | ngOnDestroy() {
32 | this._dirChangeSubscription.unsubscribe();
33 | }
34 |
35 | switchDir() {
36 | if (this.dir === "rtl") {
37 | this.dir = "ltr";
38 | } else {
39 | this.dir = "rtl";
40 | }
41 | }
42 |
43 | dirChange() {
44 | console.log('aaa');
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/app/bidi/cdk-bidi.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule} from '@angular/router';
4 | import {CdkBidiRoutingModule} from './cdk-bidi-routing.module';
5 | import {CdkBidiComponent} from './cdk-bidi.component';
6 | import {BidiModule} from "@angular/cdk/bidi";
7 |
8 | @NgModule({
9 | imports: [
10 | CommonModule,
11 | RouterModule,
12 | BidiModule,
13 | CdkBidiRoutingModule
14 | ],
15 | declarations: [
16 | CdkBidiComponent
17 | ]
18 | })
19 | export class CdkBidiModule {
20 | }
21 |
--------------------------------------------------------------------------------
/src/app/coercion/cdk-coercion-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkCoercionComponent} from './cdk-coercion.component';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: CdkCoercionComponent
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [
15 | RouterModule.forChild(routes),
16 | CommonModule
17 | ],
18 | exports: [
19 | RouterModule
20 | ],
21 | providers: []
22 | })
23 | export class CdkCoercionRoutingModule { }
24 |
--------------------------------------------------------------------------------
/src/app/coercion/cdk-coercion.component.html:
--------------------------------------------------------------------------------
1 | coercion cdk 里面常用转换工具类
2 | 转boolean: coerceBooleanProperty
3 | 转number: coerceNumberProperty
4 | 是否是number: _isNumberValue
5 | 转换为数组: coerceArray
6 | 转CSS像素: coerceCssPixelValue
7 |
--------------------------------------------------------------------------------
/src/app/coercion/cdk-coercion.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/coercion/cdk-coercion.component.less
--------------------------------------------------------------------------------
/src/app/coercion/cdk-coercion.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit} from '@angular/core';
2 | import {
3 | _isNumberValue,
4 | coerceArray,
5 | coerceBooleanProperty,
6 | coerceCssPixelValue,
7 | coerceNumberProperty
8 | } from "@angular/cdk/coercion";
9 |
10 | @Component({
11 | selector: 'app-cdk-coercion',
12 | templateUrl: './cdk-coercion.component.html',
13 | styleUrls: ['./cdk-coercion.component.less']
14 | })
15 | export class CdkCoercionComponent implements OnInit {
16 |
17 | constructor() {
18 | }
19 |
20 | ngOnInit() {
21 | // 转boolean
22 | console.log("转boolean: " + coerceBooleanProperty('false'));
23 | // 转number
24 | console.log("转number: " + coerceNumberProperty(10.5));
25 | console.log("是否是number类型: " + coerceNumberProperty('a', this.coerceNumberFallback()));
26 | console.log("是否是number类型: " + _isNumberValue('a'));
27 | // 转数组
28 | console.log("转换为数组: " + coerceArray(1204));
29 | // 转CSS pixel value
30 | console.log("转CSS像素: " + coerceCssPixelValue('10'));
31 | }
32 |
33 | /**
34 | * 当转number的时候发生了错误时候的返回值
35 | */
36 | coerceNumberFallback() {
37 | return 10;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/app/coercion/cdk-coercion.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkCoercionComponent} from './cdk-coercion.component';
4 | import {CdkCoercionRoutingModule} from './cdk-coercion-routing.module';
5 | import {RouterModule} from '@angular/router';
6 |
7 | @NgModule({
8 | imports: [
9 | CommonModule,
10 | RouterModule,
11 | CdkCoercionRoutingModule
12 | ],
13 | declarations: [
14 | CdkCoercionComponent
15 | ]
16 | })
17 | export class CdkCoercionModule {
18 | }
19 |
--------------------------------------------------------------------------------
/src/app/drag-drop/cdk-drag-drop-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkDragDropComponent} from './cdk-drag-drop.component';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: CdkDragDropComponent
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [
15 | RouterModule.forChild(routes),
16 | CommonModule
17 | ],
18 | exports: [
19 | RouterModule
20 | ],
21 | providers: []
22 | })
23 | export class CdkDragDropRoutingModule { }
24 |
--------------------------------------------------------------------------------
/src/app/drag-drop/cdk-drag-drop.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/app/drag-drop/cdk-drag-drop.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/drag-drop/cdk-drag-drop.component.less
--------------------------------------------------------------------------------
/src/app/drag-drop/cdk-drag-drop.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-cdk-drag-drop',
5 | templateUrl: './cdk-drag-drop.component.html',
6 | styleUrls: ['./cdk-drag-drop.component.less']
7 | })
8 | export class CdkDragDropComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/app/drag-drop/cdk-drag-drop.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkDragDropComponent} from './cdk-drag-drop.component';
4 | import {CdkDragDropRoutingModule} from './cdk-drag-drop-routing.module';
5 | import {DragDropModule} from '@angular/cdk/drag-drop';
6 | import {RouterModule} from '@angular/router';
7 | import {DragDropDropListComponent} from './drop-list-directive/drag-drop-drop-list.component';
8 | import {DragDropDropComponent} from './drop-directive/drag-drop-drop.component';
9 | import {DragDropTransferringItemComponent} from './transferring-item/drag-drop-transferring-item.component';
10 | import {DragDropHandleDragAreaComponent} from './handle-drag-area/drag-drop-handle-drag-area.component';
11 | import {DragDropCustomizingDragPreviewComponent} from './customizing-drag-preview/drag-drop-customizing-drag-preview.component';
12 | import {DragDropCustomizingDragPlaceHolderComponent} from './customizing-drag-place-holder/drag-drop-customizing-drag-place-holder.component';
13 | import {DragDropOrientationDragComponent} from './orientation-drag/drag-drop-orientation-drag.component';
14 | import {DragDropRestrictingMoveAreaComponent} from './restricting-move-area/drag-drop-restricting-move-area.component';
15 | import {DragDropDragDialogComponent} from './drag-dialog/drag-drop-drag-dialog.component';
16 | import { DragDropControllingWithItemComponent } from './controlling-with-item/drag-drop-controlling-with-item.component';
17 | import { DragDropDisableDragComponent } from './disable-drag/drag-drop-disable-drag.component';
18 |
19 | @NgModule({
20 | imports: [
21 | CommonModule,
22 | RouterModule,
23 | DragDropModule,
24 | CdkDragDropRoutingModule
25 | ],
26 | declarations: [
27 | CdkDragDropComponent,
28 | DragDropDropListComponent,
29 | DragDropDropComponent,
30 | DragDropTransferringItemComponent,
31 | DragDropHandleDragAreaComponent,
32 | DragDropCustomizingDragPreviewComponent,
33 | DragDropCustomizingDragPlaceHolderComponent,
34 | DragDropOrientationDragComponent,
35 | DragDropRestrictingMoveAreaComponent,
36 | DragDropDragDialogComponent,
37 | DragDropControllingWithItemComponent,
38 | DragDropDisableDragComponent
39 | ]
40 | })
41 | export class CdkDragDropModule {
42 | }
43 |
--------------------------------------------------------------------------------
/src/app/drag-drop/controlling-with-item/drag-drop-controlling-with-item.component.html:
--------------------------------------------------------------------------------
1 | controlling with item
2 |
3 |
Available numbers
4 |
5 |
13 |
18 | {{number}}
19 |
20 |
21 |
22 |
23 |
24 |
Even numbers
25 |
26 |
34 |
{{number}}
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/app/drag-drop/controlling-with-item/drag-drop-controlling-with-item.component.less:
--------------------------------------------------------------------------------
1 | .example-container {
2 | width: 400px;
3 | max-width: 100%;
4 | margin: 0 25px 25px 0;
5 | display: inline-block;
6 | vertical-align: top;
7 | }
8 |
9 | .example-list {
10 | border: solid 1px #ccc;
11 | min-height: 60px;
12 | background: white;
13 | border-radius: 4px;
14 | overflow: hidden;
15 | display: block;
16 | }
17 |
18 | .example-box {
19 | padding: 20px 10px;
20 | border-bottom: solid 1px #ccc;
21 | color: rgba(0, 0, 0, 0.87);
22 | display: flex;
23 | flex-direction: row;
24 | align-items: center;
25 | justify-content: space-between;
26 | box-sizing: border-box;
27 | cursor: move;
28 | background: white;
29 | font-size: 14px;
30 | }
31 |
32 | .cdk-drag-preview {
33 | box-sizing: border-box;
34 | border-radius: 4px;
35 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
36 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
37 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
38 | }
39 |
40 | .cdk-drag-placeholder {
41 | opacity: 0;
42 | }
43 |
44 | .cdk-drag-animating {
45 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
46 | }
47 |
48 | .example-box:last-child {
49 | border: none;
50 | }
51 |
52 | .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
53 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
54 | }
55 |
--------------------------------------------------------------------------------
/src/app/drag-drop/controlling-with-item/drag-drop-controlling-with-item.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 | import {CdkDrag, CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
3 |
4 | @Component({
5 | selector: 'app-drag-drop-controlling-with-item',
6 | templateUrl: './drag-drop-controlling-with-item.component.html',
7 | styleUrls: ['./drag-drop-controlling-with-item.component.less']
8 | })
9 | export class DragDropControllingWithItemComponent {
10 |
11 | all = [1, 2, 3, 4, 5, 6, 7, 8, 9];
12 | even = [10];
13 |
14 | drop(event: CdkDragDrop) {
15 | if (event.previousContainer === event.container) {
16 | moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
17 | } else {
18 | transferArrayItem(event.previousContainer.data,
19 | event.container.data,
20 | event.previousIndex,
21 | event.currentIndex);
22 | }
23 | }
24 |
25 | /** Predicate function that only allows even numbers to be dropped into a list. */
26 | evenPredicate(item: CdkDrag) {
27 | return item.data % 2 === 0;
28 | }
29 |
30 | /** Predicate function that doesn't allow items to be dropped into a list. */
31 | noReturnPredicate() {
32 | return false;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/app/drag-drop/customizing-drag-place-holder/drag-drop-customizing-drag-place-holder.component.html:
--------------------------------------------------------------------------------
1 | customizing drag place holder
2 |
--------------------------------------------------------------------------------
/src/app/drag-drop/customizing-drag-place-holder/drag-drop-customizing-drag-place-holder.component.less:
--------------------------------------------------------------------------------
1 | .example-list {
2 | width: 500px;
3 | max-width: 100%;
4 | border: solid 1px #ccc;
5 | min-height: 60px;
6 | display: block;
7 | background: white;
8 | border-radius: 4px;
9 | overflow: hidden;
10 | }
11 |
12 | .example-box {
13 | padding: 20px 10px;
14 | border-bottom: solid 1px #ccc;
15 | color: rgba(0, 0, 0, 0.87);
16 | display: flex;
17 | flex-direction: row;
18 | align-items: center;
19 | justify-content: space-between;
20 | box-sizing: border-box;
21 | cursor: move;
22 | background: white;
23 | font-size: 14px;
24 | }
25 |
26 | .cdk-drag-preview {
27 | box-sizing: border-box;
28 | border-radius: 4px;
29 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
30 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
31 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
32 | }
33 |
34 | .cdk-drag-animating {
35 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
36 | }
37 |
38 | .example-box:last-child {
39 | border: none;
40 | }
41 |
42 | .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
43 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
44 | }
45 |
46 | .example-custom-placeholder {
47 | background: #ccc;
48 | border: dotted 3px #999;
49 | min-height: 60px;
50 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
51 | }
52 |
--------------------------------------------------------------------------------
/src/app/drag-drop/customizing-drag-place-holder/drag-drop-customizing-drag-place-holder.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit} from '@angular/core';
2 | import {CdkDragDrop, moveItemInArray} from "@angular/cdk/drag-drop";
3 |
4 | @Component({
5 | selector: 'app-drag-drop-customizing-drag-place-holder',
6 | templateUrl: './drag-drop-customizing-drag-place-holder.component.html',
7 | styleUrls: ['./drag-drop-customizing-drag-place-holder.component.less']
8 | })
9 | export class DragDropCustomizingDragPlaceHolderComponent {
10 |
11 | movies = [
12 | 'Episode I - The Phantom Menace',
13 | 'Episode II - Attack of the Clones',
14 | 'Episode III - Revenge of the Sith',
15 | 'Episode IV - A New Hope',
16 | 'Episode V - The Empire Strikes Back',
17 | 'Episode VI - Return of the Jedi',
18 | 'Episode VII - The Force Awakens',
19 | 'Episode VIII - The Last Jedi'
20 | ];
21 |
22 | drop(event: CdkDragDrop) {
23 | moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/drag-drop/customizing-drag-preview/drag-drop-customizing-drag-preview.component.html:
--------------------------------------------------------------------------------
1 | customizing drag preview
2 |
3 |
4 | {{movie.title}}
5 |
![]()
6 |
7 |
--------------------------------------------------------------------------------
/src/app/drag-drop/customizing-drag-preview/drag-drop-customizing-drag-preview.component.less:
--------------------------------------------------------------------------------
1 | .example-list {
2 | width: 500px;
3 | max-width: 100%;
4 | border: solid 1px #ccc;
5 | min-height: 60px;
6 | display: block;
7 | background: white;
8 | border-radius: 4px;
9 | overflow: hidden;
10 | }
11 |
12 | .example-box {
13 | padding: 20px 10px;
14 | border-bottom: solid 1px #ccc;
15 | color: rgba(0, 0, 0, 0.87);
16 | display: flex;
17 | flex-direction: row;
18 | align-items: center;
19 | justify-content: space-between;
20 | box-sizing: border-box;
21 | cursor: move;
22 | background: white;
23 | font-size: 14px;
24 | }
25 |
26 | .cdk-drag-preview {
27 | box-sizing: border-box;
28 | border-radius: 4px;
29 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
30 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
31 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
32 | }
33 |
34 | .cdk-drag-placeholder {
35 | opacity: 0;
36 | }
37 |
38 | .cdk-drag-animating {
39 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
40 | }
41 |
42 | .example-box:last-child {
43 | border: none;
44 | }
45 |
46 | .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
47 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
48 | }
49 |
--------------------------------------------------------------------------------
/src/app/drag-drop/customizing-drag-preview/drag-drop-customizing-drag-preview.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit} from '@angular/core';
2 | import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop';
3 |
4 | @Component({
5 | selector: 'app-drag-drop-customizing-drag-preview',
6 | templateUrl: './drag-drop-customizing-drag-preview.component.html',
7 | styleUrls: ['./drag-drop-customizing-drag-preview.component.less']
8 | })
9 | export class DragDropCustomizingDragPreviewComponent {
10 |
11 | movies = [
12 | {
13 | title: 'Episode I - The Phantom Menace',
14 | poster: 'https://upload.wikimedia.org/wikipedia/en/4/40/Star_Wars_Phantom_Menace_poster.jpg'
15 | },
16 | {
17 | title: 'Episode II - Attack of the Clones',
18 | poster: 'https://upload.wikimedia.org/wikipedia/en/3/32/Star_Wars_-_Episode_II_Attack_of_the_Clones_%28movie_poster%29.jpg'
19 | },
20 | {
21 | title: 'Episode III - Revenge of the Sith',
22 | poster: 'https://upload.wikimedia.org/wikipedia/en/9/93/Star_Wars_Episode_III_Revenge_of_the_Sith_poster.jpg'
23 | },
24 | {
25 | title: 'Episode IV - A New Hope',
26 | poster: 'https://upload.wikimedia.org/wikipedia/en/8/87/StarWarsMoviePoster1977.jpg'
27 | },
28 | {
29 | title: 'Episode V - The Empire Strikes Back',
30 | poster: 'https://upload.wikimedia.org/wikipedia/en/3/3c/SW_-_Empire_Strikes_Back.jpg'
31 | },
32 | {
33 | title: 'Episode VI - Return of the Jedi',
34 | poster: 'https://upload.wikimedia.org/wikipedia/en/b/b2/ReturnOfTheJediPoster1983.jpg'
35 | },
36 | {
37 | title: 'Episode VII - The Force Awakens',
38 | poster: 'https://upload.wikimedia.org/wikipedia/en/a/a2/Star_Wars_The_Force_Awakens_Theatrical_Poster.jpg'
39 | },
40 | {
41 | title: 'Episode VIII - The Last Jedi',
42 | poster: 'https://upload.wikimedia.org/wikipedia/en/7/7f/Star_Wars_The_Last_Jedi.jpg'
43 | }
44 | ];
45 |
46 | // tslint:enable:max-line-length
47 |
48 | drop(event: CdkDragDrop<{ title: string, poster: string }[]>) {
49 | moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/app/drag-drop/disable-drag/drag-drop-disable-drag.component.html:
--------------------------------------------------------------------------------
1 | disable drag
2 |
3 |
4 |
5 |
6 | {{item.value}}
10 | {{item.value}}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/app/drag-drop/disable-drag/drag-drop-disable-drag.component.less:
--------------------------------------------------------------------------------
1 | .example-list {
2 | width: 500px;
3 | max-width: 100%;
4 | border: solid 1px #ccc;
5 | min-height: 60px;
6 | display: block;
7 | background: white;
8 | border-radius: 4px;
9 | overflow: hidden;
10 | }
11 |
12 | .example-box {
13 | padding: 20px 10px;
14 | border-bottom: solid 1px #ccc;
15 | color: rgba(0, 0, 0, 0.87);
16 | display: flex;
17 | flex-direction: row;
18 | align-items: center;
19 | justify-content: space-between;
20 | box-sizing: border-box;
21 | cursor: move;
22 | background: white;
23 | font-size: 14px;
24 | }
25 |
26 | .cdk-drag-preview {
27 | box-sizing: border-box;
28 | border-radius: 4px;
29 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
30 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
31 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
32 | }
33 |
34 | .cdk-drag-placeholder {
35 | opacity: 0;
36 | }
37 |
38 | .cdk-drag-animating {
39 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
40 | }
41 |
42 | .example-box:last-child {
43 | border: none;
44 | }
45 |
46 | .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
47 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
48 | }
49 |
--------------------------------------------------------------------------------
/src/app/drag-drop/disable-drag/drag-drop-disable-drag.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 | import {CdkDragDrop, moveItemInArray} from "@angular/cdk/drag-drop";
3 |
4 | @Component({
5 | selector: 'app-drag-drop-disable-drag',
6 | templateUrl: './drag-drop-disable-drag.component.html',
7 | styleUrls: ['./drag-drop-disable-drag.component.less']
8 | })
9 | export class DragDropDisableDragComponent {
10 |
11 | items = [
12 | {value: 'I can be dragged', disabled: false},
13 | {value: 'I cannot be dragged', disabled: true},
14 | {value: 'I can also be dragged', disabled: false}
15 | ];
16 |
17 | drop(event: CdkDragDrop) {
18 | moveItemInArray(this.items, event.previousIndex, event.currentIndex);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drag-dialog/drag-drop-drag-dialog.component.html:
--------------------------------------------------------------------------------
1 | drag dialog
2 |
3 |
4 |
5 |
6 | Drag the dialog around!
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drag-dialog/drag-drop-drag-dialog.component.less:
--------------------------------------------------------------------------------
1 | .example-dialog-content {
2 | width: 200px;
3 | height: 200px;
4 | border: solid 1px #ccc;
5 | color: rgba(0, 0, 0, 0.87);
6 | cursor: move;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | background: #fff;
11 | border-radius: 4px;
12 | transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
13 | box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
14 | 0 2px 2px 0 rgba(0, 0, 0, 0.14),
15 | 0 1px 5px 0 rgba(0, 0, 0, 0.12);
16 | }
17 |
18 | .example-dialog-content:active {
19 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
20 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
21 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
22 | }
23 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drag-dialog/drag-drop-drag-dialog.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, OnDestroy, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
2 | import {Overlay, OverlayRef} from '@angular/cdk/overlay';
3 | import {TemplatePortal} from '@angular/cdk/portal';
4 |
5 | @Component({
6 | selector: 'app-drag-drop-drag-dialog',
7 | templateUrl: './drag-drop-drag-dialog.component.html',
8 | styleUrls: ['./drag-drop-drag-dialog.component.less']
9 | })
10 | export class DragDropDragDialogComponent implements AfterViewInit, OnDestroy {
11 | @ViewChild(TemplateRef) _dialogTemplate: TemplateRef;
12 | private _overlayRef: OverlayRef;
13 | private _portal: TemplatePortal;
14 |
15 | constructor(private _overlay: Overlay, private _viewContainerRef: ViewContainerRef) {}
16 |
17 | ngAfterViewInit() {
18 | this._portal = new TemplatePortal(this._dialogTemplate, this._viewContainerRef);
19 | this._overlayRef = this._overlay.create({
20 | positionStrategy: this._overlay.position().global().centerHorizontally().centerVertically(),
21 | hasBackdrop: true
22 | });
23 | this._overlayRef.backdropClick().subscribe(() => this._overlayRef.detach());
24 | }
25 |
26 | ngOnDestroy() {
27 | this._overlayRef.dispose();
28 | }
29 |
30 | openDialog() {
31 | this._overlayRef.attach(this._portal);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drop-directive/drag-drop-drop.component.html:
--------------------------------------------------------------------------------
1 | cdkDrop
2 |
3 | 可以到处拖拽
4 |
5 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drop-directive/drag-drop-drop.component.less:
--------------------------------------------------------------------------------
1 | .example-box {
2 | width: 100px;
3 | height: 100px;
4 | border: solid 1px #ccc;
5 | color: rgba(0, 0, 0, 0.87);
6 | cursor: move;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | text-align: center;
11 | background: #fff;
12 | border-radius: 4px;
13 | position: relative;
14 | z-index: 1;
15 | transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
16 | box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
17 | 0 2px 2px 0 rgba(0, 0, 0, 0.14),
18 | 0 1px 5px 0 rgba(0, 0, 0, 0.12);
19 | }
20 |
21 | .example-box:active {
22 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
23 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
24 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drop-directive/drag-drop-drop.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
2 | import {CdkDrag} from "@angular/cdk/drag-drop";
3 |
4 | @Component({
5 | selector: 'app-drag-drop-drop',
6 | templateUrl: './drag-drop-drop.component.html',
7 | styleUrls: ['./drag-drop-drop.component.less']
8 | })
9 | export class DragDropDropComponent implements AfterViewInit {
10 |
11 | @ViewChild(CdkDrag) cdkDragDirective: CdkDrag;
12 |
13 | constructor() {
14 | }
15 |
16 | ngAfterViewInit() {
17 | console.log(this.cdkDragDirective.getPlaceholderElement());
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drop-list-directive/drag-drop-drop-list.component.html:
--------------------------------------------------------------------------------
1 | cdkDropList
2 |
5 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drop-list-directive/drag-drop-drop-list.component.less:
--------------------------------------------------------------------------------
1 | .example-list {
2 | width: 500px;
3 | max-width: 100%;
4 | border: solid 1px #ccc;
5 | min-height: 60px;
6 | display: block;
7 | background: white;
8 | border-radius: 4px;
9 | overflow: hidden;
10 | }
11 |
12 | .example-box {
13 | padding: 20px 10px;
14 | border-bottom: solid 1px #ccc;
15 | color: rgba(0, 0, 0, 0.87);
16 | display: flex;
17 | flex-direction: row;
18 | align-items: center;
19 | justify-content: space-between;
20 | box-sizing: border-box;
21 | cursor: move;
22 | background: white;
23 | font-size: 14px;
24 | }
25 |
26 | .cdk-drag-preview {
27 | box-sizing: border-box;
28 | border-radius: 4px;
29 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
30 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
31 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
32 | }
33 |
34 | .cdk-drag-placeholder {
35 | opacity: 0;
36 | }
37 |
38 | .cdk-drag-animating {
39 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
40 | }
41 |
42 | .example-box:last-child {
43 | border: none;
44 | }
45 |
46 | .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
47 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
48 | }
49 |
--------------------------------------------------------------------------------
/src/app/drag-drop/drop-list-directive/drag-drop-drop-list.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 | import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop';
3 |
4 | @Component({
5 | selector: 'app-drag-drop-drop-list',
6 | templateUrl: './drag-drop-drop-list.component.html',
7 | styleUrls: ['./drag-drop-drop-list.component.less']
8 | })
9 | export class DragDropDropListComponent {
10 |
11 | movies = [
12 | 'Episode I - The Phantom Menace',
13 | 'Episode II - Attack of the Clones',
14 | 'Episode III - Revenge of the Sith',
15 | 'Episode IV - A New Hope',
16 | 'Episode V - The Empire Strikes Back',
17 | 'Episode VI - Return of the Jedi',
18 | 'Episode VII - The Force Awakens',
19 | 'Episode VIII - The Last Jedi'
20 | ];
21 |
22 | drop(event: CdkDragDrop) {
23 | moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/app/drag-drop/handle-drag-area/drag-drop-handle-drag-area.component.html:
--------------------------------------------------------------------------------
1 | cdkDragHandle
2 |
3 | I can only be dragged using the handle
4 |
5 |
11 |
12 |
--------------------------------------------------------------------------------
/src/app/drag-drop/handle-drag-area/drag-drop-handle-drag-area.component.less:
--------------------------------------------------------------------------------
1 | .example-box {
2 | width: 200px;
3 | height: 200px;
4 | padding: 10px;
5 | box-sizing: border-box;
6 | border: solid 1px #ccc;
7 | color: rgba(0, 0, 0, 0.87);
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | text-align: center;
12 | background: #fff;
13 | border-radius: 4px;
14 | position: relative;
15 | z-index: 1;
16 | transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
17 | box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
18 | 0 2px 2px 0 rgba(0, 0, 0, 0.14),
19 | 0 1px 5px 0 rgba(0, 0, 0, 0.12);
20 | }
21 |
22 | .example-box:active {
23 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
24 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
25 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
26 | }
27 |
28 | .example-handle {
29 | position: absolute;
30 | top: 10px;
31 | right: 10px;
32 | color: #ccc;
33 | cursor: move;
34 | width: 24px;
35 | height: 24px;
36 | }
37 |
--------------------------------------------------------------------------------
/src/app/drag-drop/handle-drag-area/drag-drop-handle-drag-area.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-drag-drop-handle-drag-area',
5 | templateUrl: './drag-drop-handle-drag-area.component.html',
6 | styleUrls: ['./drag-drop-handle-drag-area.component.less']
7 | })
8 | export class DragDropHandleDragAreaComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/app/drag-drop/orientation-drag/drag-drop-orientation-drag.component.html:
--------------------------------------------------------------------------------
1 | 水平方向的drag
2 |
5 |
--------------------------------------------------------------------------------
/src/app/drag-drop/orientation-drag/drag-drop-orientation-drag.component.less:
--------------------------------------------------------------------------------
1 | .example-list {
2 | width: 1000px;
3 | max-width: 100%;
4 | border: solid 1px #ccc;
5 | min-height: 60px;
6 | display: flex;
7 | flex-direction: row;
8 | background: white;
9 | border-radius: 4px;
10 | overflow: hidden;
11 | }
12 |
13 | .example-box {
14 | padding: 20px 10px;
15 | border-right: solid 1px #ccc;
16 | color: rgba(0, 0, 0, 0.87);
17 | display: flex;
18 | flex-direction: row;
19 | align-items: center;
20 | justify-content: space-between;
21 | box-sizing: border-box;
22 | cursor: move;
23 | background: white;
24 | font-size: 14px;
25 | flex-grow: 1;
26 | flex-basis: 0;
27 | }
28 |
29 | .cdk-drag-preview {
30 | box-sizing: border-box;
31 | border-radius: 4px;
32 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
33 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
34 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
35 | }
36 |
37 | .cdk-drag-placeholder {
38 | opacity: 0;
39 | }
40 |
41 | .cdk-drag-animating {
42 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
43 | }
44 |
45 | .example-box:last-child {
46 | border: none;
47 | }
48 |
49 | .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
50 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
51 | }
52 |
--------------------------------------------------------------------------------
/src/app/drag-drop/orientation-drag/drag-drop-orientation-drag.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop';
3 |
4 | @Component({
5 | selector: 'app-drag-drop-orientation-drag',
6 | templateUrl: './drag-drop-orientation-drag.component.html',
7 | styleUrls: ['./drag-drop-orientation-drag.component.less']
8 | })
9 | export class DragDropOrientationDragComponent {
10 |
11 | timePeriods = [
12 | 'Bronze age',
13 | 'Iron age',
14 | 'Middle ages',
15 | 'Early modern period',
16 | 'Long nineteenth century'
17 | ];
18 |
19 | drop(event: CdkDragDrop) {
20 | moveItemInArray(this.timePeriods, event.previousIndex, event.currentIndex);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/app/drag-drop/restricting-move-area/drag-drop-restricting-move-area.component.html:
--------------------------------------------------------------------------------
1 | 限制移动的区域
2 |
3 | 只能上下移动
4 |
5 |
6 |
7 | 只能左右移动
8 |
9 |
--------------------------------------------------------------------------------
/src/app/drag-drop/restricting-move-area/drag-drop-restricting-move-area.component.less:
--------------------------------------------------------------------------------
1 | .example-box {
2 | width: 200px;
3 | height: 200px;
4 | border: solid 1px #ccc;
5 | color: rgba(0, 0, 0, 0.87);
6 | cursor: move;
7 | display: inline-flex;
8 | justify-content: center;
9 | align-items: center;
10 | text-align: center;
11 | background: #fff;
12 | border-radius: 4px;
13 | margin-right: 25px;
14 | position: relative;
15 | z-index: 1;
16 | transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
17 | box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
18 | 0 2px 2px 0 rgba(0, 0, 0, 0.14),
19 | 0 1px 5px 0 rgba(0, 0, 0, 0.12);
20 | }
21 |
22 | .example-box:active {
23 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
24 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
25 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
26 | }
27 |
--------------------------------------------------------------------------------
/src/app/drag-drop/restricting-move-area/drag-drop-restricting-move-area.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-drag-drop-restricting-move-area',
5 | templateUrl: './drag-drop-restricting-move-area.component.html',
6 | styleUrls: ['./drag-drop-restricting-move-area.component.less']
7 | })
8 | export class DragDropRestrictingMoveAreaComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/app/drag-drop/transferring-item/drag-drop-transferring-item.component.html:
--------------------------------------------------------------------------------
1 | 两个list之间交换item
2 |
3 |
15 |
16 |
28 |
29 |
--------------------------------------------------------------------------------
/src/app/drag-drop/transferring-item/drag-drop-transferring-item.component.less:
--------------------------------------------------------------------------------
1 | .example-container {
2 | width: 400px;
3 | max-width: 100%;
4 | margin: 0 25px 25px 0;
5 | display: inline-block;
6 | vertical-align: top;
7 | }
8 |
9 | .example-list {
10 | border: solid 1px #ccc;
11 | min-height: 60px;
12 | background: white;
13 | border-radius: 4px;
14 | overflow: hidden;
15 | display: block;
16 | }
17 |
18 | .example-box {
19 | padding: 20px 10px;
20 | border-bottom: solid 1px #ccc;
21 | color: rgba(0, 0, 0, 0.87);
22 | display: flex;
23 | flex-direction: row;
24 | align-items: center;
25 | justify-content: space-between;
26 | box-sizing: border-box;
27 | cursor: move;
28 | background: white;
29 | font-size: 14px;
30 | }
31 |
32 | .cdk-drag-preview {
33 | box-sizing: border-box;
34 | border-radius: 4px;
35 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
36 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
37 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
38 | }
39 |
40 | .cdk-drag-placeholder {
41 | opacity: 0;
42 | }
43 |
44 | .cdk-drag-animating {
45 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
46 | }
47 |
48 | .example-box:last-child {
49 | border: none;
50 | }
51 |
52 | .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
53 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
54 | }
55 |
--------------------------------------------------------------------------------
/src/app/drag-drop/transferring-item/drag-drop-transferring-item.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
3 |
4 | @Component({
5 | selector: 'app-drag-drop-transferring-item',
6 | templateUrl: './drag-drop-transferring-item.component.html',
7 | styleUrls: ['./drag-drop-transferring-item.component.less']
8 | })
9 | export class DragDropTransferringItemComponent {
10 |
11 | todo = [
12 | 'Get to work',
13 | 'Pick up groceries',
14 | 'Go home',
15 | 'Fall asleep'
16 | ];
17 |
18 | done = [
19 | 'Get up',
20 | 'Brush teeth',
21 | 'Take a shower',
22 | 'Check e-mail',
23 | 'Walk dog'
24 | ];
25 |
26 | drop(event: CdkDragDrop) {
27 | if (event.previousContainer === event.container) {
28 | moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
29 | } else {
30 | transferArrayItem(event.previousContainer.data,
31 | event.container.data,
32 | event.previousIndex,
33 | event.currentIndex);
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/app/keycodes/cdk-key-codes-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkKeyCodesComponent} from './cdk-key-codes.component';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: CdkKeyCodesComponent
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [
15 | RouterModule.forChild(routes),
16 | CommonModule
17 | ],
18 | exports: [
19 | RouterModule
20 | ],
21 | providers: []
22 | })
23 | export class CdkKeyCodesRoutingModule { }
24 |
--------------------------------------------------------------------------------
/src/app/keycodes/cdk-key-codes.component.html:
--------------------------------------------------------------------------------
1 | 键盘常用键码
2 |
3 | ps: 结果都在ts文件里面,通过console打印出来
4 |
--------------------------------------------------------------------------------
/src/app/keycodes/cdk-key-codes.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/keycodes/cdk-key-codes.component.less
--------------------------------------------------------------------------------
/src/app/keycodes/cdk-key-codes.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 | import {DELETE, ENTER, hasModifierKey, MAC_ENTER, TAB} from '@angular/cdk/keycodes';
3 |
4 | @Component({
5 | selector: 'app-key-codes',
6 | templateUrl: './cdk-key-codes.component.html',
7 | styleUrls: ['./cdk-key-codes.component.less']
8 | })
9 | export class CdkKeyCodesComponent {
10 |
11 | onKeyDown(event) {
12 | /**
13 | * 组合按键判断(如果按下的是 ctr按键 + 其他的按键的时候 返回true)
14 | */
15 | console.log(hasModifierKey(event, 'ctrlKey'));
16 | /**
17 | * 打印按键值
18 | */
19 | console.log(event.keyCode);
20 | /**
21 | * 通过 cdk 判断按键类型
22 | */
23 | switch (event.keyCode) {
24 | case MAC_ENTER:
25 | case ENTER:
26 | console.log('当前按键: Enter键');
27 | break;
28 | case TAB:
29 | console.log('当前按键: Tab键');
30 | break;
31 | case DELETE:
32 | console.log('当前按键: Delete键');
33 | break;
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/app/keycodes/cdk-key-codes.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkKeyCodesComponent} from './cdk-key-codes.component';
4 | import {RouterModule} from '@angular/router';
5 | import {CdkKeyCodesRoutingModule} from './cdk-key-codes-routing.module';
6 |
7 | @NgModule({
8 | imports: [
9 | CommonModule,
10 | RouterModule,
11 | CdkKeyCodesRoutingModule
12 | ],
13 | declarations: [
14 | CdkKeyCodesComponent
15 | ]
16 | })
17 | export class CdkKeyCodesModule {
18 | }
19 |
--------------------------------------------------------------------------------
/src/app/layout/cdk-layout-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkLayoutComponent} from './cdk-layout.component';
5 |
6 |
7 | const routes: Routes = [
8 | {
9 | path: '',
10 | component: CdkLayoutComponent
11 | }
12 | ];
13 |
14 | @NgModule({
15 | imports: [
16 | RouterModule.forChild(routes),
17 | CommonModule
18 | ],
19 | exports: [
20 | RouterModule
21 | ],
22 | providers: []
23 | })
24 | export class CdkLayoutRoutingModule {
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/layout/cdk-layout.component.html:
--------------------------------------------------------------------------------
1 | cdk layout 所有的内容都在ts中哦!
2 | BreakpointObserver MediaMatcher
--------------------------------------------------------------------------------
/src/app/layout/cdk-layout.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/layout/cdk-layout.component.less
--------------------------------------------------------------------------------
/src/app/layout/cdk-layout.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnDestroy, OnInit} from '@angular/core';
2 | import {BreakpointObserver, Breakpoints, BreakpointState, MediaMatcher} from '@angular/cdk/layout';
3 |
4 | @Component({
5 | selector: 'app-cdk-layout',
6 | templateUrl: './cdk-layout.component.html',
7 | styleUrls: ['./cdk-layout.component.less']
8 | })
9 | export class CdkLayoutComponent implements OnInit, OnDestroy {
10 |
11 | matcher: MediaQueryList;
12 |
13 | // @HostListener('window:resize')
14 | // public onWindowResize(): void {
15 | // if (window.innerWidth >= 960) {
16 | // console.log('>= 960');
17 | // } else if (window.innerWidth >= 600 && window.innerWidth < 960) {
18 | // console.log('>= 600 && < 960');
19 | // } else {
20 | // console.log('< 600');
21 | // }
22 | // }
23 |
24 | constructor(public breakpointObserver: BreakpointObserver, public mediaMatcher: MediaMatcher) {
25 | }
26 |
27 | ngOnInit() {
28 |
29 | // 简单的一次性匹配,可以使用isMatching方法。如果组件初始化时窗口至少为40rem高,则输出到控制台
30 | if (this.breakpointObserver.isMatched('(min-height: 40rem)')) {
31 | console.log('窗口至少为40rem高!');
32 | } else {
33 | console.log('窗口没有40rem高!');
34 | }
35 |
36 | // 注意哦,不会一直回调哦,只会在第一次满足或者不满足条件的时候回调。
37 | this.breakpointObserver
38 | .observe(['(min-width: 500px)'])
39 | .subscribe((state: BreakpointState) => {
40 | if (state.matches) {
41 | console.log('窗口宽度大于或者等于500px!');
42 | } else {
43 | console.log('窗口不满足宽度大于或者等于500px!');
44 | }
45 | });
46 |
47 | // 也可以使用Breakpoints对象,而不是使用手写的媒体查询,它为我们提供了常见断点的键。如果多个参数,当有一个条件满足或者不满足的时候就会触发
48 | this.breakpointObserver
49 | .observe([Breakpoints.Small, Breakpoints.HandsetPortrait])
50 | .subscribe((state: BreakpointState) => {
51 | if (state.matches) {
52 | console.log(
53 | 'Breakpoints.Small or Breakpoints.HandsetPortrait'
54 | );
55 | }
56 | });
57 |
58 |
59 | this.matcher = this.mediaMatcher.matchMedia('(min-width: 500px)');
60 | this.matcher.addListener(this.matchMediaListener);
61 |
62 | // // 在程序加载时判断当前设备是横屏还是竖屏
63 | // const isPortrait = window.matchMedia('(orientation: portrait)').matches;
64 | // if (isPortrait) {
65 | // console.log('This is portrait');
66 | // }
67 | //
68 | // // 初始化时窗口的大小等等
69 | // if (window.innerWidth >= 960) {
70 | // console.log('>= 960');
71 | // } else {
72 | // console.log('< 960');
73 | // }
74 | }
75 |
76 | ngOnDestroy() {
77 | this.matcher.removeListener(this.matchMediaListener);
78 | }
79 |
80 | matchMediaListener(event) {
81 | console.log(event.matches ? 'match' : 'no match');
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/src/app/layout/cdk-layout.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkLayoutRoutingModule} from './cdk-layout-routing.module';
4 | import {CdkLayoutComponent} from './cdk-layout.component';
5 | import {RouterModule} from '@angular/router';
6 | import {LayoutModule} from "@angular/cdk/layout";
7 |
8 | @NgModule({
9 | imports: [
10 | CommonModule,
11 | RouterModule,
12 | LayoutModule,
13 | CdkLayoutRoutingModule
14 | ],
15 | declarations: [
16 | CdkLayoutComponent
17 | ]
18 | })
19 | export class CdkLayoutModule {
20 | }
21 |
--------------------------------------------------------------------------------
/src/app/observers/cdk-observers-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkObserversComponent} from './cdk-observers.component';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: CdkObserversComponent
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [
15 | RouterModule.forChild(routes),
16 | CommonModule
17 | ],
18 | exports: [
19 | RouterModule
20 | ],
21 | providers: []
22 | })
23 | export class CdkObserversRoutingModule { }
24 |
--------------------------------------------------------------------------------
/src/app/observers/cdk-observers.component.html:
--------------------------------------------------------------------------------
1 | 通过 cdk observers 可以监听dom变化
2 |
3 |
4 |
5 | {{content}}
6 |
7 |
8 |
9 |
10 | {{content}}
11 |
--------------------------------------------------------------------------------
/src/app/observers/cdk-observers.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/observers/cdk-observers.component.less
--------------------------------------------------------------------------------
/src/app/observers/cdk-observers.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
2 | import {ContentObserver} from '@angular/cdk/observers';
3 |
4 | @Component({
5 | selector: 'app-cdk-observers',
6 | templateUrl: './cdk-observers.component.html',
7 | styleUrls: ['./cdk-observers.component.less']
8 | })
9 | export class CdkObserversComponent implements AfterViewInit {
10 |
11 | @ViewChild('observerSource')
12 | observerSource: ElementRef;
13 |
14 | content = 1;
15 |
16 | constructor(private observer: ContentObserver) {
17 | setInterval(() => {
18 | this.content++;
19 | }, 3000);
20 | }
21 |
22 | ngAfterViewInit(): void {
23 | // ContentObserver service监听变化
24 | this.observer.observe(this.observerSource.nativeElement).subscribe((event: MutationRecord[]) => console.log(event));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/app/observers/cdk-observers.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkObserversRoutingModule} from './cdk-observers-routing.module';
4 | import {CdkObserversComponent} from './cdk-observers.component';
5 | import {ObserversModule} from '@angular/cdk/observers';
6 | import { ObserversChildComponent } from './child/observers-child.component';
7 |
8 | @NgModule({
9 | imports: [
10 | CommonModule,
11 | ObserversModule,
12 | CdkObserversRoutingModule
13 | ],
14 | declarations: [CdkObserversComponent, ObserversChildComponent]
15 | })
16 | export class CdkObserversModule {
17 | }
18 |
--------------------------------------------------------------------------------
/src/app/observers/child/observers-child.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/app/observers/child/observers-child.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/observers/child/observers-child.component.less
--------------------------------------------------------------------------------
/src/app/observers/child/observers-child.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-observers-child',
5 | templateUrl: './observers-child.component.html',
6 | styleUrls: ['./observers-child.component.less']
7 | })
8 | export class ObserversChildComponent {
9 |
10 | count = 0;
11 |
12 | projectContentChanged($event: MutationRecord[]) {
13 | ++this.count;
14 | console.log(`ng-content内容改变了,第${this.count}次`);
15 | console.log($event, this.count);
16 | }
17 |
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/app/overlay/cdk-overlay-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from "@angular/router";
4 | import {CdkOverlayComponent} from "./cdk-overlay.component";
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: CdkOverlayComponent
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [
15 | RouterModule.forChild(routes),
16 | CommonModule
17 | ],
18 | exports: [
19 | RouterModule
20 | ],
21 | providers: []
22 | })
23 | export class CdkOverlayRoutingModule { }
24 |
--------------------------------------------------------------------------------
/src/app/overlay/cdk-overlay.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
组件或者ng-template实现overlay
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
15 | ng-temtortelliniTemplateplate显示
16 |
17 |
18 |
19 |
24 |
25 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
指令(Directives)实现overlay
37 |
40 |
41 |
47 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/app/overlay/cdk-overlay.component.less:
--------------------------------------------------------------------------------
1 |
2 | .template-overlay-pane {
3 | padding: 10px;
4 | border: 1px solid black;
5 | background-color: skyblue;
6 | }
7 |
8 | .menu-wrap {
9 | margin: 0;
10 | padding: 10px;
11 | border: 1px solid black;
12 | color: white;
13 | background-color: orangered;
14 | opacity: 0.5;
15 | }
16 |
17 | .backdrop-with-out-transparent {
18 | background-color: transparent;
19 | }
--------------------------------------------------------------------------------
/src/app/overlay/cdk-overlay.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ElementRef, ViewChild, ViewContainerRef, ViewEncapsulation} from '@angular/core';
2 | import {Overlay, OverlayConfig, OverlayRef} from '@angular/cdk/overlay';
3 | import {ComponentPortal, TemplatePortalDirective} from '@angular/cdk/portal';
4 | import {OverlayPanelComponent} from './panel/overlay-panel.component';
5 |
6 | @Component({
7 | selector: 'app-cdk-overlay',
8 | templateUrl: './cdk-overlay.component.html',
9 | styleUrls: ['./cdk-overlay.component.less'],
10 | encapsulation: ViewEncapsulation.None,
11 | preserveWhitespaces: false,
12 | })
13 | export class CdkOverlayComponent {
14 |
15 |
16 | isMenuOpen = false;
17 | globalOverlayPosition = 0;
18 | actionMenuItemList = ['第一项item', '第二项item'];
19 | private _overlayTemplateRef: OverlayRef;
20 | private _overlayConnectRef: OverlayRef;
21 |
22 | @ViewChild('overlayGlobalTemplate') templateGlobalPortals: TemplatePortalDirective;
23 | @ViewChild('connectComponentOrigin') _overlayConnectComponentOrigin: ElementRef;
24 | @ViewChild('connectTemplateOrigin') _overlayConnectTemplateOrigin: ElementRef;
25 | @ViewChild('overlayConnectTemplate') _overlayOriginTemplateDirective: TemplatePortalDirective;
26 |
27 | constructor(public overlay: Overlay
28 | , public viewContainerRef: ViewContainerRef) {
29 | }
30 |
31 | /**
32 | * overlay 在整个屏幕的中间显示
33 | */
34 | showOverlayGlobalPanelCenter() {
35 | // config: OverlayConfig overlay的配置,配置显示位置,和滑动策略
36 | const config = new OverlayConfig();
37 | config.positionStrategy = this.overlay.position()
38 | .global() // 全局显示
39 | .centerHorizontally() // 水平居中
40 | .centerVertically(); // 垂直居中
41 | config.hasBackdrop = true; // 设置overlay后面有一层背景, 当然你也可以设置backdropClass 来设置这层背景的class
42 | const overlayRef = this.overlay.create(config); // OverlayRef, overlay层
43 | overlayRef.backdropClick().subscribe(() => {
44 | // 点击了backdrop背景
45 | overlayRef.dispose();
46 | });
47 | // OverlayPanelComponent是动态组件
48 | // 创建一个ComponentPortal,attach到OverlayRef,这个时候我们这个overlay层就显示出来了。
49 | overlayRef.attach(new ComponentPortal(OverlayPanelComponent, this.viewContainerRef));
50 | // 监听overlayRef上的键盘按键事件
51 | overlayRef.keydownEvents().subscribe((event: KeyboardEvent) => {
52 | console.log(overlayRef._keydownEventSubscriptions + ' times');
53 | console.log(event);
54 | });
55 | }
56 |
57 | /**
58 | * overlay 在整个屏幕位置,自己控制位置
59 | */
60 | showOverlayGlobalPanelPosition() {
61 | const config = new OverlayConfig();
62 | config.positionStrategy = this.overlay.position()
63 | .global()
64 | .left(`${this.globalOverlayPosition}px`)
65 | .top(`${this.globalOverlayPosition}px`);
66 | this.globalOverlayPosition += 30;
67 | config.hasBackdrop = true;
68 | const overlayRef = this.overlay.create(config);
69 | overlayRef.backdropClick().subscribe(() => {
70 | overlayRef.dispose();
71 | });
72 | overlayRef.attach(new ComponentPortal(OverlayPanelComponent, this.viewContainerRef));
73 | }
74 |
75 | /**
76 | * 显示 ng-template 的内容
77 | */
78 | showOverlayPanelTemplate() {
79 | const config = new OverlayConfig();
80 | config.positionStrategy = this.overlay.position()
81 | .global()
82 | .centerHorizontally()
83 | .top(`${this.globalOverlayPosition}px`);
84 | this.globalOverlayPosition += 30;
85 | this._overlayTemplateRef = this.overlay.create(config);
86 | this._overlayTemplateRef.attach(this.templateGlobalPortals);
87 | }
88 |
89 | /**
90 | * 移除 ng-template 内容
91 | */
92 | dismissOverlayPanelTemplate() {
93 | if (this._overlayTemplateRef && this._overlayTemplateRef.hasAttached()) {
94 | this._overlayTemplateRef.dispose();
95 | }
96 | }
97 |
98 | /**
99 | * overlay connect origin 显示,依附某个组件显示
100 | */
101 | showOverlayPanelConnectComponent() {
102 | const strategy = this.overlay.position()
103 | .flexibleConnectedTo(this._overlayConnectComponentOrigin.nativeElement)
104 | .withPositions([{
105 | originX: 'center',
106 | originY: 'bottom',
107 | overlayX: 'center',
108 | overlayY: 'top',
109 | offsetX: 0,
110 | offsetY: 0
111 | }]);
112 | strategy.withLockedPosition(true);
113 | const config = new OverlayConfig({positionStrategy: strategy});
114 | config.scrollStrategy = this.overlay.scrollStrategies.reposition();
115 | this._overlayConnectRef = this.overlay.create(config);
116 | this._overlayConnectRef.attach(new ComponentPortal(OverlayPanelComponent, this.viewContainerRef));
117 | }
118 |
119 | dismissOverlayPanelConnectComponent() {
120 | if (this._overlayConnectRef && this._overlayConnectRef.hasAttached()) {
121 | this._overlayConnectRef.dispose();
122 | }
123 | }
124 |
125 | /**
126 | * overlay connect origin 显示,依附ng-template
127 | */
128 | showOverlayPanelConnectTemplate() {
129 | const strategy = this.overlay.position()
130 | .flexibleConnectedTo(this._overlayConnectTemplateOrigin.nativeElement)
131 | .withPositions([{
132 | originX: 'start',
133 | originY: 'bottom',
134 | overlayX: 'end',
135 | overlayY: 'top',
136 | offsetX: 0,
137 | offsetY: 0
138 | }]);
139 | const config = new OverlayConfig({positionStrategy: strategy});
140 | config.hasBackdrop = true;
141 | config.backdropClass = 'backdrop-with-out';
142 | const overlayRef = this.overlay.create(config);
143 | overlayRef.backdropClick().subscribe(() => {
144 | overlayRef.dispose();
145 | });
146 | overlayRef.attach(this._overlayOriginTemplateDirective);
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/app/overlay/cdk-overlay.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {OverlayModule} from "@angular/cdk/overlay";
4 | import {CdkOverlayComponent} from './cdk-overlay.component';
5 | import {CdkOverlayRoutingModule} from "./cdk-overlay-routing.module";
6 | import {OverlayPanelComponent} from './panel/overlay-panel.component';
7 | import {PortalModule} from "@angular/cdk/portal";
8 |
9 | @NgModule({
10 | imports: [
11 | CommonModule,
12 | PortalModule,
13 | OverlayModule,
14 | CdkOverlayRoutingModule
15 | ],
16 | declarations: [
17 | CdkOverlayComponent,
18 | OverlayPanelComponent
19 | ],
20 | entryComponents: [
21 | OverlayPanelComponent
22 | ],
23 | providers: [
24 | ],
25 | })
26 | export class CdkOverlayModule {
27 | }
28 |
--------------------------------------------------------------------------------
/src/app/overlay/panel/overlay-panel.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-overlay-panel',
5 | template: `
6 | Overlay展示
7 | `,
8 | styles: [`
9 | .wu-overlay-pane {
10 | margin: 0;
11 | padding: 10px;
12 | border: 1px solid black;
13 | background-color: skyblue;
14 | }
15 | `]
16 | })
17 | export class OverlayPanelComponent implements OnInit {
18 |
19 | constructor() { }
20 |
21 | ngOnInit() {
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/app/platform/cdk-platform-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkOverlayComponent} from '../overlay/cdk-overlay.component';
5 | import {CdkPlatformComponent} from './cdk-platform.component';
6 |
7 | const routes: Routes = [
8 | {
9 | path: '',
10 | component: CdkPlatformComponent
11 | }
12 | ];
13 |
14 | @NgModule({
15 | imports: [
16 | RouterModule.forChild(routes),
17 | CommonModule
18 | ],
19 | exports: [
20 | RouterModule
21 | ],
22 | providers: []
23 | })
24 | export class CdkPlatformRoutingModule { }
25 |
--------------------------------------------------------------------------------
/src/app/platform/cdk-platform.component.html:
--------------------------------------------------------------------------------
1 | 通过 cdk Platform 获取到的平台信息如下:
2 | 是否 Android: {{platform.ANDROID}}
3 | 是否 iOS: {{platform.IOS}}
4 | 是否 Firefox: {{platform.FIREFOX}}
5 | 是否 Blink: {{platform.BLINK}}
6 | 是否 Webkit: {{platform.WEBKIT}}
7 | 是否 Trident: {{platform.TRIDENT}}
8 | 是否 Edge: {{platform.EDGE}}
9 | 是否浏览器: {{platform.isBrowser}}
10 | 支持输入的类型: {{supportedInputTypes}}
11 | 是否支持被动监听: {{supportsPassiveEventListeners}}
12 | 是否支持 scroll 行为: {{supportsScrollBehavior}}
--------------------------------------------------------------------------------
/src/app/platform/cdk-platform.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/platform/cdk-platform.component.less
--------------------------------------------------------------------------------
/src/app/platform/cdk-platform.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 | import {getSupportedInputTypes, Platform, supportsPassiveEventListeners, supportsScrollBehavior} from '@angular/cdk/platform';
3 |
4 | @Component({
5 | selector: 'app-cdk-platform',
6 | templateUrl: './cdk-platform.component.html',
7 | styleUrls: ['./cdk-platform.component.less']
8 | })
9 | export class CdkPlatformComponent {
10 |
11 | /**
12 | * 获取支持的输入类型
13 | */
14 | supportedInputTypes = Array.from(getSupportedInputTypes()).join(', ');
15 | /**
16 | * 是否支持被动事件监听器
17 | */
18 | supportsPassiveEventListeners = supportsPassiveEventListeners();
19 | /**
20 | * 是否支持滑动行为
21 | */
22 | supportsScrollBehavior = supportsScrollBehavior();
23 |
24 | /**
25 | * Platform Service引入进来
26 | */
27 | constructor(public platform: Platform) {
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/app/platform/cdk-platform.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkPlatformRoutingModule} from './cdk-platform-routing.module';
4 | import {CdkPlatformComponent} from './cdk-platform.component';
5 | import {PlatformModule} from '@angular/cdk/platform';
6 |
7 | @NgModule({
8 | imports: [
9 | CommonModule,
10 | PlatformModule,
11 | CdkPlatformRoutingModule
12 | ],
13 | declarations: [CdkPlatformComponent]
14 | })
15 | export class CdkPlatformModule {
16 | }
17 |
--------------------------------------------------------------------------------
/src/app/portal/cdk-portal-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkPortalComponent} from './cdk-portal.component';
5 |
6 |
7 | const routes: Routes = [
8 | {
9 | path: '',
10 | component: CdkPortalComponent
11 | }
12 | ];
13 |
14 | @NgModule({
15 | imports: [
16 | RouterModule.forChild(routes),
17 | CommonModule
18 | ],
19 | exports: [
20 | RouterModule
21 | ],
22 | providers: []
23 | })
24 | export class CdkPortalRoutingModule {
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/portal/cdk-portal.component.html:
--------------------------------------------------------------------------------
1 | 通过 cdk portal 显示view
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
17 |
20 |
23 |
24 |
25 |
26 | ng-template 指定的内容(first) 外部参数 {{obj.age}}
27 |
28 |
29 |
30 |
ng-template 指定的内容(last)
31 |
32 |
33 |
34 | 这部分内容在app-root标签之外
35 |
36 |
--------------------------------------------------------------------------------
/src/app/portal/cdk-portal.component.less:
--------------------------------------------------------------------------------
1 | .demo-portal-host {
2 | border: 1px dashed black;
3 | width: 500px;
4 | height: 100px;
5 | }
--------------------------------------------------------------------------------
/src/app/portal/cdk-portal.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AfterViewInit,
3 | ApplicationRef,
4 | Component,
5 | ComponentFactoryResolver,
6 | ElementRef,
7 | Inject,
8 | Injector,
9 | QueryList,
10 | TemplateRef,
11 | ViewChild,
12 | ViewChildren,
13 | ViewContainerRef
14 | } from '@angular/core';
15 | import {ComponentPortal, DomPortalOutlet, TemplatePortal, TemplatePortalDirective} from '@angular/cdk/portal';
16 | import {PortalChildComponent} from './portal-child-component/portal-child.component';
17 | import {DOCUMENT} from '@angular/common';
18 |
19 | @Component({
20 | selector: 'app-cdk-portal',
21 | templateUrl: './cdk-portal.component.html',
22 | styleUrls: ['./cdk-portal.component.less']
23 | })
24 | export class CdkPortalComponent implements AfterViewInit {
25 |
26 | // 获取到对应html里面所有添加了cdkPortal指令的元素的TemplatePortal
27 | @ViewChildren(TemplatePortalDirective) templatePortals: QueryList>;
28 | // 获取单个的cdkPortal指令的元素的TemplatePortal 【#templatePortal="cdkPortal"】
29 | @ViewChild('templatePortal') divTemplatePortal: TemplatePortal;
30 |
31 | @ViewChild('outOfApp') templateOutOfApp: TemplateRef;
32 | private _domPortalOutletOutOfApp: DomPortalOutlet;
33 |
34 | selectedPortal;
35 |
36 | ctx = {
37 | $implicit: {
38 | name: 'John',
39 | age: 34
40 | },
41 | location: 'USA'
42 | };
43 |
44 |
45 | constructor(@Inject(DOCUMENT) private document: any,
46 | private elementRef: ElementRef,
47 | private injector: Injector,
48 | private appRef: ApplicationRef,
49 | private viewContainerRef: ViewContainerRef,
50 | private componentFactoryResolver: ComponentFactoryResolver) {
51 | }
52 |
53 | ngAfterViewInit(): void {
54 | /**
55 | * 把内容放置在
56 | */
57 | const element = this.document.createElement('div');
58 | this.document.body.appendChild(element);
59 | this._domPortalOutletOutOfApp = new DomPortalOutlet(element, this.componentFactoryResolver, this.appRef, this.injector);
60 | const templatePortal = new TemplatePortal(
61 | this.templateOutOfApp,
62 | this.viewContainerRef
63 | );
64 | this._domPortalOutletOutOfApp.attach(templatePortal);
65 |
66 | console.log(this.divTemplatePortal);
67 | }
68 |
69 | cdkPortalFirst() {
70 | this.templatePortals.first.context = this.ctx;
71 | this.selectedPortal = this.templatePortals.first;
72 | }
73 |
74 | cdkPortalLast() {
75 | this.selectedPortal = this.templatePortals.last;
76 | }
77 |
78 | cdkPortalComponent() {
79 | this.selectedPortal = new ComponentPortal(PortalChildComponent);
80 | }
81 |
82 | onPortalAttached() {
83 | console.log('cdkPortalOutlet上有组件attach上来了');
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/app/portal/cdk-portal.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule} from '@angular/router';
4 | import {CdkPortalRoutingModule} from './cdk-portal-routing.module';
5 | import {CdkPortalComponent} from './cdk-portal.component';
6 | import {PortalChildComponent} from './portal-child-component/portal-child.component';
7 | import {PortalComponentComponent} from './portal-component/portal-component.component';
8 | import {PortalTemplateComponent} from './portal-template/portal-template.component';
9 | import {PortalModule} from "@angular/cdk/portal";
10 | import {ToolTipDirective} from './portal-tool-tip/tool-tip.directive';
11 | import { ToolTipComponent } from './portal-tool-tip/tool-tip.component';
12 |
13 | @NgModule({
14 | imports: [
15 | CommonModule,
16 | RouterModule,
17 | PortalModule,
18 | CdkPortalRoutingModule
19 | ],
20 | declarations: [
21 | CdkPortalComponent,
22 | PortalChildComponent,
23 | PortalComponentComponent,
24 | PortalTemplateComponent,
25 | ToolTipDirective,
26 | ToolTipComponent
27 | ],
28 | entryComponents: [
29 | PortalChildComponent,
30 | ToolTipComponent
31 | ]
32 | })
33 | export class CdkLPortalModule {
34 | }
35 |
--------------------------------------------------------------------------------
/src/app/portal/portal-child-component/portal-child.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, EventEmitter, Inject, InjectionToken} from '@angular/core';
2 |
3 | /**
4 | * 用于动态创建PortalChildComponent的时候传递参数
5 | */
6 | export const PORTAL_CHILD_DATA = new InjectionToken('PORTAL_CHILD_DATA');
7 |
8 | @Component({
9 | selector: 'app-portal-child',
10 | template: `
11 | portal child show
12 |
13 | `
14 | })
15 | export class PortalChildComponent {
16 |
17 | outEvent: EventEmitter;
18 |
19 | /**
20 | * 构造函数
21 | * @param initData 创建组件的时候传递过来的参数(为了测试用了any类型,推荐根据业务使用特定的类型,尽量不要使用any)
22 | */
23 | constructor(@Inject(PORTAL_CHILD_DATA) public initData: any) {
24 | console.log(initData);
25 | }
26 |
27 | /**
28 | * 用来测试把Portal里面的事件返回上去
29 | */
30 | onButtonClick() {
31 | if (this.outEvent != null) {
32 | this.outEvent.emit('child 里面被点击了');
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/app/portal/portal-component/portal-component.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ApplicationRef,
3 | Component,
4 | ComponentFactoryResolver, ComponentRef,
5 | ElementRef, EventEmitter,
6 | Injector, OnDestroy,
7 | OnInit,
8 | ViewContainerRef
9 | } from '@angular/core';
10 | import {ComponentPortal, DomPortalHost, PortalInjector} from '@angular/cdk/portal';
11 | import {PORTAL_CHILD_DATA, PortalChildComponent} from '../portal-child-component/portal-child.component';
12 | import {Subject} from "rxjs";
13 | import {takeUntil} from "rxjs/operators";
14 |
15 | @Component({
16 | selector: 'app-portal-component',
17 | template: ``
18 | })
19 | export class PortalComponentComponent implements OnInit, OnDestroy {
20 |
21 | private portalHost: DomPortalHost;
22 | private _$destroy = new Subject();
23 |
24 | constructor(
25 | private elementRef: ElementRef,
26 | private injector: Injector,
27 | private appRef: ApplicationRef,
28 | private viewContainerRef: ViewContainerRef,
29 | private componentFactoryResolver: ComponentFactoryResolver,
30 | ) {
31 | }
32 |
33 | ngOnInit() {
34 | // 1. 创建DomPortalHost
35 | this.portalHost = new DomPortalHost(
36 | this.elementRef.nativeElement as HTMLElement,
37 | this.componentFactoryResolver,
38 | this.appRef,
39 | this.injector
40 | );
41 | // injectionTokens用于传递参数,如果不想传递参数,直接const templatePortal = new ComponentPortal(PortalChildComponent) 就可以了
42 | const injectionTokens = new WeakMap();
43 | injectionTokens.set(PORTAL_CHILD_DATA, '构建组件传递的参数');
44 |
45 | // 2. 创建ComponentPortal
46 | const templatePortal = new ComponentPortal(PortalChildComponent
47 | , this.viewContainerRef
48 | , new PortalInjector(this.injector, injectionTokens)
49 | , this.componentFactoryResolver);
50 |
51 | // 3. ComponentPortal attach 到DomPortalHost里面去, 并且把ComponentPortal里面的时间返回上来
52 | // 如果不需要传出参数,this.portalHost.attach(templatePortal); 就可以了
53 | const portalComponentRef: ComponentRef = this.portalHost.attachComponentPortal(templatePortal);
54 | // 处理返回回来的事件
55 | const eventEmitter: EventEmitter = new EventEmitter();
56 | portalComponentRef.instance.outEvent = eventEmitter;
57 | eventEmitter.pipe(takeUntil(this._$destroy))
58 | .subscribe((event: string) => this.handlerPortalEvent(event));
59 | }
60 |
61 | private handlerPortalEvent(event: string): void {
62 | console.log('收到了Portal返回上来的事件信息:' + event);
63 | }
64 |
65 | ngOnDestroy(): void {
66 | this._$destroy.next();
67 | this._$destroy.complete();
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/app/portal/portal-template/portal-template.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ApplicationRef,
3 | Component,
4 | ComponentFactoryResolver,
5 | ElementRef,
6 | Injector,
7 | OnInit,
8 | TemplateRef,
9 | ViewChild,
10 | ViewContainerRef
11 | } from '@angular/core';
12 | import {DomPortalHost, TemplatePortal} from "@angular/cdk/portal";
13 |
14 | @Component({
15 | selector: 'app-portal-template',
16 | template: `
17 |
18 |
19 | 参数: {{ data }}
20 |
21 | `
22 | })
23 | export class PortalTemplateComponent implements OnInit {
24 |
25 | @ViewChild('portalTemplate') testTemplate: TemplateRef;
26 |
27 | constructor(
28 | private elementRef: ElementRef,
29 | private injector: Injector,
30 | private appRef: ApplicationRef,
31 | private viewContainerRef: ViewContainerRef,
32 | private componentFactoryResolver: ComponentFactoryResolver,
33 | ) {
34 | }
35 |
36 | ngOnInit() {
37 |
38 | // 1. DomPortalHost
39 | const portalHost = new DomPortalHost(
40 | this.elementRef.nativeElement as HTMLElement,
41 | this.componentFactoryResolver,
42 | this.appRef,
43 | this.injector
44 | );
45 | // 2. TemplatePortal
46 | const templatePortal = new TemplatePortal(
47 | this.testTemplate,
48 | this.viewContainerRef,
49 | {
50 | $implicit: "我是传递进来的数据",
51 | }
52 | );
53 | // 3. attach
54 | portalHost.attach(templatePortal);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/app/portal/portal-tool-tip/tool-tip.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, TemplateRef, ViewChild} from '@angular/core';
2 |
3 | @Component({
4 | template: `
5 |
6 | {{ tooltipText }}
7 | `,
8 | styles: [
9 | `
10 | .tooltip {
11 | position: absolute;
12 | color: red;
13 | top: 20px;
14 | left: 20px;
15 | }
16 | `
17 | ]
18 | })
19 | export class ToolTipComponent {
20 | @ViewChild('tooltip') tooltip: TemplateRef;
21 | }
22 |
--------------------------------------------------------------------------------
/src/app/portal/portal-tool-tip/tool-tip.directive.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ApplicationRef, ComponentFactoryResolver,
3 | Directive,
4 | ElementRef,
5 | HostBinding,
6 | HostListener,
7 | Injector,
8 | Input,
9 | OnInit,
10 | ViewContainerRef
11 | } from '@angular/core';
12 | import {DomPortalHost, TemplatePortal} from "@angular/cdk/portal";
13 | import {ToolTipComponent} from "./tool-tip.component";
14 | import {ComponentRef} from "@angular/core";
15 |
16 | @Directive({
17 | selector: '[appToolTip]'
18 | })
19 | export class ToolTipDirective implements OnInit {
20 |
21 | @Input('tooltipText')
22 | tooltipText: string;
23 |
24 | private _tooltipPortalHost: DomPortalHost;
25 | private _templatePortal: TemplatePortal;
26 |
27 | @HostBinding('style.position') position = 'relative';
28 |
29 | /**
30 | * 鼠标移入的时候显示
31 | */
32 | @HostListener('mouseenter')
33 | onMouseEnter() {
34 | this.show();
35 | }
36 |
37 | /**
38 | * 鼠标移出的时候隐藏
39 | */
40 | @HostListener('mouseleave')
41 | onMouseLeave() {
42 | this.hide();
43 | }
44 |
45 | constructor(
46 | private elementRef: ElementRef,
47 | private injector: Injector,
48 | private appRef: ApplicationRef,
49 | private viewContainerRef: ViewContainerRef,
50 | private componentFactoryResolver: ComponentFactoryResolver,
51 | ) {
52 | }
53 |
54 | ngOnInit() {
55 | this.createContainerTemplate();
56 | }
57 |
58 | private createContainerTemplate() {
59 | this._tooltipPortalHost = new DomPortalHost(
60 | (this.elementRef.nativeElement as HTMLElement),
61 | this.componentFactoryResolver,
62 | this.appRef,
63 | this.injector
64 | );
65 |
66 | const tooltipComponent = this.componentFactoryResolver.resolveComponentFactory(ToolTipComponent);
67 | const tooltipComponentRef: ComponentRef = tooltipComponent.create(this.injector);
68 |
69 | this._templatePortal = new TemplatePortal(
70 | tooltipComponentRef.instance.tooltip,
71 | this.viewContainerRef,
72 | {
73 | $implicit: this.tooltipText,
74 | }
75 | );
76 | }
77 |
78 | /**
79 | * 显示
80 | */
81 | private show() {
82 | if (!this._templatePortal.isAttached) {
83 | this._tooltipPortalHost.attach(this._templatePortal);
84 | }
85 | }
86 |
87 | /**
88 | * 隐藏
89 | */
90 | private hide() {
91 | this._tooltipPortalHost.detach();
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/src/app/scrolling/cdk-scrolling-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkScrollingComponent} from './cdk-scrolling.component';
5 |
6 |
7 | const routes: Routes = [
8 | {
9 | path: '',
10 | component: CdkScrollingComponent
11 | }
12 | ];
13 |
14 | @NgModule({
15 | imports: [
16 | RouterModule.forChild(routes),
17 | CommonModule
18 | ],
19 | exports: [
20 | RouterModule
21 | ],
22 | providers: []
23 | })
24 | export class CdkScrollingRoutingModule {
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/scrolling/cdk-scrolling.component.html:
--------------------------------------------------------------------------------
1 | cdk scrolling
2 |
3 |
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/app/scrolling/cdk-scrolling.component.less:
--------------------------------------------------------------------------------
1 | .scrolling-parent {
2 | height: 100px;
3 | width: 200px;
4 | border: 1px solid black;
5 | padding: 8px;
6 | overflow-y: auto;
7 | }
8 |
9 | .scrolling-item {
10 | height: 50px;
11 | }
--------------------------------------------------------------------------------
/src/app/scrolling/cdk-scrolling.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
2 | import {CdkScrollable, ScrollDispatcher, ViewportRuler} from '@angular/cdk/overlay';
3 |
4 | @Component({
5 | selector: 'app-cdk-scrolling',
6 | templateUrl: './cdk-scrolling.component.html',
7 | styleUrls: ['./cdk-scrolling.component.less']
8 | })
9 | export class CdkScrollingComponent implements OnInit, AfterViewInit {
10 |
11 | @ViewChild('scrollingParent')
12 | childDiv: ElementRef;
13 |
14 | constructor(private scrollDispatcher: ScrollDispatcher, private viewPortRuler: ViewportRuler) {
15 | }
16 |
17 | ngOnInit() {
18 | this.scrollDispatcher.scrolled().subscribe((scrollable: CdkScrollable) => {
19 | if (scrollable) {
20 | console.log('发生scroll了,來源于:');
21 | console.log(scrollable.getElementRef().nativeElement);
22 | }
23 | });
24 |
25 | /**
26 | * ViewportRuler 用来监听窗口的大小
27 | */
28 | // { width, height }
29 | console.log(this.viewPortRuler.getViewportSize());
30 |
31 | // { bottom, height, left, right, top, width }
32 | console.log(this.viewPortRuler.getViewportRect());
33 |
34 | // { top, left }
35 | console.log(this.viewPortRuler.getViewportScrollPosition());
36 |
37 | // native resize event object
38 | this.viewPortRuler.change().subscribe(resizeEvent => console.log(resizeEvent));
39 |
40 | }
41 |
42 | ngAfterViewInit(): void {
43 | /**
44 | * 第二个参数auditTimeInMs表示事件延时多少秒发生
45 | * 当祖先设置了cdkScrollable指令,在孩子里面也能抓到scrolling事件
46 | */
47 | this.scrollDispatcher.ancestorScrolled(this.childDiv).subscribe((scrollable: CdkScrollable) => {
48 | if (scrollable) {
49 | console.log('祖先发生scroll了,來源于:');
50 | console.log(scrollable.getElementRef().nativeElement);
51 | }
52 | });
53 |
54 | // 获取ScrollDispatcher里面所有注册了scrolling的组件信息
55 | console.log(this.scrollDispatcher.scrollContainers);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/app/scrolling/cdk-scrolling.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkScrollingRoutingModule} from './cdk-scrolling-routing.module';
4 | import {CdkScrollingComponent} from './cdk-scrolling.component';
5 | import {RouterModule} from '@angular/router';
6 | import {VirtualScrollComponent} from './virtual-scroll/virtual-scroll.component';
7 | import {ScrollingModule} from "@angular/cdk/scrolling";
8 | import {VirtualScrollDataSourceComponent} from './virtual-scroll-data-source/virtual-scroll-data-source.component';
9 | import {VirtualScrollHorizontalComponent} from './virtual-scroll-horizontal/virtual-scroll-horizontal.component';
10 | import {VirtualScrollStrategiesComponent} from './virtual-scroll-strategies/virtual-scroll-strategies.component';
11 | import {DragDropModule} from '@angular/cdk/drag-drop';
12 | import { DragScrollingComponent } from './drag-scrolling/drag-scrolling.component';
13 |
14 | @NgModule({
15 | imports: [
16 | CommonModule,
17 | RouterModule,
18 | DragDropModule,
19 | ScrollingModule,
20 | CdkScrollingRoutingModule
21 | ],
22 | declarations: [
23 | CdkScrollingComponent,
24 | VirtualScrollComponent,
25 | VirtualScrollDataSourceComponent,
26 | VirtualScrollHorizontalComponent,
27 | VirtualScrollStrategiesComponent,
28 | DragScrollingComponent
29 | ]
30 | })
31 | export class CdkScrollingModule {
32 | }
33 |
--------------------------------------------------------------------------------
/src/app/scrolling/drag-scrolling/drag-scrolling.component.html:
--------------------------------------------------------------------------------
1 |
2 | drag和scrolling结合使用
3 |
4 |
--------------------------------------------------------------------------------
/src/app/scrolling/drag-scrolling/drag-scrolling.component.less:
--------------------------------------------------------------------------------
1 | .example-list {
2 | width: 500px;
3 | max-width: 100%;
4 | border: solid 1px #ccc;
5 | min-height: 60px;
6 | display: block;
7 | background: white;
8 | border-radius: 4px;
9 | overflow: hidden;
10 | }
11 |
12 | .example-box {
13 | padding: 20px 10px;
14 | border-bottom: solid 1px #ccc;
15 | color: rgba(0, 0, 0, 0.87);
16 | display: flex;
17 | flex-direction: row;
18 | align-items: center;
19 | justify-content: space-between;
20 | box-sizing: border-box;
21 | cursor: move;
22 | background: white;
23 | font-size: 14px;
24 | }
25 |
26 | .cdk-drag-preview {
27 | box-sizing: border-box;
28 | border-radius: 4px;
29 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
30 | 0 8px 10px 1px rgba(0, 0, 0, 0.14),
31 | 0 3px 14px 2px rgba(0, 0, 0, 0.12);
32 | }
33 |
34 | .cdk-drag-placeholder {
35 | opacity: 0;
36 | }
37 |
38 | .cdk-drag-animating {
39 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
40 | }
41 |
42 | .example-box:last-child {
43 | border: none;
44 | }
45 |
46 | .example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
47 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
48 | }
--------------------------------------------------------------------------------
/src/app/scrolling/drag-scrolling/drag-scrolling.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, ElementRef, OnDestroy, QueryList, ViewChild, ViewChildren} from '@angular/core';
2 | import {CdkDrag, CdkDragDrop, CdkDragMove, moveItemInArray} from '@angular/cdk/drag-drop';
3 | import {merge, Subscription} from 'rxjs';
4 | import {map, startWith, switchMap, tap} from 'rxjs/operators';
5 |
6 | const speed = 10;
7 |
8 | @Component({
9 | selector: 'app-drag-scrolling',
10 | templateUrl: './drag-scrolling.component.html',
11 | styleUrls: ['./drag-scrolling.component.less']
12 | })
13 | export class DragScrollingComponent implements AfterViewInit, OnDestroy {
14 | movies = [
15 | 'Episode I - The Phantom Menace',
16 | 'Episode II - Attack of the Clones',
17 | 'Episode III - Revenge of the Sith',
18 | 'Episode IV - A New Hope',
19 | 'Episode V - The Empire Strikes Back',
20 | 'Episode VI - Return of the Jedi',
21 | 'Episode VII - The Force Awakens',
22 | 'Episode VIII - The Last Jedi',
23 | 'Rouge One',
24 | 'Solo',
25 | 'Clone Wars'
26 | ];
27 |
28 | animationFrame: number | undefined;
29 |
30 | @ViewChild('scrollEl')
31 | scrollEl: ElementRef;
32 |
33 | @ViewChildren(CdkDrag)
34 | dragEls: QueryList;
35 |
36 | subs = new Subscription();
37 |
38 | ngOnDestroy(): void {
39 | this.subs.unsubscribe();
40 | }
41 |
42 | ngAfterViewInit() {
43 | const onMove$ = this.dragEls.changes.pipe(
44 | startWith(this.dragEls)
45 | , map((d: QueryList) => d.toArray())
46 | , map(dragels => dragels.map(drag => drag.moved))
47 | , switchMap(obs => merge(...obs))
48 | , tap(this.triggerScroll)
49 | );
50 |
51 | this.subs.add(onMove$.subscribe());
52 |
53 | const onDown$ = this.dragEls.changes.pipe(
54 | startWith(this.dragEls)
55 | , map((d: QueryList) => d.toArray())
56 | , map(dragels => dragels.map(drag => drag.ended))
57 | , switchMap(obs => merge(...obs))
58 | , tap(this.cancelScroll)
59 | );
60 |
61 | this.subs.add(onDown$.subscribe());
62 | }
63 |
64 | drop(event: CdkDragDrop) {
65 | moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
66 | }
67 |
68 | public triggerScroll($event: CdkDragMove) {
69 | if (this.animationFrame) {
70 | cancelAnimationFrame(this.animationFrame);
71 | this.animationFrame = undefined;
72 | }
73 | this.animationFrame = requestAnimationFrame(() => this.scroll($event));
74 | }
75 |
76 | private cancelScroll() {
77 | if (this.animationFrame) {
78 | cancelAnimationFrame(this.animationFrame);
79 | this.animationFrame = undefined;
80 | }
81 | }
82 |
83 | private scroll($event: CdkDragMove) {
84 | const {y} = $event.pointerPosition;
85 | const baseEl = this.scrollEl.nativeElement;
86 | const box = baseEl.getBoundingClientRect();
87 | const scrollTop = baseEl.scrollTop;
88 | const top = box.top + -y;
89 | if (top > 0 && scrollTop !== 0) {
90 | const newScroll = scrollTop - speed * Math.exp(top / 50);
91 | baseEl.scrollTop = newScroll;
92 | this.animationFrame = requestAnimationFrame(() => this.scroll($event));
93 | return;
94 | }
95 |
96 | const bottom = y - box.bottom;
97 | if (bottom > 0 && scrollTop < box.bottom) {
98 | const newScroll = scrollTop + speed * Math.exp(bottom / 50);
99 | baseEl.scrollTop = newScroll;
100 | this.animationFrame = requestAnimationFrame(() => this.scroll($event));
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-data-source/customer-data-source.ts:
--------------------------------------------------------------------------------
1 | import {BehaviorSubject, Observable, Subscription} from "rxjs";
2 | import {CollectionViewer, DataSource} from "@angular/cdk/collections";
3 |
4 | export class CustomerDataSource extends DataSource{
5 |
6 | private length = 100000;
7 | private pageSize = 100;
8 | private cachedData = Array.from({length: this.length});
9 | private fetchedPages = new Set();
10 | private dataStream = new BehaviorSubject<(string | undefined)[]>(this.cachedData);
11 | private subscription = new Subscription();
12 |
13 | connect(collectionViewer: CollectionViewer): Observable<(string | undefined)[]> {
14 | this.subscription.add(collectionViewer.viewChange.subscribe(range => {
15 | const startPage = this.getPageForIndex(range.start);
16 | const endPage = this.getPageForIndex(range.end - 1);
17 | for (let i = startPage; i <= endPage; i++) {
18 | this.fetchPage(i);
19 | }
20 | }));
21 | return this.dataStream;
22 | }
23 |
24 | disconnect(): void {
25 | this.subscription.unsubscribe();
26 | }
27 |
28 | private getPageForIndex(index: number): number {
29 | return Math.floor(index / this.pageSize);
30 | }
31 |
32 | private fetchPage(page: number) {
33 | if (this.fetchedPages.has(page)) {
34 | return;
35 | }
36 | this.fetchedPages.add(page);
37 |
38 | // Use `setTimeout` to simulate fetching data from server.
39 | setTimeout(() => {
40 | this.cachedData.splice(page * this.pageSize, this.pageSize,
41 | ...Array.from({length: this.pageSize})
42 | .map((_, i) => `Item #${page * this.pageSize + i}`));
43 | this.dataStream.next(this.cachedData);
44 | }, Math.random() * 1000 + 200);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-data-source/virtual-scroll-data-source.component.html:
--------------------------------------------------------------------------------
1 |
2 | DataSource
3 |
4 | {{item || 'Loading...'}}
5 |
6 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-data-source/virtual-scroll-data-source.component.less:
--------------------------------------------------------------------------------
1 | .example-viewport {
2 | height: 200px;
3 | width: 200px;
4 | border: 1px solid black;
5 | }
6 |
7 | .example-item {
8 | height: 50px;
9 | }
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-data-source/virtual-scroll-data-source.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 | import {CustomerDataSource} from "./customer-data-source";
3 |
4 | @Component({
5 | selector: 'app-virtual-scroll-data-source',
6 | templateUrl: './virtual-scroll-data-source.component.html',
7 | styleUrls: ['./virtual-scroll-data-source.component.less']
8 | })
9 | export class VirtualScrollDataSourceComponent {
10 |
11 | ds = new CustomerDataSource();
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-horizontal/virtual-scroll-horizontal.component.html:
--------------------------------------------------------------------------------
1 |
2 | cdk-virtual-scroll-viewport horizontal
3 |
8 |
9 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-horizontal/virtual-scroll-horizontal.component.less:
--------------------------------------------------------------------------------
1 | .cdk-virtual-scroll-data-source-example .example-viewport {
2 | height: 200px;
3 | width: 200px;
4 | border: 1px solid black;
5 | }
6 |
7 | .cdk-virtual-scroll-data-source-example .example-viewport .cdk-virtual-scroll-content-wrapper {
8 | display: flex;
9 | flex-direction: row;
10 | }
11 |
12 | .cdk-virtual-scroll-data-source-example .example-item {
13 | width: 50px;
14 | height: 100%;
15 | writing-mode: vertical-lr;
16 | }
17 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-horizontal/virtual-scroll-horizontal.component.ts:
--------------------------------------------------------------------------------
1 | import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-virtual-scroll-horizontal',
5 | templateUrl: './virtual-scroll-horizontal.component.html',
6 | styleUrls: ['./virtual-scroll-horizontal.component.less'],
7 | encapsulation: ViewEncapsulation.None,
8 | changeDetection: ChangeDetectionStrategy.OnPush,
9 | })
10 | export class VirtualScrollHorizontalComponent {
11 |
12 | items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-strategies/custom-virtual-scroll-strategies.ts:
--------------------------------------------------------------------------------
1 | import {FixedSizeVirtualScrollStrategy} from "@angular/cdk/scrolling";
2 |
3 | export class CustomVirtualScrollStrategies extends FixedSizeVirtualScrollStrategy {
4 | constructor() {
5 | super(50, 250, 500);
6 | }
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-strategies/virtual-scroll-strategies.component.html:
--------------------------------------------------------------------------------
1 |
2 | 通过provider提供缓存策略
3 |
4 | {{item}}
5 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-strategies/virtual-scroll-strategies.component.less:
--------------------------------------------------------------------------------
1 | .example-viewport {
2 | height: 200px;
3 | width: 200px;
4 | border: 1px solid black;
5 | }
6 |
7 | .example-item {
8 | height: 50px;
9 | }
10 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll-strategies/virtual-scroll-strategies.component.ts:
--------------------------------------------------------------------------------
1 | import {ChangeDetectionStrategy, Component} from '@angular/core';
2 | import {VIRTUAL_SCROLL_STRATEGY} from "@angular/cdk/scrolling";
3 | import {CustomVirtualScrollStrategies} from "./custom-virtual-scroll-strategies";
4 |
5 | @Component({
6 | selector: 'app-virtual-scroll-strategies',
7 | templateUrl: './virtual-scroll-strategies.component.html',
8 | styleUrls: ['./virtual-scroll-strategies.component.less'],
9 | changeDetection: ChangeDetectionStrategy.OnPush,
10 | providers: [{provide: VIRTUAL_SCROLL_STRATEGY, useClass: CustomVirtualScrollStrategies}]
11 | })
12 | export class VirtualScrollStrategiesComponent {
13 |
14 | items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll/virtual-scroll.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
cdk-virtual-scroll-viewport组件使用
4 |
5 |
12 |
Item: {{item}}
13 |
Index: {{index}}
14 |
Count: {{count}}
15 |
First: {{first ? 'Yes' : 'No'}}
16 |
Last: {{last ? 'Yes' : 'No'}}
17 |
Even: {{even ? 'Yes' : 'No'}}
18 |
Odd: {{odd ? 'Yes' : 'No'}}
19 |
20 |
21 |
22 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll/virtual-scroll.component.less:
--------------------------------------------------------------------------------
1 | .example-viewport {
2 | height: 200px;
3 | width: 200px;
4 | border: 1px solid black;
5 | }
6 |
7 | .example-item-detail {
8 | height: 18px;
9 | }
10 |
11 | .example-alternate {
12 | background: rgba(127, 127, 127, 0.3);
13 | }
--------------------------------------------------------------------------------
/src/app/scrolling/virtual-scroll/virtual-scroll.component.ts:
--------------------------------------------------------------------------------
1 | import {AfterViewInit, Component, ViewChild} from '@angular/core';
2 | import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling";
3 |
4 | @Component({
5 | selector: 'app-virtual-scroll',
6 | templateUrl: './virtual-scroll.component.html',
7 | styleUrls: ['./virtual-scroll.component.less']
8 | })
9 | export class VirtualScrollComponent implements AfterViewInit{
10 |
11 | @ViewChild('scrollComponent')
12 | private _scrollViewport: CdkVirtualScrollViewport;
13 |
14 | items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
15 |
16 | ngAfterViewInit(): void {
17 | }
18 |
19 | onButtonClick() {
20 | this._scrollViewport.scrollToIndex(10);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/app/table/cdk-base-table-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from '@angular/router';
4 | import {CdkBaseTableComponent} from './cdk-base-table.component';
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: CdkBaseTableComponent
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [
15 | RouterModule.forChild(routes),
16 | CommonModule
17 | ],
18 | exports: [
19 | RouterModule
20 | ],
21 | providers: []
22 | })
23 | export class CdkBaseTableRoutingModule { }
24 |
--------------------------------------------------------------------------------
/src/app/table/cdk-base-table.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | No. |
7 | {{element.position}} |
8 |
9 |
10 |
11 |
12 | Name |
13 | {{element.name}} |
14 |
15 |
16 |
17 |
18 | Weight |
19 | {{element.weight}} |
20 |
21 |
22 |
23 |
24 | Symbol |
25 | {{element.symbol}} |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/app/table/cdk-base-table.component.less:
--------------------------------------------------------------------------------
1 | table {
2 | width: 100%;
3 | }
4 |
5 | th {
6 | text-align: left;
7 | }
8 |
--------------------------------------------------------------------------------
/src/app/table/cdk-base-table.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import {DataSource} from '@angular/cdk/table';
3 | import {BehaviorSubject, Observable} from 'rxjs';
4 |
5 | export interface PeriodicElement {
6 | name: string;
7 | position: number;
8 | weight: number;
9 | symbol: string;
10 | }
11 |
12 | const ELEMENT_DATA: PeriodicElement[] = [
13 | {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
14 | {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
15 | {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
16 | {position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
17 | {position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
18 | {position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'},
19 | {position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N'},
20 | {position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'},
21 | {position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'},
22 | {position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'},
23 | ];
24 |
25 | @Component({
26 | selector: 'app-cdk-table',
27 | templateUrl: './cdk-base-table.component.html',
28 | styleUrls: ['./cdk-base-table.component.less']
29 | })
30 | export class CdkBaseTableComponent {
31 |
32 | displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
33 | dataSource = new ExampleDataSource();
34 |
35 | }
36 |
37 | /**
38 | * Data source to provide what data should be rendered in the table. Note that the data source
39 | * can retrieve its data in any way. In this case, the data source is provided a reference
40 | * to a common data base, ExampleDatabase. It is not the data source's responsibility to manage
41 | * the underlying data. Instead, it only needs to take the data and send the table exactly what
42 | * should be rendered.
43 | */
44 | export class ExampleDataSource extends DataSource {
45 | /** Stream of data that is provided to the table. */
46 | data = new BehaviorSubject(ELEMENT_DATA);
47 |
48 | /** Connect function called by the table to retrieve one stream containing the data to render. */
49 | connect(): Observable {
50 | return this.data;
51 | }
52 |
53 | disconnect() {}
54 | }
55 |
--------------------------------------------------------------------------------
/src/app/table/cdk-base-table.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkBaseTableComponent} from './cdk-base-table.component';
4 | import {CdkBaseTableRoutingModule} from './cdk-base-table-routing.module';
5 | import {CdkTableModule} from '@angular/cdk/table';
6 |
7 | @NgModule({
8 | imports: [
9 | CommonModule,
10 | CdkTableModule,
11 | CdkBaseTableRoutingModule
12 | ],
13 | declarations: [CdkBaseTableComponent]
14 | })
15 | export class CdkBaseTableModule {
16 | }
17 |
--------------------------------------------------------------------------------
/src/app/text-field/cdk-text-field-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from "@angular/router";
4 | import {CdkTextFieldComponent} from "./cdk-text-field.component";
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: CdkTextFieldComponent
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [
15 | RouterModule.forChild(routes),
16 | CommonModule
17 | ],
18 | exports: [
19 | RouterModule
20 | ],
21 | providers: []
22 | })
23 | export class CdkTextFieldRoutingModule { }
24 |
--------------------------------------------------------------------------------
/src/app/text-field/cdk-text-field.component.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/app/text-field/cdk-text-field.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/text-field/cdk-text-field.component.less
--------------------------------------------------------------------------------
/src/app/text-field/cdk-text-field.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild} from '@angular/core';
2 | import {AutofillMonitor, CdkTextareaAutosize} from "@angular/cdk/text-field";
3 | import {take} from "rxjs/operators";
4 |
5 | @Component({
6 | selector: 'app-cdk-text-field',
7 | templateUrl: './cdk-text-field.component.html',
8 | styleUrls: ['./cdk-text-field.component.less']
9 | })
10 | export class CdkTextFieldComponent implements OnDestroy, OnInit {
11 | @ViewChild('autosize') autosize: CdkTextareaAutosize;
12 | @ViewChild('first', {read: ElementRef}) firstName: ElementRef;
13 | @ViewChild('last', {read: ElementRef}) lastName: ElementRef;
14 | firstNameAutofilled: boolean;
15 | lastNameAutofilled: boolean;
16 |
17 |
18 | constructor(private ngZone: NgZone, private autofill: AutofillMonitor) {
19 | }
20 |
21 | ngOnInit() {
22 | this.autofill.monitor(this.firstName)
23 | .subscribe(e => this.firstNameAutofilled = e.isAutofilled);
24 | this.autofill.monitor(this.lastName)
25 | .subscribe(e => this.lastNameAutofilled = e.isAutofilled);
26 | }
27 |
28 | ngOnDestroy() {
29 | this.autofill.stopMonitoring(this.firstName);
30 | this.autofill.stopMonitoring(this.lastName);
31 | }
32 |
33 | /**
34 | * 外部调用触发调整大小的逻辑,比如当fontSize改变之后,调用该函数
35 | */
36 | triggerResize() {
37 | // 重新适应内容,比如fontSize改变了,可以调用该方法重新适应内容
38 | this.ngZone.onStable.pipe(take(1))
39 | .subscribe(() => this.autosize.resizeToFitContent(true));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/app/text-field/cdk-text-field.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkTextFieldComponent} from './cdk-text-field.component';
4 | import {CdkTextFieldRoutingModule} from "./cdk-text-field-routing.module";
5 | import {RouterModule} from "@angular/router";
6 | import {TextFieldModule} from "@angular/cdk/text-field";
7 |
8 | @NgModule({
9 | imports: [
10 | CommonModule,
11 | RouterModule,
12 | TextFieldModule,
13 | CdkTextFieldRoutingModule
14 | ],
15 | declarations: [CdkTextFieldComponent]
16 | })
17 | export class CdkTextFieldModule {
18 | }
19 |
--------------------------------------------------------------------------------
/src/app/tip/tip.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/app/tip/tip.component.less:
--------------------------------------------------------------------------------
1 | .tooltip-example {
2 | text-align: center;
3 | padding: 0 50px;
4 | }
5 |
6 | .tooltip-example [appTip] {
7 | display: inline-block;
8 | margin: 50px 20px;
9 | width: 180px;
10 | height: 50px;
11 | border: 1px solid gray;
12 | border-radius: 5px;
13 | line-height: 50px;
14 | text-align: center;
15 | }
--------------------------------------------------------------------------------
/src/app/tip/tip.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-tip',
5 | templateUrl: './tip.component.html',
6 | styleUrls: ['./tip.component.less']
7 | })
8 | export class TipComponent {
9 |
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/app/tip/tip.directive.ts:
--------------------------------------------------------------------------------
1 | import {Directive, ElementRef, HostListener, Input, Renderer2} from '@angular/core';
2 |
3 | @Directive({
4 | selector: '[appTip]'
5 | })
6 | export class TipDirective {
7 |
8 | @Input() tooltipTitle: string;
9 | @Input() placement: string;
10 | @Input() delay: string;
11 | tooltip: HTMLElement;
12 | offset = 10;
13 |
14 | constructor(private el: ElementRef, private renderer: Renderer2) {
15 | }
16 |
17 | @HostListener('mouseenter') onMouseEnter() {
18 | if (!this.tooltip) {
19 | this.show();
20 | }
21 | }
22 |
23 | @HostListener('mouseleave') onMouseLeave() {
24 | if (this.tooltip) {
25 | this.hide();
26 | }
27 | }
28 |
29 | show() {
30 | this.create();
31 | this.setPosition();
32 | this.renderer.addClass(this.tooltip, 'ng-tooltip-show');
33 | }
34 |
35 | hide() {
36 | this.renderer.removeClass(this.tooltip, 'ng-tooltip-show');
37 | window.setTimeout(() => {
38 | this.renderer.removeChild(document.body, this.tooltip);
39 | this.tooltip = null;
40 | }, this.delay);
41 | }
42 |
43 | create() {
44 | this.tooltip = this.renderer.createElement('span');
45 |
46 | this.renderer.appendChild(
47 | this.tooltip,
48 | this.renderer.createText(this.tooltipTitle) // textNode
49 | );
50 |
51 | this.renderer.appendChild(document.body, this.tooltip);
52 | // this.renderer.appendChild(this.el.nativeElement, this.tooltip);
53 |
54 | this.renderer.addClass(this.tooltip, 'ng-tooltip');
55 | this.renderer.addClass(this.tooltip, `ng-tooltip-${this.placement}`);
56 |
57 | // delay
58 | this.renderer.setStyle(this.tooltip, '-webkit-transition', `opacity ${this.delay}ms`);
59 | this.renderer.setStyle(this.tooltip, '-moz-transition', `opacity ${this.delay}ms`);
60 | this.renderer.setStyle(this.tooltip, '-o-transition', `opacity ${this.delay}ms`);
61 | this.renderer.setStyle(this.tooltip, 'transition', `opacity ${this.delay}ms`);
62 | }
63 |
64 | setPosition() {
65 | const hostPos = this.el.nativeElement.getBoundingClientRect();
66 |
67 | // tooltip
68 | const tooltipPos = this.tooltip.getBoundingClientRect();
69 |
70 | // getBoundingClientRect
71 | const scrollPos = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
72 |
73 | let top, left;
74 |
75 | if (this.placement === 'top') {
76 | top = hostPos.top - tooltipPos.height - this.offset;
77 | left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
78 | }
79 |
80 | if (this.placement === 'bottom') {
81 | top = hostPos.bottom + this.offset;
82 | left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
83 | }
84 |
85 | if (this.placement === 'left') {
86 | top = hostPos.top + (hostPos.height - tooltipPos.height) / 2;
87 | left = hostPos.left - tooltipPos.width - this.offset;
88 | }
89 |
90 | if (this.placement === 'right') {
91 | top = hostPos.top + (hostPos.height - tooltipPos.height) / 2;
92 | left = hostPos.right + this.offset;
93 | }
94 |
95 | this.renderer.setStyle(this.tooltip, 'top', `${top + scrollPos}px`);
96 | this.renderer.setStyle(this.tooltip, 'left', `${left}px`);
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/app/workflow-stepper/cdk-workflow-stepper-routing.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {RouterModule, Routes} from "@angular/router";
4 | import {CdkWorkflowStepperComponent} from "./cdk-workflow-stepper.component";
5 |
6 | const routes: Routes = [
7 | {
8 | path: '',
9 | component: CdkWorkflowStepperComponent
10 | }
11 | ];
12 |
13 | @NgModule({
14 | imports: [
15 | RouterModule.forChild(routes),
16 | CommonModule
17 | ],
18 | exports: [
19 | RouterModule
20 | ],
21 | providers: []
22 | })
23 | export class CdkWorkflowStepperRoutingModule { }
24 |
--------------------------------------------------------------------------------
/src/app/workflow-stepper/cdk-workflow-stepper.component.html:
--------------------------------------------------------------------------------
1 | cdk stepper
2 |
3 |
4 | 第一步
5 |
8 |
9 |
10 |
11 | 第二步
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/app/workflow-stepper/cdk-workflow-stepper.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/app/workflow-stepper/cdk-workflow-stepper.component.less
--------------------------------------------------------------------------------
/src/app/workflow-stepper/cdk-workflow-stepper.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit, ViewChild} from '@angular/core';
2 | import {FormControl} from '@angular/forms';
3 | import {CdkStep, CdkStepper} from '@angular/cdk/stepper';
4 |
5 | @Component({
6 | selector: 'app-cdk-workflow-stepper',
7 | templateUrl: './cdk-workflow-stepper.component.html',
8 | styleUrls: ['./cdk-workflow-stepper.component.less']
9 | })
10 | export class CdkWorkflowStepperComponent {
11 |
12 | name = 'Angular 5';
13 | form1 = new FormControl();
14 | @ViewChild('stepper') stepper: CdkStepper;
15 | @ViewChild('step1') step1: CdkStep;
16 | @ViewChild('step2') step2: CdkStep;
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/app/workflow-stepper/cdk-workflow-stepper.module.ts:
--------------------------------------------------------------------------------
1 | import {NgModule} from '@angular/core';
2 | import {CommonModule} from '@angular/common';
3 | import {CdkWorkflowStepperComponent} from './cdk-workflow-stepper.component';
4 | import {CdkWorkflowStepperRoutingModule} from './cdk-workflow-stepper-routing.module';
5 | import {CdkStepperModule} from '@angular/cdk/stepper';
6 | import {StepperComponent} from './stepper/stepper.component';
7 | import {FormsModule} from '@angular/forms';
8 | import {StepperHeaderComponent} from './stepper/stepper-header.component';
9 |
10 | @NgModule({
11 | imports: [
12 | CommonModule,
13 | FormsModule,
14 | CdkStepperModule,
15 | CdkWorkflowStepperRoutingModule
16 | ],
17 | declarations: [CdkWorkflowStepperComponent, StepperComponent, StepperHeaderComponent]
18 | })
19 | export class CdkWorkflowStepperModule {
20 | }
21 |
--------------------------------------------------------------------------------
/src/app/workflow-stepper/stepper/stepper-animations.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * Copyright Google LLC All Rights Reserved.
4 | *
5 | * Use of this source code is governed by an MIT-style license that can be
6 | * found in the LICENSE file at https://angular.io/license
7 | */
8 | import {
9 | animate,
10 | state,
11 | style,
12 | transition,
13 | trigger,
14 | AnimationTriggerMetadata,
15 | } from '@angular/animations';
16 |
17 | /**
18 | * Animations used by the Material steppers.
19 | * @docs-private
20 | */
21 | export const yxStepperAnimations: {
22 | readonly horizontalStepTransition: AnimationTriggerMetadata;
23 | readonly verticalStepTransition: AnimationTriggerMetadata;
24 | } = {
25 | /** Animation that transitions the step along the X axis in a horizontal stepper. */
26 | horizontalStepTransition: trigger('stepTransition', [
27 | state('previous', style({transform: 'translate3d(-100%, 0, 0)', visibility: 'hidden'})),
28 | state('current', style({transform: 'none', visibility: 'visible'})),
29 | state('next', style({transform: 'translate3d(100%, 0, 0)', visibility: 'hidden'})),
30 | transition('* => *', animate('500ms cubic-bezier(0.35, 0, 0.25, 1)'))
31 | ]),
32 |
33 | /** Animation that transitions the step along the Y axis in a vertical stepper. */
34 | verticalStepTransition: trigger('stepTransition', [
35 | state('previous', style({height: '0px', visibility: 'hidden'})),
36 | state('next', style({height: '0px', visibility: 'hidden'})),
37 | state('current', style({height: '*', visibility: 'visible'})),
38 | transition('* <=> current', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
39 | ])
40 | };
--------------------------------------------------------------------------------
/src/app/workflow-stepper/stepper/stepper-header.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{index + 1}}
7 |
8 |
9 |
10 | {{index + 1}}
11 |
12 |
13 |
14 | {{index + 1}}
15 |
16 |
17 |
18 | {{index + 1}}
19 |
20 |
21 |
22 | {{index + 1}}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
{{label}}
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/app/workflow-stepper/stepper/stepper-header.component.less:
--------------------------------------------------------------------------------
1 | .yx-step-icon {
2 | border-radius: 50%;
3 | height: 24px;
4 | width: 24px;
5 | flex-shrink: 0;
6 | position: relative;
7 | }
8 |
9 | .yx-step-icon-content {
10 | // Use absolute positioning to center the content, because it works better with text.
11 | position: absolute;
12 | top: 50%;
13 | left: 50%;
14 | transform: translate(-50%, -50%);
15 | }
16 |
17 | .yx-step-label {
18 | display: inline-block;
19 | white-space: nowrap;
20 | overflow: hidden;
21 | text-overflow: ellipsis;
22 | min-width: 50px;
23 | vertical-align: middle;
24 | }
--------------------------------------------------------------------------------
/src/app/workflow-stepper/stepper/stepper-header.component.ts:
--------------------------------------------------------------------------------
1 | import {ChangeDetectorRef, Component, ElementRef, Input, OnDestroy} from '@angular/core';
2 | import {CdkStepHeader, CdkStepLabel, StepState} from '@angular/cdk/stepper';
3 | import {FocusMonitor} from '@angular/cdk/a11y';
4 |
5 | @Component({
6 | selector: 'yx-stepper-header',
7 | templateUrl: './stepper-header.component.html',
8 | styleUrls: ['./stepper-header.component.less']
9 | })
10 | export class StepperHeaderComponent extends CdkStepHeader implements OnDestroy {
11 |
12 | /** State of the given step. */
13 | @Input() state: StepState;
14 |
15 | /** Label of the given step. */
16 | @Input() label: CdkStepLabel | string;
17 |
18 | /** Index of the given step. */
19 | @Input() index: number;
20 |
21 | /** Whether the given step is selected. */
22 | @Input() selected: boolean;
23 |
24 | /** Whether the given step label is active. */
25 | @Input() active: boolean;
26 |
27 | /** Whether the given step is optional. */
28 | @Input() optional: boolean;
29 |
30 | constructor(
31 | private _focusMonitor: FocusMonitor,
32 | _elementRef: ElementRef,
33 | changeDetectorRef: ChangeDetectorRef) {
34 | super(_elementRef);
35 | _focusMonitor.monitor(_elementRef, true);
36 | }
37 |
38 | ngOnDestroy() {
39 | this._focusMonitor.stopMonitoring(this._elementRef);
40 | }
41 |
42 | /** Returns the host HTML element. */
43 | _getHostElement() {
44 | return this._elementRef.nativeElement;
45 | }
46 |
47 | /** Returns MatStepLabel if the label of given step is a template label. */
48 | _templateLabel(): CdkStepLabel | null {
49 | return this.label instanceof CdkStepLabel ? this.label : null;
50 | }
51 |
52 | /** Returns string label of given step if it is a text label. */
53 | _stringLabel(): string | null {
54 | return this.label instanceof CdkStepLabel ? null : this.label;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/app/workflow-stepper/stepper/stepper.component.html:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
26 |
38 |
--------------------------------------------------------------------------------
/src/app/workflow-stepper/stepper/stepper.component.less:
--------------------------------------------------------------------------------
1 | .yx-stepper-header-container {
2 | white-space: nowrap;
3 | display: flex;
4 | align-items: center;
5 | }
6 |
7 | .yx-stepper-header {
8 | display: flex;
9 | height: 24px;
10 | overflow: hidden;
11 | align-items: center;
12 | padding: 0 24px;
13 | }
14 |
15 | .yx-content-container {
16 | overflow: hidden;
17 | }
18 |
19 | /**
20 | 保证值显示一个step
21 | */
22 | .yx-stepper-content[aria-expanded='false'] {
23 | height: 0;
24 | overflow: hidden;
25 | }
--------------------------------------------------------------------------------
/src/app/workflow-stepper/stepper/stepper.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AfterContentInit,
3 | ChangeDetectionStrategy,
4 | Component,
5 | ContentChildren,
6 | EventEmitter,
7 | Output,
8 | QueryList,
9 | ViewEncapsulation
10 | } from '@angular/core';
11 | import {AnimationEvent} from '@angular/animations';
12 | import {CdkStep, CdkStepper, StepContentPositionState} from '@angular/cdk/stepper';
13 | import {Subject} from 'rxjs';
14 | import {distinctUntilChanged, takeUntil} from 'rxjs/operators';
15 | import {yxStepperAnimations} from './stepper-animations';
16 |
17 | @Component({
18 | selector: 'yx-stepper',
19 | templateUrl: './stepper.component.html',
20 | styleUrls: ['./stepper.component.less'],
21 | providers: [{provide: CdkStepper, useExisting: StepperComponent}],
22 | animations: [yxStepperAnimations.horizontalStepTransition],
23 | encapsulation: ViewEncapsulation.None,
24 | changeDetection: ChangeDetectionStrategy.OnPush,
25 | })
26 | export class StepperComponent extends CdkStepper implements AfterContentInit {
27 |
28 | /** Steps that the stepper holds. */
29 | @ContentChildren(CdkStep) _steps: QueryList;
30 |
31 | /** Event emitted when the current step is done transitioning in. */
32 | @Output() readonly animationDone: EventEmitter = new EventEmitter();
33 |
34 | _animationDone = new Subject();
35 |
36 | ngAfterContentInit() {
37 |
38 | // Mark the component for change detection whenever the content children query changes
39 | this._steps.changes.pipe(takeUntil(this._destroyed)).subscribe(() => this._stateChanged());
40 |
41 | this._animationDone.pipe(
42 | // This needs a `distinctUntilChanged` in order to avoid emitting the same event twice due
43 | // to a bug in animations where the `.done` callback gets invoked twice on some browsers.
44 | // See https://github.com/angular/angular/issues/24084
45 | distinctUntilChanged((x, y) => x.fromState === y.fromState && x.toState === y.toState),
46 | takeUntil(this._destroyed)
47 | ).subscribe(event => {
48 | if ((event.toState as StepContentPositionState) === 'current') {
49 | this.animationDone.emit();
50 | }
51 | });
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/browserslist:
--------------------------------------------------------------------------------
1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed
5 | > 0.5%
6 | last 2 versions
7 | Firefox ESR
8 | not dead
9 | # IE 9-11
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false
7 | };
8 |
9 | /*
10 | * In development mode, to ignore zone related error stack frames such as
11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
12 | * import the following file, but please comment it out in production mode
13 | * because it will have performance impact when throw error
14 | */
15 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI.
16 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tuacy/angular-cdk-study/83abe74d0a6473d544ab3320fe696c654642da80/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AngularCdkStudy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, '../coverage'),
20 | reports: ['html', 'lcovonly'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false
30 | });
31 | };
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule)
12 | .catch(err => console.log(err));
13 |
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/weak-map';
35 | // import 'core-js/es6/set';
36 |
37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
38 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
39 |
40 | /** IE10 and IE11 requires the following for the Reflect API. */
41 | // import 'core-js/es6/reflect';
42 |
43 |
44 | /** Evergreen browsers require these. **/
45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
46 | import 'core-js/es7/reflect';
47 |
48 |
49 | /**
50 | * Web Animations `@angular/platform-browser/animations`
51 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
52 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
53 | **/
54 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
55 |
56 | /**
57 | * By default, zone.js will patch all possible macroTask and DomEvents
58 | * user can disable parts of macroTask/DomEvents patch by setting following flags
59 | */
60 |
61 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
62 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
63 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
64 |
65 | /*
66 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
67 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
68 | */
69 | // (window as any).__Zone_enable_cross_context_check = true;
70 |
71 | /***************************************************************************************************
72 | * Zone JS is required by default for Angular itself.
73 | */
74 | import 'zone.js/dist/zone'; // Included with Angular CLI.
75 |
76 |
77 |
78 | /***************************************************************************************************
79 | * APPLICATION IMPORTS
80 | */
81 |
--------------------------------------------------------------------------------
/src/styles.less:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | /* Master Styles */
3 | @import '~@angular/cdk/overlay-prebuilt.css';
4 |
5 | h1 {
6 | color: #369;
7 | font-family: Arial, Helvetica, sans-serif;
8 | font-size: 250%;
9 | }
10 | h2, h3 {
11 | color: #444;
12 | font-family: Arial, Helvetica, sans-serif;
13 | font-weight: lighter;
14 | }
15 | body {
16 | margin: 2em;
17 | }
18 | body, input[text], button {
19 | color: #888;
20 | font-family: Cambria, Georgia;
21 | }
22 | a {
23 | cursor: pointer;
24 | cursor: hand;
25 | }
26 | button {
27 | font-family: Arial;
28 | background-color: #eee;
29 | border: none;
30 | padding: 5px 10px;
31 | border-radius: 4px;
32 | cursor: pointer;
33 | cursor: hand;
34 | }
35 | button:hover {
36 | background-color: #cfd8dc;
37 | }
38 | button:disabled {
39 | background-color: #eee;
40 | color: #aaa;
41 | cursor: auto;
42 | }
43 |
44 | /* Navigation link styles */
45 | nav a {
46 | padding: 5px 10px;
47 | text-decoration: none;
48 | margin-right: 10px;
49 | margin-top: 10px;
50 | display: inline-block;
51 | background-color: #eee;
52 | border-radius: 4px;
53 | }
54 | nav a:visited, a:link {
55 | color: #607D8B;
56 | }
57 | nav a:hover {
58 | color: #039be5;
59 | background-color: #CFD8DC;
60 | }
61 | nav a.active {
62 | color: #039be5;
63 | }
64 |
65 | /* everywhere else */
66 | * {
67 | font-family: Arial, Helvetica, sans-serif;
68 | }
69 |
70 | .badge {
71 | display: inline-block;
72 | min-width: 10px;
73 | padding: 3px 7px;
74 | font-size: 12px;
75 | font-weight: bold;
76 | line-height: 1;
77 | color: #fff;
78 | text-align: center;
79 | white-space: nowrap;
80 | vertical-align: middle;
81 | background-color: #777;
82 | border-radius: 10px;
83 | }
84 |
85 | .ng-tooltip {
86 | position: absolute;
87 | max-width: 150px;
88 | font-size: 14px;
89 | text-align: center;
90 | color: #f8f8f2;
91 | padding: 3px 8px;
92 | background: #282a36;
93 | border-radius: 4px;
94 | z-index: 1000;
95 | opacity: 0;
96 | }
97 |
98 | .ng-tooltip:after {
99 | content: "";
100 | position: absolute;
101 | border-style: solid;
102 | }
103 |
104 | .ng-tooltip-top:after {
105 | top: 100%;
106 | left: 50%;
107 | margin-left: -5px;
108 | border-width: 5px;
109 | border-color: black transparent transparent transparent;
110 | }
111 |
112 | .ng-tooltip-bottom:after {
113 | bottom: 100%;
114 | left: 50%;
115 | margin-left: -5px;
116 | border-width: 5px;
117 | border-color: transparent transparent black transparent;
118 | }
119 |
120 | .ng-tooltip-left:after {
121 | top: 50%;
122 | left: 100%;
123 | margin-top: -5px;
124 | border-width: 5px;
125 | border-color: transparent transparent transparent black;
126 | }
127 |
128 | .ng-tooltip-right:after {
129 | top: 50%;
130 | right: 100%;
131 | margin-top: -5px;
132 | border-width: 5px;
133 | border-color: transparent black transparent transparent;
134 | }
135 |
136 | .ng-tooltip-show {
137 | opacity: 1;
138 | }
--------------------------------------------------------------------------------
/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: any;
11 |
12 | // First, initialize the Angular testing environment.
13 | getTestBed().initTestEnvironment(
14 | BrowserDynamicTestingModule,
15 | platformBrowserDynamicTesting()
16 | );
17 | // Then we find all the tests.
18 | const context = require.context('./', true, /\.spec\.ts$/);
19 | // And load the modules.
20 | context.keys().map(context);
21 |
--------------------------------------------------------------------------------
/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "module": "es2015",
6 | "types": []
7 | },
8 | "exclude": [
9 | "src/test.ts",
10 | "**/*.spec.ts"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/spec",
5 | "module": "commonjs",
6 | "types": [
7 | "jasmine",
8 | "node"
9 | ]
10 | },
11 | "files": [
12 | "test.ts",
13 | "polyfills.ts"
14 | ],
15 | "include": [
16 | "**/*.spec.ts",
17 | "**/*.d.ts"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/src/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tslint.json",
3 | "rules": {
4 | "directive-selector": [
5 | false,
6 | "attribute",
7 | "app",
8 | "camelCase"
9 | ],
10 | "component-selector": [
11 | false,
12 | "element",
13 | "app",
14 | "kebab-case"
15 | ]
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "sourceMap": true,
7 | "declaration": false,
8 | "moduleResolution": "node",
9 | "emitDecoratorMetadata": true,
10 | "experimentalDecorators": true,
11 | "target": "es5",
12 | "typeRoots": [
13 | "node_modules/@types"
14 | ],
15 | "lib": [
16 | "es2017",
17 | "dom"
18 | ]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "arrow-return-shorthand": true,
7 | "callable-types": true,
8 | "class-name": true,
9 | "comment-format": [
10 | true,
11 | "check-space"
12 | ],
13 | "curly": true,
14 | "deprecation": {
15 | "severity": "warn"
16 | },
17 | "eofline": true,
18 | "forin": true,
19 | "import-blacklist": [
20 | true,
21 | "rxjs/Rx"
22 | ],
23 | "import-spacing": true,
24 | "indent": [
25 | true,
26 | "spaces"
27 | ],
28 | "interface-over-type-literal": true,
29 | "label-position": true,
30 | "max-line-length": [
31 | true,
32 | 140
33 | ],
34 | "member-access": false,
35 | "member-ordering": [
36 | true,
37 | {
38 | "order": [
39 | "static-field",
40 | "instance-field",
41 | "static-method",
42 | "instance-method"
43 | ]
44 | }
45 | ],
46 | "no-arg": true,
47 | "no-bitwise": true,
48 | "no-console": [
49 | true,
50 | "debug",
51 | "info",
52 | "time",
53 | "timeEnd",
54 | "trace"
55 | ],
56 | "no-construct": true,
57 | "no-debugger": true,
58 | "no-duplicate-super": true,
59 | "no-empty": false,
60 | "no-empty-interface": true,
61 | "no-eval": true,
62 | "no-inferrable-types": [
63 | true,
64 | "ignore-params"
65 | ],
66 | "no-misused-new": true,
67 | "no-non-null-assertion": true,
68 | "no-shadowed-variable": true,
69 | "no-string-literal": false,
70 | "no-string-throw": true,
71 | "no-switch-case-fall-through": true,
72 | "no-trailing-whitespace": true,
73 | "no-unnecessary-initializer": true,
74 | "no-unused-expression": true,
75 | "no-use-before-declare": true,
76 | "no-var-keyword": true,
77 | "object-literal-sort-keys": false,
78 | "one-line": [
79 | true,
80 | "check-open-brace",
81 | "check-catch",
82 | "check-else",
83 | "check-whitespace"
84 | ],
85 | "prefer-const": true,
86 | "quotemark": [
87 | false,
88 | "single"
89 | ],
90 | "radix": true,
91 | "semicolon": [
92 | true,
93 | "always"
94 | ],
95 | "triple-equals": [
96 | true,
97 | "allow-null-check"
98 | ],
99 | "typedef-whitespace": [
100 | true,
101 | {
102 | "call-signature": "nospace",
103 | "index-signature": "nospace",
104 | "parameter": "nospace",
105 | "property-declaration": "nospace",
106 | "variable-declaration": "nospace"
107 | }
108 | ],
109 | "unified-signatures": true,
110 | "variable-name": false,
111 | "whitespace": [
112 | true,
113 | "check-branch",
114 | "check-decl",
115 | "check-operator",
116 | "check-separator",
117 | "check-type"
118 | ],
119 | "no-output-on-prefix": true,
120 | "use-input-property-decorator": true,
121 | "use-output-property-decorator": true,
122 | "use-host-property-decorator": true,
123 | "no-input-rename": true,
124 | "no-output-rename": true,
125 | "use-life-cycle-interface": true,
126 | "use-pipe-transform-interface": true,
127 | "component-class-suffix": true,
128 | "directive-class-suffix": true
129 | }
130 | }
131 |
--------------------------------------------------------------------------------