Angular(01)-- 架構概覽

来源:https://www.cnblogs.com/dasusu/archive/2019/03/12/10518722.html
-Advertisement-
Play Games

聲明 本系列文章內容梳理自以下來源: "Angular 官方中文版教程" 官方的教程,其實已經很詳細且易懂,這裡再次梳理的目的在於複習和鞏固相關知識點,剛開始接觸學習 Angular 的還是建議以官網為主。 因為這系列文章,更多的會帶有我個人的一些理解和解讀,由於目前我也才剛開始接觸 Angular ...


聲明

本系列文章內容梳理自以下來源:

官方的教程,其實已經很詳細且易懂,這裡再次梳理的目的在於複習和鞏固相關知識點,剛開始接觸學習 Angular 的還是建議以官網為主。

因為這系列文章,更多的會帶有我個人的一些理解和解讀,由於目前我也才剛開始接觸 Angular 不久,在該階段的一些理解並不一定是正確的,擔心會有所誤導,所以還是以官網為主。

正文- 架構概覽

接觸 Angular 大概一個月吧,期間寫了個項目,趁現在稍微有點時間,來回顧梳理一下。

其實,如果前端網站並不是特別複雜,那麼使用 Angular 無非也就是常跟幾個重要的知識點打交道,在官網的核心知識的第一節中就將這些知識點羅列出來了,也就是:架構概覽。

Angular架構概覽.png

畫了這個圖來大概表示下 Angular 的架構概覽,基本涉及到一些常見的重要的知識點了,比如:

  • 模塊
  • 路由
  • 組件
  • 模板
  • 服務
  • 指令
  • 管道

不同的類型,文件名通常會都按照一定的規範來命名,以便直接看出該文件的角色。

當然,文件命名只是給開發人員來方便維護、辨別,對於 Angular 來說,這些都是一份份的 ts 文件代碼,所以,都需要在相對應的文件中加上一些裝飾器比如:@Directive,@Pipe,@Component,@NgModel 等這些,才能夠讓 Angular 識別出該文件的角色、用途。

基本上,用 Angular 做一個簡單的前端項目,就是跟上面這些打交道,理清它們各自的用途及用法,還有之間的聯繫,基本上,就可以上手進行一些開發了。

當然,像在 Service 服務中,還會有非同步編程、HttpClient 網路編程的相關知識點;

在 Component 組件中,也還會有表單、動畫相關的編程知識點,這些都是需要進一步去深入學習研究,但從總體架構上來看,就是要先瞭解以上這些知識點了。

模塊

一個 Angular 項目,至少會有一個模塊,即最少都會有一份用 @NgModel 聲明的 ts 文件,表明該文件作為模塊角色,來管理其他角色。

其他角色包括:組件、指令、管道、服務等等,這些角色必須在模塊文件中聲明瞭,才能夠被該模塊內的其他角色所使用,而且同一個組件、指令、管道不允許同時在多個模塊中進行聲明,只能通過模塊 exports 給其他模塊使用。

Angular 里的模塊,並不等同於 Android 項目中的模塊概念。

在 Android 項目代碼中,可能我們會根據功能來進行模塊的劃分,但這個模塊僅僅是抽象上的概念,也就是建個包,把代碼都集中管理。

而 Angular 里的模塊,不僅可以在項目結構上集中管理同一個模塊的代碼文件,還可以為模塊內的代碼提供一個運行的上下文。

意思就是說,不同模塊在運行期間互不影響,就好像各自運行在各自的沙箱容器中一樣。舉個簡單的例子,在不同模塊中聲明相同的變數名,或相同的 css 的類選擇器,它們之間並不會起衝突。

當然,模塊之間可以有交互,模塊可以依賴於另一模塊,模塊內的可以共用資源等等,所以,NgModel 中有許多需要配置的聲明項,比如:

  • declarations:聲明屬於本模塊內的組件、指令、管道
  • providers:聲明屬於本模塊內的服務
  • imports:聲明本模塊所引用的其他模塊,通常是 imports 其他模塊在 exports 中聲明的項
  • exports:聲明本模塊對外公開的組件、指令、管道等,在這裡公開的項才可以被其他模塊所使用
  • bootstrap:只有根模塊才需要配置,用來設置應用主視圖,Angular 應用啟動後,這裡就是入口,類似於 Android 中的入口 Activity
  • 還有其他一些可選配置,比如應用主題,或者動態的組件聲明等等

在 Angular 中,大多數的模式就是,一個根模塊管理著很多功能模塊,然後,每個模塊管理自己模塊內部所使用到的組件、指令、管道、服務、或者需要依賴於其他模塊,如果該模塊內部的這些角色,有些可以供其他模塊使用,那麼就需要對外暴露。

路由

一個項目這麼多模塊,Angular 並不會一開始就把所有模塊都載入,而是惰性載入,按需載入。

那麼,什麼時候會去載入呢?

就是等某個模塊內部的組件被使用的時候會載入,而組件是什麼時候會被使用的呢?

有兩個時機,一是組件被直接調用;二是觸發了路由去載入;

路由通常的配置方式是用一個 @NgModel 聲明的模塊,但只用其中兩項配置:imports 和 exports,imports 用來導入當前模塊所有組件與 url 的映射表,而 exports 用來將這些映射表信息暴露,以供相對應的模塊去引入使用。

當然,你不想抽離路由配置,直接將其配置在對應模塊的 imports 內也可以,抽離的話,相對獨立,可維護。

區別於傳統的前端網頁的跳轉方式,Angular 項目是一個單頁應用,所謂的單頁應用就是說只有一個頁面,所有頁面的跳轉,其實是將當前頁面的顯示內容進行替換,頁面仍舊只有一個,並不會打開新的頁面。

而頁面的跳轉,通常有以下幾種場景:

  • 用戶輸入 url 進行跳轉
  • 用戶點擊交互按鈕進行跳轉
  • 用戶操作前進或後退進行跳轉

這些場景,路由的工作機制都能夠很好的支持。

如果網頁很簡單,只有一個首頁,並不存在頁面跳轉場景,那麼可以不用配置路由,只需要在 index.html 中配置根視圖,以及在根模塊的 bootstrap 中配置根視圖組件即可。

但如果項目劃分成了多個功能模塊,那麼應該交由每個模塊管理自己的路由表,而後選擇一個上層模塊,來統一關聯各個模塊路由,有兩種方式:一是在上層模塊的 imports 內按照一定順序來導入各個功能模塊;但這種方式想要按照路由層級來查看路由表就比較麻煩,需要到各個模塊內部去查看或者藉助一些工具。

另一種方式是,在上層模塊的路由表中使用 loadChildren 載入各個功能模塊,然後各個功能模塊預設路由都顯示成空視圖,各自內部再通過配置 children 的路由表方式來管理各個模塊內部自己的路由表。

組件與模板

在 Angular 中,最常接觸的應該就是組件了。

我是這麼理解的,組件可以是你在界面上看到的任何東西,可以是一個頁面,可以是頁面上的一個按鈕。

而對於瀏覽器解析並呈現前端頁面時,Html、CSS、JavaScript 這三分文件通常都是需要的,而 Angular 是使用了 TypeScript,所以一個組件,其實就包括了:Html,CSS,TypeScript。

在 Angular 中,可以說,是以組件為單位來組成頁面的,組件是核心,因為 Angular 提供的功能基本都是用來為組件服務的。

以上,是我的理解。

但要註意,官網教程中,很多地方的組件描述,更多時候是傾向於表示 TypeScript 的那份文件,因為對於組件來說,TypeScript 可以說是它的核心,CSS 只是樣式文件,Html 更類似於模板存在。

所以這裡將組件和模板放在一起講,因為就像開頭那張圖一樣,組件是一份 TypeScript 文件,在該文件中,定義了這個組件的模板(template)來源和 CSS 樣式來源。

模板提供了該組件的呈現結構,而 TypeScript 里定義了組件的數據來源及交互行為,它們兩一起組織成一個視圖呈現給用戶。

既然,這份 TypeScript 的組件文件和模板文件需要共同合作,那麼它們之間就少不了交互,所以就涉及到很多所謂的模板語法,也就是所謂的組件和模板之間的交互方式。

比如,當要往模板中嵌入 TypeScript 中的變數數據時,可以使用 {{value}} 這種語法形式,同樣的,還有模板中標簽的屬性綁定,事件回調註冊的交互方式的語法。

總之,Angular 支持雙向數據綁定,是一種以數據驅動的思想來讓頁面進行交互刷新的方式,區別於傳統的前端模式。在以往,如果需要動態的更新 DOM 上的信息時,需要先獲取到相對應的元素實例對象,然後調用相應的 DOM API 來操縱 DOM;

而使用 Angular 的話,可以直接在模板的相應元素中,將某個屬性與 TypeScript 文件中某個變數直接進行綁定,後續這個變數值變化時,Angular 會自動去更新相應 DOM 的屬性,也就是說,原本那些操縱 DOM 的代碼,Angular 幫我們做了,我們不用再自己去處理了。

另外,註意,以上出現的 TypeScript 的描述,你可以理解成官網中的組件,我之所以不想用組件的方式來進行描述,是因為,我覺得,組件是一個整體,它本身就包括了 TypeScript 文件和模板文件,所以官網中說的組件和模板的交互,我覺得,換成組件中的 TypeScript 文件與模板文件的交互更為適合。

當然,這隻是我目前階段的理解。

服務

服務是一個廣義上的概念,通常用來處理那些跟 UI 交互無關的事情,比如網路請求的工作等。

所以它也是為組件服務,而且 Angular 有一套依賴註入機制,也就是說,組件只需要告訴 Angular,它需要哪些服務,至於這些服務的實例是什麼時候創建,交給誰去管理等這些組件內部都不用自己去處理了。

Angular 會自動創建相關的服務實例,然後在組件適當的時候,將這個實例註入給組件去使用。

這種模式跟以前在 Android 端開發時有所區別,在 Android 端中,當需要業務層某個實例對象時,通常都需要自己內部去初始化,或者這個實例是個單例的話,也需要自己去實現單例。

但在 Angular 中,你可以藉助它依賴註入的機制,來讓 Angular 幫你去做這些依賴的對象的實例管理的事,如果需要一個全局的單例服務,那麼可以將該服務聲明成 root 即全局可用;如果需要一個模塊內的單例,那麼可以在該模塊的 providers 中聲明該服務;如果需要一個組件自己的實例對象,那麼可以在組件的元數據塊的 providers 中配置該服務。

總之,就是,跟 UI 交互無關的工作,可以抽到服務中去處理,而該服務實例的管理,交給 Angular 就可以了,組件只需要告訴 Angular 它需要哪種形式的服務即可。

那麼,組件是怎麼告訴 Angular 的呢?

同樣在 Android 項目或者後端項目中,也有一些依賴註入框架,那些通常都是藉助註解的方式來實現。

但在 Angular 中,不用這麼麻煩,直接在組件的構造函數的參數中,聲明某個服務類型的參數即可。

指令

指令也是為組件服務的,但是,是在組件的模板文件中來使用。

因為組件的模板,其實就是一份 HTML 文件,基於 HTML 的標簽之上,加上一些 Angular 的模板語法,而 Angular 在將這份 HTML 文件代碼交給瀏覽器解析之前,會先自行解析一遍,去將模板中不屬於 HTML 的那些語法解析出相應的行為。

而指令分為結構型指令和屬性型指令,它們的區別,其實就在於,一個是改變 DOM 的結構,一個是改變 DOM 元素的樣式。

所以說,指令的目的,其實就是簡化一些操縱 DOM 的工作,比如你需要讓某些按鈕都具有統一的行為和樣式,當被點擊時先做什麼,再做什麼。

實現這個,你當然可以在 TypeScript 中去書寫這些邏輯,但要應用到每個按鈕上,就比較繁瑣。

這個時候,就可以將這些工作都封裝到指令內部,然後在每個按鈕標簽上加上該指令,Angular 在解析模板時,發現了這個指令,就會為每個按鈕都加上這麼一段程式邏輯。

我個人覺得,指令的功能,讓我們處理一些相同的行為,可以更好的去封裝,減少冗餘和繁瑣。

當然,上面舉的場景,也可以自己封裝個按鈕組件,然後在其他模板中,不使用原生按鈕,而使用封裝後的按鈕組件,也可以達到目的。

所以,組件其實也是指令的一種,但組件的實現方式會比較重,有時候,只需要封裝一些簡單的行為邏輯,就可以直接藉助指令的方式封裝。

指令的原理也很簡單,在模板中某個元素標簽上,添加上某個指令後,解析到這個指令時,會進入這個指令的相關工作,而指令內部,會獲取到一個當前指令掛載的元素標簽對象,既然都拿到這個對象了,那麼,在指令內部想對這個元素做什麼,都可以了。

指令還有另一個通途,通常用來擴展原有的功能,因為可能項目中,在模板里使用的組件或者 HTML 元素的標簽因為種種原生無權或不方便進行修改,而又想在其基礎上擴展一些功能,此時就可以利用指令來實現。

管道

管道同樣是為組件服務,也同樣是在組件的模板文件中來使用。

它的用途,在於,將數據按照一定的規則進行轉換,比如 Object 對象,轉換成 json 格式數據,再比如,long 型的時間,轉換成具體的時間日期等等。

Angular 中已經內置了一些管道,也可以自定義管道。

示例

大概瞭解了 Angular 的架構概覽,接下去就來看看一個簡單的 Angular 項目結構,以及各個文件、模塊的用途,稍微講一下。

這是用 WebStrom 創建一個 Angular 項目後,自動生成的簡單架構。

在利用 Angular Cli 工具生成腳手架時,預設就已經生成了很多配置項,而且此時,項目已經是可以運行的,因為也自動生成了一個根模塊和根視圖,預設頁面是 Angular 的歡迎界面。

挑幾個來講講。

angular.json

這是 Angular-CLI 的配置文件,而 Angular-CLI 是自動化的工程構建工具,也就是利用這個工具,可以幫助我們完成很多工作,比如創建項目、創建文件、構建、打包等等。

原本的 HTML、CSS、JavaScript 的前端開發模式,並沒有工程的概念,只要用瀏覽器打開 HTML 文件就能夠運行。而 Angular 引入了 TypeScript,Scss 等瀏覽器並不無法識別的語言,自然,要讓瀏覽器運行 Angular 項目之前,需要進行一次編譯,一次轉換。

這些工作就可以藉助 Angular-CLI 來進行。另外,創建一個模塊,創建一個組件,也都可以通過 Angular-CLI 來。

那麼,在創建這些文件或者說,打包編譯這些項目文件時,該按照怎樣的規則,就是參照 angular.json 這份配置文件。

大概看一下內容:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json", // 預設的配置項,比如預設配置了 ng g component 生成組件時應該生成哪些文件等等
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "daView": {  // 項目的配置
      "root": "",
      "sourceRoot": "src",  // 源代碼路基
      "projectType": "application", // 項目的類型,是應用還是三方庫(library)
      "prefix": "app", // 利用命令生成 component 和 directive 的首碼
      "schematics": {}, // 替換掉第一行的 schema.json 中的一些預設配置項,不如創建組件時,不要生成spec文件
      "architect": { // 執行一些構造工作時的配置
        "build": { // 執行 ng build 時的一些配置項
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/daView", // 編譯後的文件輸出的位置
            "index": "src/index.html",   // 構建所需的模板 Index.html
            "main": "src/main.ts",       // 構建所需的文件
            "polyfills": "src/polyfills.ts", // 構建所需的文件
            "tsConfig": "src/tsconfig.app.json", // 對 typescript 編譯的配置文件 
            "assets": [ // 構建所需的資源
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [ // 構建所需的樣式文件,可以是 scss
              "src/styles.css"
            ],
            "scripts": [] // 構建所需的三方庫,比如 jQuery
          },
          "configurations": {/*...*/}
        },
        "serve": {/*...*/}, // 執行 ng serve 時的一些配置項
        "extract-i18n": {/*...*/},
        "test": {/*...*/},
        "lint": {/*...*/}
        }
      }
    },
    "daView-e2e": {/*...*/},
  "defaultProject": "daView"
}

所以,利用 Angular-CLI 生成的初始項目中,有許多基本的文件,這些文件,基本也都在 angular.json 中被配置使用了,每個配置文件基本都有各自的用途。

比如,tslint 用來配置 lint 檢查,tsconfig 用來配置 TypeScript 的編譯配置,其他那些 html,css,ts,js 文件基本都是 Angular 項目運行所需的基礎文件。

package.json

對於一個工程項目來說,依賴的三方庫管理工具也很重要,在 Android 項目中,通常是藉助 Gradle 或 maven 來管理三方庫。

而在 Angular 項目中,是使用 npm 來進行三方庫的管理,對應的配置文件就是 package.json。

在這份配置文件中,配置了項目所需要的三方庫,npm 會自動去將這些三方庫下載到 node_modules 目錄中。然後,再去將一些需要一起打包的三方庫在 angular.json 中進行配置。

app/src 源碼

以上就是利用 Angular-CLI 創建項目生成的初始架構中各個文件的大概用途,下麵講講 Angular 項目的大概運行流程。

在 src 中的 index.html 文件就是單頁應用的頁面文件,裡面的 body 標簽內,自動加入了一行根視圖的組件:

<app-root></app-root> 就是根組件 AppComponent (自動生成的)的組件標簽,當 Angular 在 HTML 文件中發現有組件標簽時,就會去載入該組件所屬的模塊,並去解析組件的模板文件,將其嵌入到 HTML 文件的組件標簽中。

看一下自動生成的根模塊的部分內容:

//app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
//app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'daView';
}

app.module.ts 文件用 @NgModule 表示該文件角色是模塊,併在內部配置了它的組件 AppComponent,這樣 AppComponent 組件就只屬於該模塊了,並能夠在該模塊內的其他組件中被使用。

另外,由於該模塊是根模塊,所以還需要配置 bootstrap,設置應用的根視圖,這個配置需要和 index.html 里的 body 標簽內的根視圖組件是同一個組件,否則運行時就會報錯了。

當項目中模塊多了的時候,各模塊之間基本是通過路由或者組件來進行相互關聯。

比如,我們新創建個 Home 模塊,然後在根模塊中創建個 app-routing 路由配置文件:

//app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {
    path: 'home', loadChildren: './home/home.module#HomeModule'
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

然後在 app.module.ts 的 imports 中將該路由配置導入,這樣當路由到 home 時,會去載入 home 模塊,然後看看 home 模塊的路由配置:

//home-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {HomeComponent} from './home.component';
import {HomeCenterComponent} from './component/home-center.component';

const routes: Routes = [
  {
    path: '',
    children: [
      {
        path: '', component: HomeCenterComponent
      }
    ]
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class HomeRoutingModule { }

home 模塊的預設視圖為空,但交由其子視圖來控制,所以,當導航到 home 時,home 模塊會去載入它內部的 HomeCenterComponent 組件。

以上,是當項目中有多模塊時,我的處理方式。

當按照這種方式來實現時,對於瞭解一個 Angular,就有一定的規律可循了:

  1. 先找根視圖組件,然後確認根視圖組件中的 router-outlet 標簽的區域,因為這個區域展示的就是由根模塊路由導航到的新的組件內容;
  2. 去根模塊的配置中找到根模塊的路由配置表,來查看第一個層級的路由分別對應哪些模塊;
  3. 去這些相應的模塊中,查看它們各自內部的路由配置表,來確定各自模塊的預設視圖組件是哪個,下一個層級的各個路由所對應的視圖組件;
  4. 這樣,一個頁面的組件層次結構就能夠很快的理清。

大家好,我是 dasu,歡迎關註我的公眾號(dasuAndroidTv),公眾號中有我的聯繫方式,歡迎有事沒事來嘮嗑一下,如果你覺得本篇內容有幫助到你,可以轉載但記得要關註,要標明原文哦,謝謝支持~
dasuAndroidTv2.png


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 我是在對一個UITableView 一起進行 reloadRows和reloadSections 的操作的時候 出現的 ...
  • //引入核心模塊 const http = require('http'); //創建伺服器 http.createServer((req,res)=>{ }).listen(3000); //引入核心模塊 const http = require("http"); //創建伺服器 http.cre... ...
  • 公共事件匯流排eventBus的實質就是創建一個vue實例,通過一個空的vue實例作為橋梁實現vue組件間的通信。它是實現非父子組件通信的一種解決方案。 用法如下: 第一步:項目中創建一個js文件(我通常給它取個名字為bus.js),引入vue,創建一個vue實例,導出這個實例,代碼如下(一共就兩行) ...
  • 全局安裝腳手架 cnpm install vue-cli -g 查詢安裝版本 vue -V 初始化項目 vue init webpack 項目名字 項目初始化完成 ******************************************************************** ...
  • 1.query方式傳參和接受參數 2.params方式傳遞參數 3.query和params的區別,query相當於get請求,在頁面跳轉的時候,可以在地址欄看到請求參數,然而params則相當於post請求,參數不會在地址欄中顯示。 ...
  • 按照MDN整理的數組部分的思維導圖,主要目的是方便查漏補缺,所以寫的不是很詳細。 ...
  • js獲取select標簽選中的值 遇到一個問題。需要利用JavaScript代碼獲取下拉框選中的值。 下拉框部分代碼: 獲取方式一:原生JavaScript 獲取方式二:JQuery 首先要保證已經引入了jQuery庫。 ...
  • 一,promise是什麼? promise 是最早由社區提出和實現是一種解決非同步編程的方案,比其他傳統的解決方案(回調函數和事件)更合理和強大。 ES6 將其寫進了語言標準,統一了用法,原生提供了 promise 對象。 ES6 規定,promise對象是一個構造函數,用來生成 promise 實例 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...