亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄
裝飾器與元數(shù)據(jù)
Angular 中的裝飾器和元數(shù)據(jù)
總結(jié)
首頁(yè) web前端 js教程 聊聊Angular中的元數(shù)據(jù)(Metadata)和裝飾器(Decorator)

聊聊Angular中的元數(shù)據(jù)(Metadata)和裝飾器(Decorator)

Feb 28, 2022 am 11:10 AM
angular

本篇文章繼續(xù)Angular的學(xué)習(xí),帶大家了解一下Angular中的元數(shù)據(jù)和裝飾器,簡(jiǎn)單了解一下他們的用法,希望對(duì)大家有所幫助!

聊聊Angular中的元數(shù)據(jù)(Metadata)和裝飾器(Decorator)

作為“為大型前端項(xiàng)目”而設(shè)計(jì)的前端框架,Angular 其實(shí)有許多值得參考和學(xué)習(xí)的設(shè)計(jì),本系列主要用于研究這些設(shè)計(jì)和功能的實(shí)現(xiàn)原理。本文主要圍繞 Angular 中隨處可見(jiàn)的元數(shù)據(jù),來(lái)進(jìn)行介紹。【相關(guān)教程推薦:《angular教程》】

裝飾器是使用 Angular 進(jìn)行開(kāi)發(fā)時(shí)的核心概念。在 Angular 中,裝飾器用于為類(lèi)或?qū)傩愿郊釉獢?shù)據(jù),來(lái)讓自己知道那些類(lèi)或?qū)傩缘暮x,以及該如何處理它們。

裝飾器與元數(shù)據(jù)

不管是裝飾器還是元數(shù)據(jù),都不是由 Angular 提出的概念。因此,我們先來(lái)簡(jiǎn)單了解一下。

元數(shù)據(jù)(Metadata)

在通用的概念中,元數(shù)據(jù)是描述用戶數(shù)據(jù)的數(shù)據(jù)。它總結(jié)了有關(guān)數(shù)據(jù)的基本信息,可以使查找和使用特定數(shù)據(jù)實(shí)例更加容易。例如,作者,創(chuàng)建日期,修改日期和文件大小是非常基本的文檔元數(shù)據(jù)的示例。

在用于類(lèi)的場(chǎng)景下,元數(shù)據(jù)用于裝飾類(lèi),來(lái)描述類(lèi)的定義和行為,以便可以配置類(lèi)的預(yù)期行為。

裝飾器(Decorator)

裝飾器是 JavaScript 的一種語(yǔ)言特性,是一項(xiàng)位于階段 2(stage 2)的試驗(yàn)特性。

裝飾器是定義期間在類(lèi),類(lèi)元素或其他 JavaScript 語(yǔ)法形式上調(diào)用的函數(shù)。

裝飾器具有三個(gè)主要功能:

  • 可以用具有相同語(yǔ)義的匹配值替換正在修飾的值。(例如,裝飾器可以將方法替換為另一種方法,將一個(gè)字段替換為另一個(gè)字段,將一個(gè)類(lèi)替換為另一個(gè)類(lèi),等等)。

  • 可以將元數(shù)據(jù)與正在修飾的值相關(guān)聯(lián);可以從外部讀取此元數(shù)據(jù),并將其用于元編程和自我檢查。

  • 可以通過(guò)元數(shù)據(jù)提供對(duì)正在修飾的值的訪問(wèn)。對(duì)于公共值,他們可以通過(guò)值名稱來(lái)實(shí)現(xiàn);對(duì)于私有值,它們接收訪問(wèn)器函數(shù),然后可以選擇共享它們。

本質(zhì)上,裝飾器可用于對(duì)值進(jìn)行元編程和向其添加功能,而無(wú)需從根本上改變其外部行為。

更多的內(nèi)容,可以參考 tc39/proposal-decorators 提案。

Angular 中的裝飾器和元數(shù)據(jù)

我們?cè)陂_(kāi)發(fā) Angular 應(yīng)用時(shí),不管是組件、指令,還是服務(wù)、模塊等,都需要通過(guò)裝飾器來(lái)進(jìn)行定義和開(kāi)發(fā)。裝飾器會(huì)出現(xiàn)在類(lèi)定義的緊前方,用來(lái)聲明該類(lèi)具有指定的類(lèi)型,并且提供適合該類(lèi)型的元數(shù)據(jù)。

比如,我們可以用下列裝飾器來(lái)聲明 Angular 的類(lèi):@Component()@Directive()、@Pipe()@Injectable()、@NgModule()。

使用裝飾器和元數(shù)據(jù)來(lái)改變類(lèi)的行為

@Component()為例,該裝飾器的作用包括:

  • 將類(lèi)標(biāo)記為 Angular 組件。

  • 提供可配置的元數(shù)據(jù),用來(lái)確定應(yīng)在運(yùn)行時(shí)如何處理、實(shí)例化和使用該組件。

關(guān)于@Component()該如何使用可以參考,這里不多介紹。我們來(lái)看看這個(gè)裝飾器的定義:

// 提供 Angular 組件的配置元數(shù)據(jù)接口定義
// Angular 中,組件是指令的子集,始終與模板相關(guān)聯(lián)
export interface Component extends Directive {
  // changeDetection 用于此組件的變更檢測(cè)策略
  // 實(shí)例化組件時(shí),Angular 將創(chuàng)建一個(gè)更改檢測(cè)器,該更改檢測(cè)器負(fù)責(zé)傳播組件的綁定。
  changeDetection?: ChangeDetectionStrategy;
  // 定義對(duì)其視圖 DOM 子對(duì)象可見(jiàn)的可注入對(duì)象的集合
  viewProviders?: Provider[];
  // 包含組件的模塊的模塊ID,該組件必須能夠解析模板和樣式的相對(duì) URL
  moduleId?: string;
  ...
  // 模板和 CSS 樣式的封裝策略
  encapsulation?: ViewEncapsulation;
  // 覆蓋默認(rèn)的插值起始和終止定界符(`{{`和`}}`)
  interpolation?: [string, string];
}

// 組件裝飾器和元數(shù)據(jù)
export const Component: ComponentDecorator = makeDecorator(
    'Component',
    // 使用默認(rèn)的 CheckAlways 策略,在該策略中,更改檢測(cè)是自動(dòng)進(jìn)行的,直到明確停用為止。
    (c: Component = {}) => ({changeDetection: ChangeDetectionStrategy.Default, ...c}),
    Directive, undefined,
    (type: Type<any>, meta: Component) => SWITCH_COMPILE_COMPONENT(type, meta));

以上便是組件裝飾、組件元數(shù)據(jù)的定義,我們來(lái)看看裝飾器的創(chuàng)建過(guò)程。

裝飾器的創(chuàng)建過(guò)程

我們可以從源碼中找到,組件和指令的裝飾器都會(huì)通過(guò)makeDecorator()來(lái)產(chǎn)生:

export function makeDecorator<T>(
    name: string, props?: (...args: any[]) => any, parentClass?: any, // 裝飾器名字和屬性
    additionalProcessing?: (type: Type<T>) => void,
    typeFn?: (type: Type<T>, ...args: any[]) => void):
    {new (...args: any[]): any; (...args: any[]): any; (...args: any[]): (cls: any) => any;} {
  // noSideEffects 用于確認(rèn)閉包編譯器包裝的函數(shù)沒(méi)有副作用
  return noSideEffects(() => { 
    const metaCtor = makeMetadataCtor(props);
    // 裝飾器工廠
    function DecoratorFactory(
        this: unknown|typeof DecoratorFactory, ...args: any[]): (cls: Type<T>) => any {
      if (this instanceof DecoratorFactory) {
        // 賦值元數(shù)據(jù)
        metaCtor.call(this, ...args);
        return this as typeof DecoratorFactory;
      }
      // 創(chuàng)建裝飾器工廠
      const annotationInstance = new (DecoratorFactory as any)(...args);
      return function TypeDecorator(cls: Type<T>) {
        // 編譯類(lèi)
        if (typeFn) typeFn(cls, ...args);
        // 使用 Object.defineProperty 很重要,因?yàn)樗鼤?huì)創(chuàng)建不可枚舉的屬性,從而防止該屬性在子類(lèi)化過(guò)程中被復(fù)制。
        const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
            (cls as any)[ANNOTATIONS] :
            Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS];
        annotations.push(annotationInstance);
        // 特定邏輯的執(zhí)行
        if (additionalProcessing) additionalProcessing(cls);

        return cls;
      };
    }
    if (parentClass) {
      // 繼承父類(lèi)
      DecoratorFactory.prototype = Object.create(parentClass.prototype);
    }
    DecoratorFactory.prototype.ngMetadataName = name;
    (DecoratorFactory as any).annotationCls = DecoratorFactory;
    return DecoratorFactory as any;
  });
}

在上面的例子中,我們通過(guò)makeDecorator()產(chǎn)生了一個(gè)用于定義組件的Component裝飾器工廠。當(dāng)使用@Component()創(chuàng)建組件時(shí),Angular 會(huì)根據(jù)元數(shù)據(jù)來(lái)編譯組件。

根據(jù)裝飾器元數(shù)據(jù)編譯組件

Angular 會(huì)根據(jù)該裝飾器元數(shù)據(jù),來(lái)編譯 Angular 組件,然后將生成的組件定義(?cmp)修補(bǔ)到組件類(lèi)型上:

export function compileComponent(type: Type<any>, metadata: Component): void {
  // 初始化 ngDevMode
  (typeof ngDevMode === &#39;undefined&#39; || ngDevMode) && initNgDevMode();
  let ngComponentDef: any = null;
  // 元數(shù)據(jù)可能具有需要解析的資源
  maybeQueueResolutionOfComponentResources(type, metadata);
  // 這里使用的功能與指令相同,因?yàn)檫@只是創(chuàng)建 ngFactoryDef 所需的元數(shù)據(jù)的子集
  addDirectiveFactoryDef(type, metadata);
  Object.defineProperty(type, NG_COMP_DEF, {
    get: () => {
      if (ngComponentDef === null) {
        const compiler = getCompilerFacade();
        // 根據(jù)元數(shù)據(jù)解析組件
        if (componentNeedsResolution(metadata)) {
          ...
          // 異常處理
        }
        ...
        // 創(chuàng)建編譯組件需要的完整元數(shù)據(jù)
        const templateUrl = metadata.templateUrl || `ng:///${type.name}/template.html`;
        const meta: R3ComponentMetadataFacade = {
          ...directiveMetadata(type, metadata),
          typeSourceSpan: compiler.createParseSourceSpan(&#39;Component&#39;, type.name, templateUrl),
          template: metadata.template || &#39;&#39;,
          preserveWhitespaces,
          styles: metadata.styles || EMPTY_ARRAY,
          animations: metadata.animations,
          directives: [],
          changeDetection: metadata.changeDetection,
          pipes: new Map(),
          encapsulation,
          interpolation: metadata.interpolation,
          viewProviders: metadata.viewProviders || null,
        };
        // 編譯過(guò)程需要計(jì)算深度,以便確認(rèn)編譯是否最終完成
        compilationDepth++;
        try {
          if (meta.usesInheritance) {
            addDirectiveDefToUndecoratedParents(type);
          }
          // 根據(jù)模板、環(huán)境和組件需要的元數(shù)據(jù),來(lái)編譯組件
          ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta);
        } finally {
          // 即使編譯失敗,也請(qǐng)確保減少編譯深度
          compilationDepth--;
        }
        if (compilationDepth === 0) {
          // 當(dāng)執(zhí)行 NgModule 裝飾器時(shí),我們將模塊定義加入隊(duì)列,以便僅在所有聲明都已解析的情況下才將隊(duì)列出隊(duì),并將其自身作為模塊作用域添加到其所有聲明中
          // 此調(diào)用運(yùn)行檢查以查看隊(duì)列中的任何模塊是否可以出隊(duì),并將范圍添加到它們的聲明中
          flushModuleScopingQueueAsMuchAsPossible();
        }
        // 如果組件編譯是異步的,則聲明該組件的 @NgModule 批注可以執(zhí)行并在組件類(lèi)型上設(shè)置 ngSelectorScope 屬性
        // 這允許組件在完成編譯后,使用模塊中的 directiveDefs 對(duì)其自身進(jìn)行修補(bǔ)
        if (hasSelectorScope(type)) {
          const scopes = transitiveScopesFor(type.ngSelectorScope);
          patchComponentDefWithScope(ngComponentDef, scopes);
        }
      }
      return ngComponentDef;
    },
    ...
  });
}

編譯組件的過(guò)程可能是異步的(比如需要解析組件模板或其他資源的 URL)。如果編譯不是立即進(jìn)行的,compileComponent會(huì)將資源解析加入到全局隊(duì)列中,并且將無(wú)法返回?cmp,直到通過(guò)調(diào)用resolveComponentResources解決了全局隊(duì)列為止。

編譯過(guò)程中的元數(shù)據(jù)

元數(shù)據(jù)是有關(guān)類(lèi)的信息,但它不是類(lèi)的屬性。因此,用于配置類(lèi)的定義和行為的這些數(shù)據(jù),不應(yīng)該存儲(chǔ)在該類(lèi)的實(shí)例中,我們還需要在其他地方保存此數(shù)據(jù)。

在 Angular 中,編譯過(guò)程產(chǎn)生的元數(shù)據(jù),會(huì)使用CompileMetadataResolver來(lái)進(jìn)行管理和維護(hù),這里我們主要看指令(組件)相關(guān)的邏輯:

export class CompileMetadataResolver {
  private _nonNormalizedDirectiveCache =
      new Map<Type, {annotation: Directive, metadata: cpl.CompileDirectiveMetadata}>();
  // 使用 Map 的方式來(lái)保存
  private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>(); 
  private _summaryCache = new Map<Type, cpl.CompileTypeSummary|null>();
  private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
  private _ngModuleCache = new Map<Type, cpl.CompileNgModuleMetadata>();
  private _ngModuleOfTypes = new Map<Type, Type>();
  private _shallowModuleCache = new Map<Type, cpl.CompileShallowModuleMetadata>();

  constructor(
      private _config: CompilerConfig, private _htmlParser: HtmlParser,
      private _ngModuleResolver: NgModuleResolver, private _directiveResolver: DirectiveResolver,
      private _pipeResolver: PipeResolver, private _summaryResolver: SummaryResolver<any>,
      private _schemaRegistry: ElementSchemaRegistry,
      private _directiveNormalizer: DirectiveNormalizer, private _console: Console,
      private _staticSymbolCache: StaticSymbolCache, private _reflector: CompileReflector,
      private _errorCollector?: ErrorCollector) {}
  // 清除特定某個(gè)指令的元數(shù)據(jù)
  clearCacheFor(type: Type) {
    const dirMeta = this._directiveCache.get(type);
    this._directiveCache.delete(type);
    ...
  }
  // 清除所有元數(shù)據(jù)
  clearCache(): void {
    this._directiveCache.clear();
    ...
  }
  /**
   * 加載 NgModule 中,已聲明的指令和的管道
   */
  loadNgModuleDirectiveAndPipeMetadata(moduleType: any, isSync: boolean, throwIfNotFound = true):
      Promise<any> {
    const ngModule = this.getNgModuleMetadata(moduleType, throwIfNotFound);
    const loading: Promise<any>[] = [];
    if (ngModule) {
      ngModule.declaredDirectives.forEach((id) => {
        const promise = this.loadDirectiveMetadata(moduleType, id.reference, isSync);
        if (promise) {
          loading.push(promise);
        }
      });
      ngModule.declaredPipes.forEach((id) => this._loadPipeMetadata(id.reference));
    }
    return Promise.all(loading);
  }
  // 加載指令(組件)元數(shù)據(jù)
  loadDirectiveMetadata(ngModuleType: any, directiveType: any, isSync: boolean): SyncAsync<null> {
    // 若已加載,則直接返回
    if (this._directiveCache.has(directiveType)) {
      return null;
    }
    directiveType = resolveForwardRef(directiveType);
    const {annotation, metadata} = this.getNonNormalizedDirectiveMetadata(directiveType)!;
    // 創(chuàng)建指令(組件)元數(shù)據(jù)
    const createDirectiveMetadata = (templateMetadata: cpl.CompileTemplateMetadata|null) => {
      const normalizedDirMeta = new cpl.CompileDirectiveMetadata({
        isHost: false,
        type: metadata.type,
        isComponent: metadata.isComponent,
        selector: metadata.selector,
        exportAs: metadata.exportAs,
        changeDetection: metadata.changeDetection,
        inputs: metadata.inputs,
        outputs: metadata.outputs,
        hostListeners: metadata.hostListeners,
        hostProperties: metadata.hostProperties,
        hostAttributes: metadata.hostAttributes,
        providers: metadata.providers,
        viewProviders: metadata.viewProviders,
        queries: metadata.queries,
        guards: metadata.guards,
        viewQueries: metadata.viewQueries,
        entryComponents: metadata.entryComponents,
        componentViewType: metadata.componentViewType,
        rendererType: metadata.rendererType,
        componentFactory: metadata.componentFactory,
        template: templateMetadata
      });
      if (templateMetadata) {
        this.initComponentFactory(metadata.componentFactory!, templateMetadata.ngContentSelectors);
      }
      // 存儲(chǔ)完整的元數(shù)據(jù)信息,以及元數(shù)據(jù)摘要信息
      this._directiveCache.set(directiveType, normalizedDirMeta);
      this._summaryCache.set(directiveType, normalizedDirMeta.toSummary());
      return null;
    };

    if (metadata.isComponent) {
      // 如果是組件,該過(guò)程可能為異步過(guò)程,則需要等待異步過(guò)程結(jié)束后的模板返回
      const template = metadata.template !;
      const templateMeta = this._directiveNormalizer.normalizeTemplate({
        ngModuleType,
        componentType: directiveType,
        moduleUrl: this._reflector.componentModuleUrl(directiveType, annotation),
        encapsulation: template.encapsulation,
        template: template.template,
        templateUrl: template.templateUrl,
        styles: template.styles,
        styleUrls: template.styleUrls,
        animations: template.animations,
        interpolation: template.interpolation,
        preserveWhitespaces: template.preserveWhitespaces
      });
      if (isPromise(templateMeta) && isSync) {
        this._reportError(componentStillLoadingError(directiveType), directiveType);
        return null;
      }
      // 并將元數(shù)據(jù)進(jìn)行存儲(chǔ)
      return SyncAsync.then(templateMeta, createDirectiveMetadata);
    } else {
      // 指令,直接存儲(chǔ)元數(shù)據(jù)
      createDirectiveMetadata(null);
      return null;
    }
  }
  // 獲取給定指令(組件)的元數(shù)據(jù)信息
  getDirectiveMetadata(directiveType: any): cpl.CompileDirectiveMetadata {
    const dirMeta = this._directiveCache.get(directiveType)!;
    ...
    return dirMeta;
  }
  // 獲取給定指令(組件)的元數(shù)據(jù)摘要信息
  getDirectiveSummary(dirType: any): cpl.CompileDirectiveSummary {
    const dirSummary =
        <cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
    ...
    return dirSummary;
  }
}

可以看到,在編譯過(guò)程中,不管是組件、指令、管道,還是模塊,這些類(lèi)在編譯過(guò)程中的元數(shù)據(jù),都使用Map來(lái)存儲(chǔ)。

總結(jié)

本節(jié)我們介紹了 Angular 中的裝飾器和元數(shù)據(jù),其中元數(shù)據(jù)用于描述類(lèi)的定義和行為。

在 Angular 編譯過(guò)程中,會(huì)使用Map的數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)和存儲(chǔ)裝飾器的元數(shù)據(jù),并根據(jù)這些元數(shù)據(jù)信息來(lái)編譯組件、指令、管道和模塊等。

更多編程相關(guān)知識(shí),請(qǐng)?jiān)L問(wèn):編程教學(xué)??!

以上是聊聊Angular中的元數(shù)據(jù)(Metadata)和裝飾器(Decorator)的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

熱門(mén)話題

Laravel 教程
1597
29
PHP教程
1488
72
利用紐約時(shí)報(bào)API進(jìn)行元數(shù)據(jù)爬取 利用紐約時(shí)報(bào)API進(jìn)行元數(shù)據(jù)爬取 Sep 02, 2023 pm 10:13 PM

簡(jiǎn)介上周,我寫(xiě)了一篇關(guān)于抓取網(wǎng)頁(yè)以收集元數(shù)據(jù)的介紹,并提到不可能抓取《紐約時(shí)報(bào)》網(wǎng)站?!都~約時(shí)報(bào)》付費(fèi)墻會(huì)阻止您收集基本元數(shù)據(jù)的嘗試。但有一種方法可以使用紐約時(shí)報(bào)API來(lái)解決這個(gè)問(wèn)題。最近我開(kāi)始在Yii平臺(tái)上構(gòu)建一個(gè)社區(qū)網(wǎng)站,我將在以后的教程中發(fā)布該網(wǎng)站。我希望能夠輕松添加與網(wǎng)站內(nèi)容相關(guān)的鏈接。雖然人們可以輕松地將URL粘貼到表單中,但提供標(biāo)題和來(lái)源信息卻非常耗時(shí)。因此,在今天的教程中,我將擴(kuò)展我最近編寫(xiě)的抓取代碼,以在添加《紐約時(shí)報(bào)》鏈接時(shí)利用《紐約時(shí)報(bào)》API來(lái)收集頭條新聞。請(qǐng)記住,我參與了

如何在Ubuntu 24.04上安裝Angular 如何在Ubuntu 24.04上安裝Angular Mar 23, 2024 pm 12:20 PM

Angular.js是一種可自由訪問(wèn)的JavaScript平臺(tái),用于創(chuàng)建動(dòng)態(tài)應(yīng)用程序。它允許您通過(guò)擴(kuò)展HTML的語(yǔ)法作為模板語(yǔ)言,以快速、清晰地表示應(yīng)用程序的各個(gè)方面。Angular.js提供了一系列工具,可幫助您編寫(xiě)、更新和測(cè)試代碼。此外,它還提供了許多功能,如路由和表單管理。本指南將討論在Ubuntu24上安裝Angular的方法。首先,您需要安裝Node.js。Node.js是一個(gè)基于ChromeV8引擎的JavaScript運(yùn)行環(huán)境,可讓您在服務(wù)器端運(yùn)行JavaScript代碼。要在Ub

淺析angular中怎么使用monaco-editor 淺析angular中怎么使用monaco-editor Oct 17, 2022 pm 08:04 PM

angular中怎么使用monaco-editor?下面本篇文章記錄下最近的一次業(yè)務(wù)中用到的 monaco-editor 在 angular 中的使用,希望對(duì)大家有所幫助!

如何使用PHP和Angular進(jìn)行前端開(kāi)發(fā) 如何使用PHP和Angular進(jìn)行前端開(kāi)發(fā) May 11, 2023 pm 04:04 PM

隨著互聯(lián)網(wǎng)的飛速發(fā)展,前端開(kāi)發(fā)技術(shù)也在不斷改進(jìn)和迭代。PHP和Angular是兩種廣泛應(yīng)用于前端開(kāi)發(fā)的技術(shù)。PHP是一種服務(wù)器端腳本語(yǔ)言,可以處理表單、生成動(dòng)態(tài)頁(yè)面和管理訪問(wèn)權(quán)限等任務(wù)。而Angular是一種JavaScript的框架,可以用于開(kāi)發(fā)單頁(yè)面應(yīng)用和構(gòu)建組件化的Web應(yīng)用程序。本篇文章將介紹如何使用PHP和Angular進(jìn)行前端開(kāi)發(fā),以及如何將它們

一文探究Angular中的服務(wù)端渲染(SSR) 一文探究Angular中的服務(wù)端渲染(SSR) Dec 27, 2022 pm 07:24 PM

你知道 Angular Universal 嗎?可以幫助網(wǎng)站提供更好的 SEO 支持哦!

使用Python訪問(wèn)各種音頻和視頻文件的元數(shù)據(jù) 使用Python訪問(wèn)各種音頻和視頻文件的元數(shù)據(jù) Sep 05, 2023 am 11:41 AM

我們可以使用Mutagen和Python中的eyeD3模塊訪問(wèn)音頻文件的元數(shù)據(jù)。對(duì)于視頻元數(shù)據(jù),我們可以使用電影和Python中的OpenCV庫(kù)。元數(shù)據(jù)是提供有關(guān)其他數(shù)據(jù)(例如音頻和視頻數(shù)據(jù))的信息的數(shù)據(jù)。音頻和視頻文件的元數(shù)據(jù)包括文件格式、文件分辨率、文件大小、持續(xù)時(shí)間、比特率等。通過(guò)訪問(wèn)這些元數(shù)據(jù),我們可以更有效地管理媒體并分析元數(shù)據(jù)以獲得一些有用的信息。在本文中,我們將了解Python提供的一些用于訪問(wèn)音頻和視頻文件元數(shù)據(jù)的庫(kù)或模塊。訪問(wèn)音頻元數(shù)據(jù)一些用于訪問(wèn)音頻文件元數(shù)據(jù)的庫(kù)是-使用誘變

使用Angular和Node進(jìn)行基于令牌的身份驗(yàn)證 使用Angular和Node進(jìn)行基于令牌的身份驗(yàn)證 Sep 01, 2023 pm 02:01 PM

身份驗(yàn)證是任何Web應(yīng)用程序中最重要的部分之一。本教程討論基于令牌的身份驗(yàn)證系統(tǒng)以及它們與傳統(tǒng)登錄系統(tǒng)的區(qū)別。在本教程結(jié)束時(shí),您將看到一個(gè)用Angular和Node.js編寫(xiě)的完整工作演示。傳統(tǒng)身份驗(yàn)證系統(tǒng)在繼續(xù)基于令牌的身份驗(yàn)證系統(tǒng)之前,讓我們先看一下傳統(tǒng)的身份驗(yàn)證系統(tǒng)。用戶在登錄表單中提供用戶名和密碼,然后點(diǎn)擊登錄。發(fā)出請(qǐng)求后,通過(guò)查詢數(shù)據(jù)庫(kù)在后端驗(yàn)證用戶。如果請(qǐng)求有效,則使用從數(shù)據(jù)庫(kù)中獲取的用戶信息創(chuàng)建會(huì)話,然后在響應(yīng)頭中返回會(huì)話信息,以便將會(huì)話ID存儲(chǔ)在瀏覽器中。提供用于訪問(wèn)應(yīng)用程序中受

Angular組件及其顯示屬性:了解非block默認(rèn)值 Angular組件及其顯示屬性:了解非block默認(rèn)值 Mar 15, 2024 pm 04:51 PM

Angular框架中組件的默認(rèn)顯示行為不是塊級(jí)元素。這種設(shè)計(jì)選擇促進(jìn)了組件樣式的封裝,并鼓勵(lì)開(kāi)發(fā)人員有意識(shí)地定義每個(gè)組件的顯示方式。通過(guò)顯式設(shè)置CSS屬性 display,Angular組件的顯示可以完全控制,從而實(shí)現(xiàn)所需的布局和響應(yīng)能力。

See all articles