首頁 web前端 js教程 使用 Web 元件時可能面臨的注意事項

使用 Web 元件時可能面臨的注意事項

Dec 09, 2024 am 03:19 AM

Caveats You May Face While Working With Web Components

Web 元件已經存在了一段時間,承諾提供一種標準化的方法來建立可重複使用的自訂元素。很明顯,雖然 Web 元件已經取得了顯著的進步,但開發人員在使用它們時仍然可能面臨一些注意事項。本部落格將探討其中 10 個注意事項。

1. 框架特定問題

如果您正在決定是否在專案中使用 Web 元件。重要的是要考慮您選擇的框架是否完全支援 Web 元件,否則您可能會遇到一些令人不快的警告。

例如,要在 Angular 中使用 Web 元件,需要將 CUSTOM_ELEMENTS_SCHEMA 新增至模組導入。

@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MyModule {}
登入後複製
登入後複製
登入後複製

使用 CUSTOM_ELEMENTS_SCHEMA 的問題是 Angular 將選擇退出模板中自訂元素的類型檢查和智慧感知。 (見問題)

要解決此問題,您可以建立一個 Angular 包裝器組件。

這是一個範例。

@Component({
  selector: 'some-web-component-wrapper',
  template: '<some-web-component [someProperty]="someClassProperty"></some-web-component>
})
export class SomeWebComponentWrapper {
  @Input() someClassProperty: string;
}

@NgModule({
    declarations: [SomeWebComponentWrapper],
    exports: [SomeWebComponentWrapper],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class WrapperModule {}
登入後複製
登入後複製
登入後複製

這可行,但手動建立它們不是一個好主意。因為這會產生大量的維護工作,我們可能會遇到 api 不同步的問題。為了讓這不那麼無聊。 Lit(請參閱此處)和 Stencil(請參閱此處)都提供了一個 cli 來自動創建它們。然而,首先需要創建這些包裝器組件是額外的開銷。如果您選擇的框架正確支援 Web 元件,您不必建立包裝器元件。

反應

另一個例子是 React。現在 React v19 剛剛發布,解決了這些問題。但是,如果您仍在使用 v18,請注意 v18 並不完全支援 Web 元件。因此,您在使用 React v18 中的 Web 元件時可能會遇到一些問題。這直接取自 Lit 文件。

「React 假設所有 JSX 屬性都對應到 HTML 元素屬性,並且不提供設定屬性的方法。這使得將複雜資料(如物件、陣列或函數)傳遞給 Web 元件變得困難。」

「React 也假設所有DOM 事件都有對應的「事件屬性」(onclick、onmousemove 等),並使用這些屬性而不是呼叫addEventListener()。這意味著要正確使用更複雜的Web 元件,您通常必須使用ref() 和命令式程式碼。

對於 React v18 Lit 建議使用他們的包裝元件,因為它們解決了設定屬性和監聽事件的問題。

這是使用 Lit 的 React 包裝組件的範例。


import React from 'react';
import { createComponent } from '@lit/react';
import { MyElement } from './my-element.js';

export const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onactivate: 'activate',
    onchange: 'change',
  },
});
登入後複製
登入後複製
登入後複製
用法


<MyElementComponent
  active={isActive}
  onactivate={(e) => setIsActive(e.active)}
  onchange={handleChange}
/>
登入後複製
登入後複製
登入後複製
幸運的是,有了 React v19,你就不再需要建立包裝組件了。耶!

在微前端中使用 Web 元件揭示了一個有趣的挑戰:

2. 全域註冊問題

一個重要的問題是自訂元素註冊表的全域性質:

如果您使用微前端並計劃使用 Web 元件在每個應用程式中重複使用 UI 元素,您很可能會遇到此錯誤。

@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MyModule {}
登入後複製
登入後複製
登入後複製

嘗試使用已使用的名稱註冊自訂元素時會發生此錯誤。這在微前端中很常見,因為微前端中的每個應用程式共享相同的 index.html 文件,並且每個應用程式都嘗試定義自訂元素。

有一項提案可以解決這個問題,稱為“範圍自訂元素註冊表”,但沒有預計到達時間,因此不幸的是,您需要使用填充。

如果您不使用polyfill,一種解決方法是使用前綴手動註冊自訂元素,以避免命名衝突。

要在 Lit 中執行此操作,您可以避免使用自動註冊自訂元素的 @customElement 裝飾器。然後為 tagName 新增靜態屬性。

之前

@Component({
  selector: 'some-web-component-wrapper',
  template: '<some-web-component [someProperty]="someClassProperty"></some-web-component>
})
export class SomeWebComponentWrapper {
  @Input() someClassProperty: string;
}

@NgModule({
    declarations: [SomeWebComponentWrapper],
    exports: [SomeWebComponentWrapper],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class WrapperModule {}
登入後複製
登入後複製
登入後複製

之後

import React from 'react';
import { createComponent } from '@lit/react';
import { MyElement } from './my-element.js';

export const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onactivate: 'activate',
    onchange: 'change',
  },
});
登入後複製
登入後複製
登入後複製

然後在每個應用程式中,您可以使用應用程式名稱的前綴定義自訂元素。

<MyElementComponent
  active={isActive}
  onactivate={(e) => setIsActive(e.active)}
  onchange={handleChange}
/>
登入後複製
登入後複製
登入後複製

然後要使用自訂元素,您可以將其與新前綴一起使用。

Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry':
the name "foo-bar" has already been used with this registry
登入後複製
登入後複製

這是一個快速的短期解決方案,但是您可能會注意到這不是最好的開發人員體驗,因此建議使用範圍自訂元素註冊表polyfill。

3. 繼承風格

Shadow DOM 在提供封裝的同時,也帶來了自己的一系列挑戰:

Shadow dom 透過提供封裝來運作。它可以防止樣式從組件中洩漏。它還可以防止全域樣式定位元件的 Shadow dom 內的元素。但是,如果繼承了元件外部的樣式,這些樣式仍然可能會洩漏。

這是一個例子。

@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
  render() {
    return html`<p>Hello world!</p>`;
  }
}
登入後複製
登入後複製
export class SimpleGreeting extends LitElement {
  static tagName = 'simple-greeting';

  render() {
    return html`<p>Hello world!</p>`;
  }
}
登入後複製
登入後複製

當我們點擊時該按鈕會發出一個冒泡的組合事件。

組件-a

[SimpleGreeting].forEach((component) => {
  const newTag = `app1-${component.tagName}`;
  if (!customElements.get(newTag)) {
    customElements.define(newTag, SimpleGreeting);
  }
});
登入後複製
登入後複製

由於事件來自元件 b,您可能會認為目標是元件 b 或按鈕。然而,事件被重新定位,因此目標成為組件 a。

因此,如果您需要知道事件是否來自

6. 整頁重新加載

如果連結在 Shadow dom 中使用,如本例所示,它將在您的應用程式中觸發整個頁面重新載入。

@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MyModule {}
登入後複製
登入後複製
登入後複製

這是因為路由是由瀏覽器而不是您的框架處理的。框架需要介入這些事件並在框架層級處理路由。然而,由於事件在 Shadow dom 中重新定位,這使得框架這樣做更具挑戰性,因為它們無法輕鬆存取錨元素。

要解決此問題,我們可以在 上設定一個事件處理程序這將停止事件的傳播並發出一個新事件。新事件需要冒泡並組合。此外,我們還需要存取詳細資訊
我們可以從 e.currentTarget 取得實例。

@Component({
  selector: 'some-web-component-wrapper',
  template: '<some-web-component [someProperty]="someClassProperty"></some-web-component>
})
export class SomeWebComponentWrapper {
  @Input() someClassProperty: string;
}

@NgModule({
    declarations: [SomeWebComponentWrapper],
    exports: [SomeWebComponentWrapper],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class WrapperModule {}
登入後複製
登入後複製
登入後複製

在消費端,您可以設定一個全域事件監聽器來監聽此事件並透過呼叫框架特定的路由函數來處理路由。

7. 嵌套影子dom

建置 Web 元件時。您可以決定將其他 Web 元件放入插槽或將它們嵌套在另一個 Web 元件中。這是一個例子。

開槽圖示

import React from 'react';
import { createComponent } from '@lit/react';
import { MyElement } from './my-element.js';

export const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onactivate: 'activate',
    onchange: 'change',
  },
});
登入後複製
登入後複製
登入後複製

巢狀圖示

<MyElementComponent
  active={isActive}
  onactivate={(e) => setIsActive(e.active)}
  onchange={handleChange}
/>
登入後複製
登入後複製
登入後複製

如果您決定巢狀元件,這可能會使查詢巢狀元件變得更加困難。特別是如果您有一個 QA 團隊需要建立端對端測試,因為他們需要針對頁面上的特定元素。
例如,要存取 some-icon,我們需要先透過取得 some-banner 的shadowRoot 來存取它,然後在該影子根內建立一個新查詢。

Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry':
the name "foo-bar" has already been used with this registry
登入後複製
登入後複製

這可能看起來很簡單,但元件嵌套得越深,它就會變得越來越困難。此外,如果您的元件是巢狀的,這可能會使工具提示的使用變得更加困難。特別是如果您需要定位深層嵌套的元素,以便可以在其下方顯示工具提示。

我發現使用插槽使我們的組件更小、更靈活,也更易於維護。所以更喜歡插槽,避免巢狀 Shadow dom。

8. 有限::slotted Selector

插槽提供了一種組合 UI 元素的方法,但它們在 Web 元件中存在局限性。

::slotted 選擇器僅適用於插槽的直接子級,限制了它在更複雜場景中的用處。

這是一個例子。

@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
  render() {
    return html`<p>Hello world!</p>`;
  }
}
登入後複製
登入後複製
export class SimpleGreeting extends LitElement {
  static tagName = 'simple-greeting';

  render() {
    return html`<p>Hello world!</p>`;
  }
}
登入後複製
登入後複製
[SimpleGreeting].forEach((component) => {
  const newTag = `app1-${component.tagName}`;
  if (!customElements.get(newTag)) {
    customElements.define(newTag, SimpleGreeting);
  }
});
登入後複製
登入後複製

10. 功能採用速度較慢

Web 元件在採用新功能和最佳實踐方面通常落後於 Vue、React、Svelte 和 Solid 等流行框架。
這可能是由於 Web 元件依賴瀏覽器實作和標準,與現代 JavaScript 框架的快速開發週期相比,這可能需要更長的時間才能發展。
因此,開發人員可能會發現自己正在等待某些功能,或者必須實現其他框架中隨時可用的解決方法。

Lit 的一些例子是在 JS 中使用 CSS 作為樣式的預設選項。人們很早就知道 JS 框架中的 CSS 有效能問題
因為它們經常引入額外的運行時開銷。因此,我們開始在 JS 框架中看到更新的 CSS,這些框架切換到基於零運行時的解決方案。
Lit 的 CSS in JS 解決方案仍然是基於運行時的。

另一個例子是訊號。目前 Lit 中的預設行為是我們透過添加 @property 裝飾器來為類別屬性添加反應性。
但是,當屬性發生變更時,它將觸發整個元件重新渲染。使用訊號,只有依賴訊號的元件的一部分才會更新。
這對於使用 UI 來說更有效率。如此高效,以至於有一個新提案(TC39)將其添加到 JavaScript 中。
現在 Lit 確實提供了一個使用 Signals 的套件,但它並不是預設的反應性,而 Vue 和 Solid 等其他框架已經這樣做了很多年。
在訊號成為網路標準之前,我們很可能在幾年內不會將訊號視為預設反應性。

另一個例子與我之前的警告「9. 開槽元素總是在 dom 中」相關。 Svelte 的創辦人 Rich Harris 談到了這個
在他 5 年前題為「為什麼我不使用 Web 元件」的部落格文章中。
他談到了他們如何採用 Web 標準方法來在 Svelte v2 中快速呈現分槽內容。然而,他們不得不遠離它
在 Svelte 3 中,因為這對開發人員來說是一個很大的挫折點。他們注意到大多數時候您希望開槽內容延遲渲染。

我可以舉出更多範例,例如在 Web 元件中,當 Vuejs 等其他框架已經支援此操作時,就沒有簡單的方法將資料傳遞到插槽。但這裡的主要要點是
Web 元件由於依賴 Web 標準,因此採用的功能比不依賴 Web 標準的框架慢得多。
透過不依賴網路標準,我們可以創新並提出更好的解決方案。

結論

Web 元件提供了一種強大的方法來建立可重複使用和封裝的自訂元素。然而,正如我們所探討的,開發人員在使用它們時可能會面臨一些注意事項和挑戰。例如框架不相容、微前端的使用、Shadow DOM 的限制、事件重定向問題、插槽以及緩慢的功能採用都是需要仔細考慮的領域。

儘管存在這些挑戰,Web 元件的優點(例如真正的封裝、可移植性和框架獨立性)使它們成為現代 Web 開發中的寶貴工具。隨著生態系統的不斷發展,我們預計會看到解決這些問題的改進和新的解決方案。

對於考慮 Web Components 的開發人員來說,權衡這些利弊並隨時了解該領域的最新進展至關重要。透過正確的方法和理解,Web 元件可以成為您的開發工具包的強大補充。

以上是使用 Web 元件時可能面臨的注意事項的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1677
14
CakePHP 教程
1431
52
Laravel 教程
1334
25
PHP教程
1279
29
C# 教程
1257
24
Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

JavaScript和Web:核心功能和用例 JavaScript和Web:核心功能和用例 Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

JavaScript在行動中:現實世界中的示例和項目 JavaScript在行動中:現實世界中的示例和項目 Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

了解JavaScript引擎:實施詳細信息 了解JavaScript引擎:實施詳細信息 Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:開發環境和工具 Python vs. JavaScript:開發環境和工具 Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

C/C在JavaScript口譯員和編譯器中的作用 C/C在JavaScript口譯員和編譯器中的作用 Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

從網站到應用程序:JavaScript的不同應用 從網站到應用程序:JavaScript的不同應用 Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序 Python vs. JavaScript:比較用例和應用程序 Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

See all articles