Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲综合成人在线,久久精品视频在线播放,久久精品国产在爱久久

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          web components詳述

          web components詳述

          么是Web Components

          Web Components 是一套不同的技術,允許您創建可重用的定制元素(它們的功能封裝在您的代碼之外)并且在您的web應用中使用它們。
          背景

          • 組件化開發已經是前端主流開發方式,因為組件化開發在代碼復用提升團隊效率方面有著無可比擬的優勢,現在流行的React,Vue都是組件框架。
          • 谷歌公司一直在推動瀏覽器的原生組件,即 Web Components API。相比第三方框架,原生組件簡單直接,符合直覺,不用加載任何外部模塊,代碼量小。目前,它還在不斷發展,但已經可用于生產環境。

          組件:最初的目的是代碼重用,功能相對單一或者獨立。在整個系統的代碼層次上位于最底層,被其他代碼所依賴,所以說組件化是縱向分層。
          使用方法
          1. 創建一個類或函數來指定web組件的功能,推薦請使用 ECMAScript 2015 的類語法。
          2. 使用 CustomElementRegistry.define() 方法注冊自己的新自定義元素 ,并向其傳遞要定義的元素名稱、指定元素功能的類、以及可選的其所繼承自的元素。
          3. 如果需要的話,使用Element.attachShadow() 方法將一個shadow DOM附加到自定義元素上。使用原生的DOM方法向shadow DOM中添加子元素、事件監聽器等。
          4. 如果需要的話,使用 <template>和<slot> 定義一個HTML模板。再次使用常規DOM方法克隆模板并將其附加到shadow DOM中。
          5. 最后在頁面中使用我們的自定義元素,就像使用原生HTML元素一樣
          寫一個Web Components組件
          1. 預期效果:預期渲染一個這樣的自定義品牌名片到頁面上面

          只要開發者在頁面上調用了<company-card></company-card>即可渲染頁面,根據規范,自定義元素的名稱必須包含連詞線,用與區別原生的 HTML 元素
          2. 自定義的元素需要使用js類來創建,頁面中所有的自定義元素都會是這個類的實例:

          然后就可以實現基礎效果:

          然后我們的js直接取出自定義元素上面的屬性賦值給對應的標簽即可

          3.使用template來創建元素

          • 如果使用原生js來創建組件,我們的開發效率會大打折扣,達不到我們想要的組件化提升效率的目的,所以瀏覽器提供了template來創建元素,重新寫一下樣式代碼。
          • 同時組件里面的數據,我們可以通過在自定義標簽上寫屬性,傳入到組件里面,更加符合組件開發的思路。

          然后我的js直接取出自定義元素上面的屬性賦值給對應的標簽即可。


          4. 加入樣式
          組件的樣式需要加入到template組件里面,為每個組件獨享的樣式,跟vue思路差不多最終的template可能是這樣的

          5. 最終實現效果

          生命周期函數 在custom element的構造函數中,可以指定多個不同的回調函數,它們將會在元素的不同生命時期被調用

          結語:

          不得不承認,Web Components 標準的提出解決了一些問題,必須交由瀏覽器去處理的是 Shadow DOM,在沒有Shadow DOM 的瀏覽器上實現代碼隔離的方式多多少少有缺陷。個人我覺得組件化的各個 API 不夠簡潔易用,依舊有 getElementById 這些的味道,但是交由各個類庫去簡化也可以接受,而 import 功能上沒問題,但是加載多個

          組件時性能問題還是值得商榷,標準可能需要在這個方面提供更多給瀏覽器的指引,例如是否有可能提供一種單一請求加載多個組件 HTML 的方式等。

          在現在的移動化趨勢中,Web Components 不僅僅是 Web 端的問題,越來越多的開發者期望以 Web 的方式去實現移動應用,而多端復用的實現漸漸是以組件的形式鋪開,例如 React NativeWeex。所以 Web Components 的標準可能會影響到多端開發 Web 化的一個模式和發展。

          但是,對于Web Components的發展前景還是比較看好,生產環境下還是觀望一下就好。

          絡技術的快速發展,帶來了層出不窮的新概念和框架,尤其是在前端開發領域,新技術的出現如同浪潮般一波接一波,例如 Vue3 和 Vite 的組合。而在這種技術快速更新的環境中,Web Components 作為一項已經存在一段時間的技術,為什么如今值得我們抓緊時間,去深入學習和探討呢?

          Web Components 是由 W3C 推動的標準化技術。如今,它得到了包括 Chrome、Firefox、Safari 和 Edge 在內的主流瀏覽器的廣泛支持。不僅 「Vue3」 的更新就包括了對 Web Components 的原生支持,現在也出現了很多由Web Components封裝的「組件」「庫」,尤其是現在「面試」也成為了常問的話題,其中更為頻頻出現的是 Shadow DOM。

          這項技術的魅力在于,「它允許開發者創建自定義、可重用的元素,這些元素可以在任何符合標準的 Web 應用中無縫使用,而不受限于特定的框架(React、Vue)」。如果你還對 Web Components 比較陌生,那么現在是時候開始了解這項技術了。

          Web Components 核心概念

          Web Components 是一種瀏覽器原生支持的 Web 組件化技術,它允許開發者創建可重用的「自定義元素」,并且可以在任何支持 Web Components 的瀏覽器中使用。

          image.png

          Web Components 包括以下幾個核心概念:

          1. 「Custom Elements」(自定義元素):允許開發者創建新的 HTML 元素,并且可以定義它的行為和樣式。
          2. 「Shadow DOM」(影子 DOM):允許開發者封裝組件的內部結構和樣式,避免全局命名空間的污染。
          3. 「Templates」(模板):允許開發者定義一個可以在多個組件中重用的 HTML 結構。
          4. 「Slots」(插槽):允許開發者創建一個可插入內容的占位符,以便在不同的組件中使用。

          今天將圍繞這4個核心概念以及相關拓展,通過例子演示重點說一下 Web Components 是如何創建可重用的自定義元素的。

          Custom Elements(自定義元素)

          Web Components 最大的特性之一就是能將 HTML 封裝成 Custom Elements(自定義元素)。下面我們通過一個簡單的按鈕例子,看下它是怎么實現的。

          創建自定義元素

          首先,我們需要定義一個自定義元素。這可以通過使用 customElements.define() 方法來實現。在這個例子中,我們將創建一個名為 my-button 的自定義元素。

          // main.js
          class MyButton extends HTMLElement {
            constructor() {
              super();
              const shadowRoot=this.attachShadow({ mode: 'open' });
              shadowRoot.innerHTML=`
                <style>
                  button {
                    background-color: #4CAF50;
                    border: none;
                    color: white;
                    text-align: center;
                    text-decoration: none;
                    display: inline-block;
                    font-size: 16px;
                    margin: 4px 2px;
                    cursor: pointer;
                    padding: 10px 24px;
                    border-radius: 4px;
                  }
                </style>
                <button>Click Me!</button>
              `;
            }
          }
          customElements.define('my-button', MyButton);
          

          現在我們已經定義了一個名為 my-button 的自定義元素,我們可以在 HTML 文件中直接使用它。

          <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Web Components Example</title>
          </head>
          <body>
            <my-button></my-button>
            
            <script src="./main.js"></script>
          </body>
          </html>
          

          在這個例子中,我們創建了一個名為 my-button 的自定義元素,并在 HTML 文件中直接使用它。這個自定義元素將渲染為一個綠色的按鈕,上面寫著“Click Me!”。

          不止如此,CustomElements還支持自定義元素行為(如添加點擊事件),也就是說既能封裝UI樣式,也是封裝UI交互。

          const shadowRoot=this.attachShadow({ mode: 'open' });
          shadowRoot.querySelector('button').addEventListener('click', ()=> {
              alert('按鈕被點擊了!');
          });
          

          到這里為止,便實現了一個簡單的 Web Components,詳細代碼見CustomElements。

          生命周期回調方法

          Custom Elements 也有一組生命周期回調方法(到這里是不是感覺 Web Component 就像 Vue、React似得,怎么還有生命周期?),這些方法在元素的不同生命周期階段被調用。這些生命周期方法允許你在元素的創建、插入文檔、更新和刪除等時刻執行操作。

          以下是自定義元素的一些主要生命周期回調方法:

          1. 「constructor()」: 構造函數,在創建元素實例時調用。適用于執行初始化操作,例如設置初始屬性、添加事件監聽器或創建 Shadow DOM。
          2. 「connectedCallback()」: 當自定義元素被插入到上下文時調用。適用于元素被插入到 DOM 時執行的操作,例如獲取數據、渲染內容或啟動定時器。
          3. 「disconnectedCallback()」: 當自定義元素從文檔中移除時調用。適用于元素從 DOM 中移除時執行的操作,例如移除事件監聽器或停止定時器。
          4. 「attributeChangedCallback(attributeName, oldValue, newValue)」: 當自定義元素的屬性被添加、移除或更改時調用。要使用這個回調,你需要在類中定義一個靜態的 observedAttributes 屬性,列出你想要監聽的屬性。

          下面是一個簡單的例子,展示了如何在自定義元素中使用這些生命周期方法:

          class MyCustomElement extends HTMLElement {
            constructor() {
              super();
              // 初始化操作,例如創建 Shadow DOM
              const shadowRoot=this.attachShadow({ mode: 'open' });
              shadowRoot.innerHTML='<p>這是一個自定義元素</p>';
            }
            connectedCallback() {
              // 元素被插入到 DOM 時執行的操作
              console.log('Custom element connected to the DOM');
            }
            disconnectedCallback() {
              // 元素從 DOM 中移除時執行的操作
              console.log('Custom element disconnected from the DOM');
            }
            attributeChangedCallback(name, oldValue, newValue) {
              // 監聽的屬性發生變化時執行的操作
              console.log(`Attribute ${name} changed from ${oldValue} to ${newValue}`);
            }
            static get observedAttributes() {
              // 返回一個數組,包含需要監聽的屬性
              return ['my-attribute'];
            }
          }
          customElements.define('my-custom-element', MyCustomElement);
          

          在 HTML 中使用這個自定義元素:

          <my-custom-element my-attribute="value"></my-custom-element>
          

          當 my-custom-element 被插入到 DOM 中時,connectedCallback 會被調用。如果元素被從 DOM 中移除,disconnectedCallback 會被調用。如果元素的 my-attribute 屬性發生變化,attributeChangedCallback 會被調用。

          ?

          「注意」:監聽的同時,也記得停止監聽。比如說你可能需要在元素連接到 DOM 時開始監聽事件,但是在元素斷開連接時停止監聽,避免內存泄漏。

          ?

          Shadow DOM(影子 DOM)

          下面我們將繼續探討 Shadow DOM,它是 Web Components 的核心特性之一。

          Shadow DOM

          Shadow DOM 允許開發者創建一個封閉的 DOM 子樹,這個子樹與主文檔的 DOM 分離,這意味著 Shadow DOM 內部的樣式和結構不會受到外部的影響,也不會影響到外部。

          在“Custom Elements(自定義元素)”的例子中,我們已經簡單使用了 Shadow DOM。

          「1、使用 innerHTML」

          通過設置 Shadow DOM 的 innerHTML 屬性,可以直接添加一個或多個元素。這種方式適用于從字符串模板快速填充 Shadow DOM。

          class MyElementInnerHTML extends HTMLElement {
            constructor() {
              super();
              const shadowRoot=this.attachShadow({ mode: 'open' });
              shadowRoot.innerHTML=`
                <style>
                  p { color: black; }
                </style>
                <p>使用 innerHTML</p>
              `;
            }
          }
          customElements.define('my-element-inner', MyElementInnerHTML);
          

          「2、使用 createElement 和 appendChild」

          也可以使用 document.createElement 方法創建一個新元素,然后使用 appendChild 方法將其添加到 Shadow DOM 中。

          const wrapper=document.createElement('p');
          wrapper.textContent='使用 createElement 和 appendChild';
          
          var style=document.createElement('style');
          style.textContent=`
          p { color: gray; }
          `;
          // 引入外部樣式同樣可以使用 appendChild
          // const linkElement=document.createElement('link');
          // linkElement.setAttribute('rel', 'stylesheet');
          // linkElement.setAttribute('href', 'style.css');
          class MyElementAppend extends HTMLElement {
            constructor() {
              super();
              const shadowRoot=this.attachShadow({ mode: 'open' });
              
              shadowRoot.appendChild(wrapper);
              shadowRoot.appendChild(style);
              // shadowRoot.appendChild(linkElement);
            }
          }
          customElements.define('my-element-append', MyElementAppend);
          

          3、template方式

          除上面兩種方式外,還可以使用模板元素 (<template>)添加,具體見下方 「“Templates(模版)”」

          Shadow Mode

          其中在自定義元素的構造函數中,我們調用了 attachShadow() 方法,并傳入了一個對象 { mode: 'open' }。這里的 mode 屬性決定了 Shadow DOM 的封裝模式,它有兩個可能的值:

          • open:允許外部訪問 Shadow DOM 的 API。
          • closed:不允許外部訪問 Shadow DOM 的 API。

          在這個例子中,我們創建了一個 Shadow DOM,并向其中添加了一行文字和相關的樣式。由于 Shadow DOM 的封裝性,這些樣式只會在 my-element 元素內部生效,不會影響到頁面上的其他元素(樣式隔離)。

          下面我們更詳細地探討 Shadow DOM 是否允許外部訪問,的兩種封裝模式:open 和 closed。

          「1、Shadow Mode:open 模式」

          當使用 open 模式創建 Shadow DOM 時,外部腳本可以通過 Element.shadowRoot 屬性訪問 Shadow DOM 的根節點。

          這意味著你可以從外部查詢、修改 Shadow DOM 內部的元素和樣式。下面是一個使用 open 模式的例子:

          class OpenMyElement extends HTMLElement {
            constructor() {
              super();
              // 創建一個 open 模式的 Shadow DOM
              const shadowRoot=this.attachShadow({ mode: 'open' });
              shadowRoot.innerHTML=`
                <style>
                  p { color: red; }
                </style>
                <p>這是一個 open 模式的 Shadow DOM</p>
              `;
            }
          }
          customElements.define('open-my-element', OpenMyElement);
          
          // 在外部訪問 Shadow DOM
          const element=document.querySelector('open-my-element');
          console.log(element.shadowRoot); // 輸出 ShadowRoot 對象
          

          在這個例子中,我們創建了一個自定義元素 open-my-element,它有一個 open 模式的 Shadow DOM。由于模式是 open,我們可以在外部通過 element.shadowRoot 訪問 Shadow DOM 的根節點,并進行進一步的操作,比如添加或刪除子元素,修改樣式等。

          image.png

          「2、Shadow Mode:closed 模式」

          當使用 closed 模式創建 Shadow DOM 時,外部腳本無法通過 Element.shadowRoot 屬性訪問 Shadow DOM 的根節點。

          這意味著 Shadow DOM 內部的元素和樣式對外部是完全隱藏的,無法從外部直接訪問或修改。 下面是一個使用 closed 模式的例子:

          class ClosedMyElement extends HTMLElement {
            constructor() {
              super();
              // 創建一個 closed 模式的 Shadow DOM
              const shadowRoot=this.attachShadow({ mode: 'closed' });
              shadowRoot.innerHTML=`
                <style>
                  p { color: blue; }
                </style>
                <p>這是一個 closed 模式的 Shadow DOM</p>
              `;
            }
          }
          customElements.define('closed-my-element', ClosedMyElement);
          
          // 在外部嘗試訪問 Shadow DOM
          const element=document.querySelector('closed-my-element');
          console.log(element.shadowRoot); // 輸出 null
          
          

          在這個例子中,我們創建了一個自定義元素 closed-mode-element,它有一個 closed 模式的 Shadow DOM。由于模式是 closed,當我們嘗試在外部通過 element.shadowRoot 訪問 Shadow DOM 的根節點時,將得到 null。

          image.png

          open 和 closed 模式決定了 Shadow DOM 的封裝程度:

          • open 模式允許外部訪問 Shadow DOM 的 API,這意味著你可以從外部查詢和修改 Shadow DOM 內部的元素和樣式。
          • closed 模式不允許外部訪問 Shadow DOM 的 API,這意味著 Shadow DOM 內部的元素和樣式對外部是完全隱藏的,無法從外部直接訪問或修改。

          選擇哪種模式取決于你的具體需求。如果你希望組件的內部結構和樣式完全對外部隱藏,使用 closed 模式是更好的選擇。如果你需要從外部訪問和修改組件的內部結構和樣式,使用 open 模式會更合適。

          完整代碼,詳見ShadowDOM。

          其外,Shadow DOM 還支持更高級的用法,比如可以將 Shadow DOM 分割成多個 Shadow Trees,使用 slots(插槽)來插入內容,以及使用 template(模板)來定義可重用的 HTML 結構。

          Slots(插槽)

          Slots 是一種特殊類型的元素,它允許你將內容從組件的一個部分傳遞到另一個部分,增加了組件的靈活性。它使得 Web Components 自定義元素,更加的靈活。

          基礎使用

          例如,我們可以修改 my-button 組件,使其允許用戶自定義按鈕文本:

          class MyButton extends HTMLElement {
            constructor() {
              super();
              const shadowRoot=this.attachShadow({ mode: 'open' });
              shadowRoot.innerHTML=`
                <style>
                  /* ...樣式代碼保持不變... */
                </style>
                <button>
                    <slot>Click Me!</slot>
                </button>
              `;
            }
          }
          customElements.define('my-button', MyButton);
          

          現在,當我們在 HTML 中使用 my-button 時,我們可以向其中插入任何內容,它會替換掉 <slot> 標簽:

          <my-button>Slots Custom Text</my-button>
          

          image.png

          命名插槽

          在開發中,我們更多的還會遇到不同情況下,選擇插入的內容,這里就用到了命名插槽,使用起來非常方便。

          class MyButtonName extends HTMLElement {
            constructor() {
              super();
              const shadowRoot=this.attachShadow({ mode: 'open' });
              shadowRoot.innerHTML=`
                <style>
                  /* ...樣式代碼保持不變... */
                </style>
                <button>
                  <slot name="element-name"></slot>
                  <slot name="element-age"></slot>
                  <slot name="element-email"></slot>
                </button>
              `;
            }
          }
          customElements.define('my-button-name', MyButtonName);
          
          <my-button-name>
              <span slot="element-name">element-name</span>
          </my-button-name>
          <my-button-name>
              <span slot="element-age">element-age</span>
          </my-button-name>
          <my-button-name>
              <span slot="element-email">element-email</span>
          </my-button-name>
          

          image.png

          是不是很方便,很靈活!!具體代碼詳見Web Components Slots。

          Templates(模板)

          Templates 允許你定義一個可以在多個組件中重用的 HTML 結構。你可以將模板放在 HTML 文件中的任何位置,并通過 JavaScript 動態地實例化它們:

          <my-button></my-button>
          
          <template id="my-button-template">
            <style>
              /* ...樣式代碼保持不變... */
            </style>
            <button>
                <slot>Click Me!</slot>
            </button>
          </template>
          

          在 JavaScript 中,你可以這樣使用模板:

          class MyButton extends HTMLElement {
            constructor() {
              super();
              const shadowRoot=this.attachShadow({ mode: 'open' });
              const template=document.getElementById('my-button-template');
              // 使用`cloneNode()` 方法添加了拷貝到 Shadow root 根節點上。
              shadowRoot.appendChild(template.content.cloneNode(true));
            }
          }
          customElements.define('my-button', MyButton);
          

          image.png

          這樣,你就可以在不同的組件中重用同一個模板,從而提高代碼的可維護性和重用性。具體代碼下詳見Web Components Templates。

          相關拓展

          Web Components 兼容性

          Web Components 是一組用于構建可復用組件的技術,包括 Custom Elements, Shadow DOM, HTML Templates 等。這些技術的出現,使得開發者能夠更好地組織,去開發復雜的網頁應用。然而,由于這些技術相對較新,不同瀏覽器的支持情況不盡相同,因此兼容性問題也是我們需要重點關注的方向。

          Custom Elements

          image.png

          Shadow DOM

          image.png

          HTML Templates

          image.png

          從上面可以看出,現階段市場上大部分的瀏覽器已經都原生支持了 Web Components 的規范標準。「但是如果說出現了兼容性問題,我們應該怎么處理?」

          Polyfills

          對于舊版瀏覽器不支持的兼容性情況,可以考慮使用 polyfill 來實現兼容性。Polyfills 是一種代碼注入技術,使得瀏覽器可以支持新的標準 API。對于不支持 Web Components 的瀏覽器,我們可以用 Polyfills 讓這些瀏覽器可以支持 Web Components。

          這里我們可以用到 webcomponents.js 庫,它可以實現兼容 Custom Elements、Shadow DOM 和 HTML Templates 標準,讓我們在開發時不必考慮兼容性問題。

          npm install @webcomponents/webcomponentsjs
          
          <!-- load webcomponents bundle, which includes all the necessary polyfills -->
          <script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
          
          <!-- load the element -->
          <script type="module" src="my-element.js"></script>
          
          <!-- use the element -->
          <my-element></my-element>
          

          具體配置詳情,見polyfills webcomponents。

          React 與 Vue

          相信大家也比較關心 Web Components 與現有框架(如 React、Vue)相比有哪些優勢?以及各自適用場景?

          首先,Web Components 是一組 Web 平臺 API,允許開發者創建可重用的自定義元素,而無需依賴于任何特定的框架。與現有的前端框架,Web Components 有以下幾個優勢:

          1. 「標準化」:Web Components 是基于 Web 標準(如 Custom Elements、Shadow DOM 和 HTML Templates)構建的,這意味著它們得到了瀏覽器廠商的直接支持,而不依賴于任何特定的庫或框架。
          2. 「輕量級」:Web Components 不需要額外的庫或框架即可工作,這可以減少應用程序的依賴性和大小,特別是在不需要框架其他功能的情況下。
          3. 「封裝性」:通過 Shadow DOM,Web Components 可以將標記結構、樣式和腳本封裝在一起,避免全局樣式和腳本的沖突,保證了組件的獨立性和重用性。
          4. 「易于集成」:Web Components 可以與現有的框架(如 React 和 Vue)集成,開發者可以在這些框架中使用 Web Components,或者將現有的框架組件封裝成 Web Components 以供其他項目使用。

          然而,Web Components 也有其局限性,例如:

          • 「生態系統」:與 React 和 Vue 等成熟框架相比,Web Components 的生態系統較小,社區支持和資源可能不如這些框架豐富。
          • 「功能限制」:Web Components 本身不提供狀態管理、路由等高級功能,這些通常需要額外的庫或框架來實現。
          • 「性能」:對于復雜的應用程序,一些框架(如 React)通過虛擬 DOM 等技術提供了更高的性能優化,而 Web Components 需要開發者手動優化。

          總的來說,「Web Components 提供了一種標準化且框架無關的方式來構建組件,適合組件庫的開發」。而框架如 「React、Vue 則在生態系統支持、開發體驗和數據處理方面有明顯優勢,適合快速開發復雜的應用程序」

          實際應用案例

          1. 「Vue3」: Vue3 引入了對 Web Components 的原生支持,通過所謂的 “Vue Components”,它允許將 Vue 組件轉換為 Web Components。
          2. MicroApp:基于 Web Components 的一款簡約、高效、功能強大的微前端框架。
          3. Twitter:Twitter 2016 年開始將自己的嵌入式推文 從 iframe 切換成 ShadowDOM,減少了內存消耗、加快了渲染速度,并批量渲染的時候保持絲滑。
          4. svelte + vite 開發 Web Components:通過svelte + vite快速搭建 web components 的項目。
          5. 使用Polymer構建Web Components:用于構建Web Component,它提供了一套工具和API,能夠更容易地創建自定義元素。

          參考資料

          1. 「MDN Web Docs - Web Components 入門」
          2. 你不知道的Web Components - 現狀
          3. 自定義元素 v1 - 可重復使用的網絡組件
          4. Web Components Tutorial for Beginners [2019]

          總結

          Web Components 是 W3C 推動的標準化技術,它通過自定義元素的方式,允許開發者在瀏覽器中直接使用。這種技術通過 Shadow DOM 實現了組件化 DOM 隔離和樣式隔離,確保了組件的獨立性和可重用性,這些特性被現有很多借鑒和使用。

          希望這篇文章對你有所幫助!!!歡迎在評論區,一起討論。

          今前端編程中,利用語義化的 HTML 結合 CSS 來完一個組件并不是一件難事,這也意味著無論在 ReactVue 中都可以插入,不過它倆不是今天的主角,接下來我將用一個例子來介紹如何封裝一個完整的原生 HTMLWeb Components 組件,讓我們開始吧!

          HTML結構

          首先我們來了解下 HTML 中的 <details> 元素,它可以用于創建一個小部件,其中包含僅在小部件處于“打開”狀態時才可見的附加信息,<details>元素內可以包含的內容沒有任何限制。

          默認情況下,元素創建的小部件<details>處于“關閉”狀態(open標簽可使其打開)。通過單擊小部件在“打開”和“關閉”狀態之間切換,以顯示或隱藏標簽中包含的附加信息,內部標簽 <summary> 元素則可為該部件提供概要。

          一個簡單的例子如下:

          <details>
              <summary> 不能說的秘密 </summary>
              藏的這么深,可還是被你發現了
          </details>
          details {
              border: 1px solid #aaa;
              border-radius: 4px;
              padding: .5em .5em 0;
          }
          
          summary {
              font-weight: bold;
              margin: -.5em -.5em 0;
              padding: .5em;
          }
          
          details[open] {
              padding: .5em;
          }
          
          details[open] summary {
              border-bottom: 1px solid #aaa;
              margin-bottom: .5em;
          }

          使用語義化 HTML 的優點:頁面內容結構更清晰,方便開發者閱讀,更利于瀏覽器的理解與加載,搜索引擎解析與SEO優化。

          添加億點樣式

          原生元素默認的樣式很簡陋,因此我們需要為其定制一下樣式,這塊內容我們簡單帶過,只講解關鍵部分,樣式內容有省略,具體可以在文末的碼上掘金中看到呈現效果。

          .ContentWarning > summary {
            position: relative;
            list-style: none; /** 去除默認樣式 **/
            user-select: none; 
            cursor: pointer;
            /** 為其添加一個斜線背景 **/
            --stripe-color: rgb(0 0 0 / 0.1);
            background-image: repeating-linear-gradient(45deg,
                transparent,
                transparent 0.5em,
                var(--stripe-color) 0.5em,
                var(--stripe-color) 1em);
          }
          
          /** 通過var變量調整懸停時的顏色樣式 **/
          .ContentWarning>summary: hover,
          .ContentWarning>summary: focus {
            --stripe-color: rgb(150 0 0 / 0.1);
          }

          封裝模板

          現在我們來把它封裝成一個完整的組件,這需要先將 HTML 編寫在模板 template 當中,并設置一個 id,如下所示:

          <template id="warning-card">  
            <details class="ContentWarning">
              <summary>
                <strong>?? 注意:</strong> 以下為隱藏內容
              </summary>
              <slot name="desc"> 藏的這么深,可還是被你發現了 </slot>
            </details>
          </template>

          熟悉 Vue 的小伙伴應該很容易理解上面的代碼,結構很相似,不過網頁不會直接渲染它包裹的內容。此外我們還對此模板設置了一個插槽 slot,后面會講到它的作用。

          定義組件

          有了上面封裝好的模板,我們就需要在 JS 中定義成可用組件來讓其能夠被使用,調用 window 下的 customElements.define 方法,第一個參數是傳入組件名稱,我們定義組件名為: warning-card ,第二個參數傳入一個繼承了 HTMLElement 的類,在其構造方法當中獲取并克隆一個新的 HTML 節點,它會通過 appendChild 渲染到頁面當中。

          window.customElements.define('warning-card',
            class extends HTMLElement {
              constructor() {
                super();
                var templateElem=document.getElementById('warning-card');
                var content=templateElem.content.cloneNode(true);
                this.appendChild(content);
              }
            })

          接著我們就可以在頁面中把它當作組件那樣使用了:

          <warning-card> </warning-card>

          插槽與傳參

          回頭看看上面我們模板中設置的插槽 slot,此時還是沒有生效的,我們需要稍微改寫一下構造函數中的渲染方式,將 web 組件定義為一個 Shadow DOM,這樣構造的是一個可以將標記結構、樣式和行為隱藏起來,并與頁面上的其他代碼相隔離,保證不同的部分不會混在一起的獨立元素,并在最后使用 Node.cloneNode() 方法添加了模板的拷貝到 Shadow 的根結點上。

          window.customElements.define('warning-card',
            class extends HTMLElement {
              constructor() {
                super();
                var template=document.getElementById('warning-card').content;
                this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
              }
            })

          現在我們嘗試使用下組件,往其內容添加一個圖片,指向名為 descslot 插槽中:

          <warning-card>
            <img slot="desc" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ba825ffee78c4a1b9c0232e5d2f1d048~tplv-k3u1fbpfcp-watermark.image?" />
          </warning-card>

          這時你會發現,圖片插入到 details 元素的隱藏區域當中了,slot 已經成功生效,但是樣式卻消失了,這時因為組件已經被完全隔離,我們需要將樣式作用在其內部才會生效。

          <template id="warning-card">
            <style>
              <!-- TODO: 組件的樣式 -->
            </style>
            
            <details class="ContentWarning">
              <summary>
                <strong>?? 注意:</strong>
              </summary>
              <slot name="desc">THE DESCRIPTION</slot>
            </details>
          </template>

          這樣組件就正常了:

          除了定制模板中的插槽,我們也可以通過 HTML 標簽屬性來實現一些簡單的傳參,例如在 summary 標簽中顯示一個標題:

          <warning-card title="前方高能">
          </warning-card>

          我們只需要在模板中定義好這個標題的位置:

          <template id="warning-card">
            <details class="ContentWarning">
              <summary>
                  <!-- TODO: 模板中加入一個span標簽 -->
                <strong>?? 注意:</strong> <span id="title"></span>
              </summary>
            </details>
          </template>

          最后在構造函數中我們通過 document 的原生方法寫入模板中就可以了:

          window.customElements.define('warning-card',
            class extends HTMLElement {
              constructor() {
                super();
                var template=document.getElementById('warning-card').content;
                // TODO: 找到title標簽,寫入傳入組件的title屬性值
                template.querySelector('#title').innerText=this.getAttribute('title');
                this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
              }
            })

          結束

          至此,我們通過一個簡單的原生組件學習了如何編寫 Web Components,可以在此代碼片段中查看具體源碼:原生Web Components組件 - 碼上掘金原生Web Components組件 - 碼上掘金。

          以上就是文章的全部內容,希望對你有所幫助!如果覺得文章寫的不錯,可以點贊收藏,也歡迎關注,我會持續更新更多前端有用的知識與實用技巧,我是茶無味de一天,希望與你共同成長~


          主站蜘蛛池模板: 一区二区三区在线观看| 97精品国产福利一区二区三区| 成人久久精品一区二区三区| 中文字幕无码一区二区免费| 无码一区二区三区亚洲人妻| 亚洲日韩中文字幕一区| 国产精品一区二区无线| 日本一区二区三区在线网 | 国产拳头交一区二区| 欧美亚洲精品一区二区| 精品视频午夜一区二区| 国产成人无码AV一区二区在线观看| 亚洲国产精品无码久久一区二区| 精品国产鲁一鲁一区二区| 日韩精品一区二区三区毛片 | 精品日产一区二区三区手机| 中文字幕精品一区二区日本| 国产日韩一区二区三区在线观看 | 国产在线无码视频一区二区三区| 亚洲一区二区三区自拍公司| 久99精品视频在线观看婷亚洲片国产一区一级在线 | 久久精品无码一区二区三区不卡| 国产在线一区二区视频| 国精产品一区一区三区免费视频| 亚洲精品一区二区三区四区乱码| 秋霞鲁丝片一区二区三区| 久久99精品国产一区二区三区| 伊人久久大香线蕉AV一区二区| 亚洲日本一区二区一本一道| 精品国产a∨无码一区二区三区| 日本一区二区三区在线视频| 69久久精品无码一区二区| 大伊香蕉精品一区视频在线| 亚洲日韩中文字幕无码一区| 国产剧情国产精品一区| 加勒比无码一区二区三区| 亚洲一区二区三区在线观看精品中文| 性盈盈影院免费视频观看在线一区| 亚洲一区AV无码少妇电影☆| 国模无码视频一区二区三区| 人妻少妇精品视频一区二区三区 |