天天看點

Angular使用cli生成自定義檔案、元件

不得不說,和傳統的複制黏貼來建立元件的方法相比,使用angular-cli的腳手架功能來建立子產品、元件顯得非常高效,不僅僅有了建立了檔案,還包含了一些必須的代碼,同時也将元件導入了最近的子產品,一些重複性工作就使用cli可以節省掉。angular提供了豐富的檔案類型,但是總歸是有些我們自己的項目需要,我們需要建立自定義字尾的元件,這時候就不得不舍棄cli了,那麼能不能使用自定義的方式來達到腳手架建立呢?

angular 腳手架建立的方式

我們首先來看看angular-cli提供的一些指令是怎麼建立檔案的。

看angular文檔我們可以看到這個詞:

Schematic

,這個詞意為原理圖。

Schematic

是一個腳手架庫,定義如何通過建立、修改、重構或移動檔案和代碼來生成或轉換程式設計項目。Angular Cli使用原理圖生成和修改項目檔案。庫開發人員可以建立原理圖,使Cli能夠生成其已釋出的庫。可以檢視https://www.npmjs.com/package/@angular-devkit/schematics。

那這樣的話,我們可以知道angular是借助的

Schematic

來生成項目檔案。再檢視發現

node_module

裡面有個

@Schematics/angular

,裡面定義了我們可以使用cli生成的所有檔案,包括

components\class\enum\interface

等等。

點開檢視

components

,裡面有一些ts檔案,還有一個files檔案夾,裡面包含着所有我們生成component的檔案:

  • [email protected]@if-flat__

    • __nam[email protected]herize__.component.__styleext__

    • [email protected]__.component.html

    • [email protected]__.component.spec.ts

    • [email protected]__.component.ts

那想想,在我們運作Cli建立元件的時候,會使用這裡的模闆,用file檔案夾裡面的檔案生成項目元件。其他的先不管,我們按照這裡的

components

是不是可以來構造我們自己的“原理圖”呢?

自定義原理圖

先看看我們的需求,我們現在項目的項目裡面,頁面是page,按照angular原來的寫法,所有的page的元件都是:

XXXX.component.ts

。我們為了将頁面群組件進行區分,頁面的檔案都是

XXX.page.ts

。我們先在

node_module/@Schematics/angula/

下面複制

component

建立一個

page

現在,将page下面的files檔案夾中的檔案名

.component

都改為

.page

(由于我們不用單元測試檔案,直接删除

.spec.ts

檔案即可):

  • page
    • files
      • [email protected]@if-flat__

        • [email protected]__.page.__styleext__

        • [email protected]__.page.html

        • [email protected]__.page.ts

    • index.d.ts
    • index.js 指令運作時會執行這個js檔案
    • schema.d.ts
    • schema.json 定義了這個生成器指令可以接受的參數

接下來再看page裡面的

index.js

,這個js檔案在我們跑自己的指令的時候會執行。看這個檔案,裡面的代碼雖然有點看不懂,但是猜猜還是可以的,有些關鍵地方:

const componentPath = `/${options.path}/`
            + (options.flat ? '' : core_1.strings.dasherize(options.name) + '/')
            + core_1.strings.dasherize(options.name)
            + '.component';
const classifiedName = core_1.strings.classify(`${options.name}Component`);
           

類似于這樣的地方,我們發現就是建立對應的元件檔案和裡面的元件類。是以我們把所有

.component

}Component

的地方替換為

.page

}Page

:

const componentPath = `/${options.path}/`
            + (options.flat ? '' : core_1.strings.dasherize(options.name) + '/')
            + core_1.strings.dasherize(options.name)
            + '.page';
const classifiedName = core_1.strings.classify(`${options.name}Page`);
           

然後接下來再看

page/files/[email protected]__.page.ts

import { Component, OnInit<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection !== 'Default') { %>, ChangeDetectionStrategy<% }%> } from '@angular/core';
@Component({
  selector: '<%= selector %>',<% if(inlineTemplate) { %>
  template: `
    <p>
      <%= dasherize(name) %> works!
    </p>
  `,<% } else { %>
  templateUrl: './<%= dasherize(name) %>.component.html',<% } if(inlineStyle) { %>
  styles: []<% } else { %>
  styleUrls: ['./<%= dasherize(name) %>.component.<%= styleext %>']<% } %><% if(!!viewEncapsulation) { %>,
  encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>,
  changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %>
})
export class <%= classify(name) %>Component implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}
           

這個是生成的元件的ts模闆,我們需要根據我們的需求來改造,首先是檔案裡面的類,既然我們現在的檔案名是

XXX.page.ts

,那麼裡面的類也就需要時

XXXPage

形式的,并且我們的頁面是不允許作為指令的形式出現的,是以也要去掉

selector

中繼資料。那綜合下來,我們的

[email protected]__.page.ts

應該修改為:

import { Component, OnInit<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection !== 'Default') { %>, ChangeDetectionStrategy<% }%> } from '@angular/core';
@Component({
  templateUrl: './<%= dasherize(name) %>.page.html',
  <% if(inlineStyle) { %>
  styles: []<% } else { %>
  styleUrls: ['./<%= dasherize(name) %>.page.<%= styleext %>']<% } %><% if(!!viewEncapsulation) { %>,
  encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>,
  changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %>
})
export class <%= classify(name) %>Page implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}
           

OK,目前為止,我們的“原理圖”就建立的差不多了,我們現在需要加入cli指令上去。在

@Schematics/angular/collection.json

裡面定義了cli的指令,同樣,先觀察componet的指令:

"component": {
    "aliases": [ "c" ], // 簡寫形式
    "factory": "./component", // 采用生成器
    "description": "Create an Angular component.",
    "schema": "./component/schema.json"
},
           

我們來建立我們自己的指令:

"component": {
    "aliases": [ "pa" ], // 簡寫形式
    "factory": "./page", // 采用生成器
    "description": "Create an Angular component page.",
    "schema": "./page/schema.json"
},
           

測試指令

目前為止,我們已經添加好了我們自己的生成指令,現在來嘗試着生成一個page元件,在

app/pages/user

下面生成元件

user-test

,指令:

ng g page pages/user/user-test

,檢視結果:

CREATE src/app/pages/user/user-test/user-test.page.css (0 bytes)
CREATE src/app/pages/user/user-test/user-test.page.html (28 bytes)
CREATE src/app/pages/user/user-test/user-test.page.ts (239 bytes)
UPDATE src/app/pages/user/user.module.ts (1803 bytes)
           

看看生成的ts檔案:

import { Component, OnInit } from '@angular/core';
@Component({
  templateUrl: './user-test.page.html',
  styleUrls: ['./user-test.page.css']
})
export class UserTestPage implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}
           

非常好啊,完全滿足我們的需求。

慢着,我現在項目中使用的是less,而且使用

component

建立的元件裡面的樣式檔案都是less,為啥我們自定義的生成的是css檔案???

很可能是沒有識别我們自定義的less,那我們自定義的less是怎麼定的呢?看看

angular.json

檔案中有個

project

裡面:

"schematics": {
    "@schematics/angular:component": {
        "styleext": "less"
    }
},
           

也就是說,我們在這裡配置了生成

component

元件時,

styleext

less

,我們的

page

指令是沒有配置的,是以會找預設的樣式檔案字尾。那我們在這裡嘗試加上試試看:

"schematics": {
    "@schematics/angular:component": {
        "styleext": "less"
    },
    "@schematics/angular:page": {
        "styleext": "less"
    }
},
           

再生成一下:

CREATE src/app/pages/user/user-test/user-test.page.less (0 bytes)
CREATE src/app/pages/user/user-test/user-test.page.html (28 bytes)
CREATE src/app/pages/user/user-test/user-test.page.ts (240 bytes)
UPDATE src/app/pages/user/user.module.ts (1804 bytes)
           

完美~

繼續閱讀