中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用Web組件自定義元素

發布時間:2022-08-23 16:28:45 來源:億速云 閱讀:171 作者:iii 欄目:開發技術

這篇文章主要介紹“怎么使用Web組件自定義元素”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“怎么使用Web組件自定義元素”文章能幫助大家解決問題。

Web組件使用

名稱規范

  • 在定義它們時必須使用至少兩個單詞和一個連字符

  • 必須小寫

  • 自定義元素不能自閉合

class UserCard extends HTMLElement {
  constructor() {
    super();
  }
}
window.customElements.define('user-card', UserCard);

組件傳參數并可以寫模板包括js和css

組件的樣式應該與代碼封裝在一起,只對自定義元素生效,不影響外部的全局樣式,:host偽類,指代自定義元素本身

<html>
    <head></head>
    <body>
        <user-card name="Marty Mcfly"></user-card>
        <template id="userCardTemplate">
          <div class="profile-picture">
            <img src="marty.png" alt="Marty Mcfly" />
          </div>
          <div class="name"></div>
          <style>
           :host {
             display: flex;
             align-items: center;
             width: 450px;
             height: 180px;
             background-color: #d4d4d4;
             border: 1px solid #d5d5d5;
             box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
             border-radius: 3px;
             overflow: hidden;
             padding: 10px;
             box-sizing: border-box;
             font-family: 'Poppins', sans-serif;
           }
           .image {
             flex: 0 0 auto;
             width: 160px;
             height: 160px;
             vertical-align: middle;
             border-radius: 5px;
           }
        </style>
        </template>
        <script>
            class UserCard extends HTMLElement {
              constructor() {
                super();
                var templateElem = document.getElementById('userCardTemplate');
                var content = templateElem.content.cloneNode(true);
                // 使用name參數
                content.querySelector('.container>.name').innerText = this.getAttribute('name');
                this.appendChild(content);
              }
            }
            window.customElements.define('user-card', UserCard);    
        </script>
    </body>
</html>

Shadow Dom 影子節點

  • 沒有開啟Shadow Dom 前template的內容會直接append到user-card節點上

  • 開啟Shadow Dom后,template和user-card中間多了一個節點叫shadowRoot

  • attachShadow 的mode參數有 open 和 closed 兩個不同參數,區別是open時,外部能訪問內部節點,closed時完全隔離

  • attachShadow 是大多數標簽都支持的,比如 div,p,selection,但是a,ul,li等不支持

<script>
    class UserCard extends HTMLElement {
      constructor() {
        super();
        var shadow = this.attachShadow( { mode: 'closed' } );   /******這行開啟shadow*****/
        var templateElem = document.getElementById('userCardTemplate');
        var content = templateElem.content.cloneNode(true);
        // 使用name參數
        content.querySelector('.container>.name').innerText = this.getAttribute('name');
        shadow.appendChild(content);         /******這行template添加到shadow*****/
      }
    }
    window.customElements.define('user-card', UserCard);    
</script>

類中的構造函數和鉤子函數

class UserCard extends HTMLElement {
  // attributeChangedCallback 能監聽的屬性
  static get observedAttributes() {return ['name', 'url']; }
  constructor() {
    super();
    // 可以創Shadom,通過this.shadowRoot獲取
    // this.attachShadow({ mode: 'open' })
  }
  connectedCallback (){
      console.log('鉤子,元素append到ducument觸發')
  }
  disconnectedCallback (){
      console.log('鉤子,元素從document刪除觸發')
  }
  // 只有observedAttributes 中監聽的屬性name,url變化會觸發下面回調
  attributeChangedCallback (attr, oldVal, newVal){
      console.log('鉤子,元素屬性改變時觸發')
  }
}
window.customElements.define('user-card', UserCard);
姓名何時調用
constructor元素的一個實例被創建。對于初始化狀態、設置事件監聽器或創建shadow Dom。
connectedCallback每次將元素插入 DOM 時調用。一般主要工作代碼寫在這里。
disconnectedCallback每次從 DOM 中刪除元素時調用。一般寫清理的一些代碼。
attributeChangedCallback(attrName, oldVal, newVal)觀察屬性在添加、刪除、更新、替換時被調用。只有屬性中列出的observedAttributes屬性才會收到此回調。
adoptedCallback自定義元素已被移動到一個新的document(例如有人稱為document.adoptNode(el))。

getter/setter屬性和屬性反射

html中attribute 和 類中property 是各自獨立,想要建立映射需要手動設置

getter和setter生效

<html>
  <head></head>
  <body>
    <user-card id="usercard" name="Marty"></user-card>
    <script>
      class UserCard extends HTMLElement {
        _name = null;
        constructor() {
          super();
        }
        set name(value) {
          this._name = name;
        }
        get name() {
          return this._name;
        }
      }
      window.customElements.define("user-card", UserCard);
    </script>
  </body>
</html>

測試

document.getElementById('usercard').name = 'jack'  // 會進入setter
document.getElementById('usercard').name  // 會進入getter,返回jack
document.getElementById('usercard').getAttribute('name')  // 不會進入getter,返回Marty
document.getElementById('usercard').setAttribute('name','bob')  // 不會進入setter
document.getElementById('usercard').getAttribute('name')  // 不會進入getter,返回bob

此時,我們看到 setAttribute 和 gettAttribute 都不會觸發類中的 getter 和 setter 方法,但是可以看到如果是 .name 這樣的方式可以觸發 ,那么改造方式如下:

方式一 重寫 setAttribute :

<html>
  <head></head>
  <body>
    <user-card id="usercard" name="Marty"></user-card>
    <user-card id="uc" name="Marty Mcfly"></user-card>
    <script>
      const rawSetAttribute = Element.prototype.setAttribute;
      class UserCard extends HTMLElement {
        _name = null;
        constructor() {
          super();
          Element.prototype.setAttribute = function setAttribute(key, value) {
            // 特定的指定name
            if (key == "name") {
              this.name = value; // 這樣就能觸發 setter
            }
            rawSetAttribute.call(this, key, value);
          };
        }
        set name(value) {
          debugger;
          this._name = name;
        }
        get name() {
          debugger;
          return this._name;
        }
      }
      window.customElements.define("user-card", UserCard);
    </script>
  </body>
</html>

方式二 重寫 observedAttributes和attributeChangedCallback 監聽 name :

<html>
  <head></head>
  <body>
    <user-card id="uc" name="Marty Mcfly"></user-card>
    <script>
      class UserCard extends HTMLElement {
        static get observedAttributes() {
          return ["name"];
        }
        _name = null;
        constructor() {
          super();
        }
        attributeChangedCallback(attr, _oldVal, newVal) {
          if (attr == "name") {
            this.name = newVal;
          }
        }
        set name(value) {
          debugger;
          this._name = name;
        }
        get name() {
          debugger;
          return this._name;
        }
      }
      window.customElements.define("user-card", UserCard);
    </script>
  </body>
</html>

由此,可以看到組件在頁面渲染時會進入setter方法,而且 setAttribute,getAttribute 均進入到setter方法

document.getElementById('usercard').setAttribute('name','bob')  // 會進入setter
document.getElementById('usercard').getAttribute('name')  // 會進入getter,返回bob

擴展原生 HTML

假設您想創建一個更高級的<button>. 與其復制<button>的行為和功能,更好的選擇是使用自定義元素逐步增強現有元素。

  • 擴展現有元素的主要好處是獲得其所有特性(DOM 屬性、方法、可訪問性)。

  • Safari瀏覽器兼容性待提高

  • 要擴展一個元素,您需要創建一個繼承自正確 DOM 接口的類定義。前面例子都是繼承HTMLElement,現在更多繼承例如,按鈕HTMLButtonElement,圖片HTMLImageElement

class FancyButton extends HTMLButtonElement {
    constructor() {
        super(); 
        this.addEventListener('click', e => this.drawRipple(e.offsetX, e.offsetY));
    }
    drawRipple(x, y) {
        let div = document.createElement('div');
        div.classList.add('ripple');
        this.appendChild(div);
        div.style.top = `${y - div.clientHeight/2}px`;
        div.style.left = `${x - div.clientWidth/2}px`;
        div.style.backgroundColor = 'currentColor';
        div.classList.add('run');
        div.addEventListener('transitionend', e => div.remove());
    }
}
customElements.define('fancy-button', FancyButton, {extends: 'button'});

注意:擴展基礎元素時,對的調用 define() 略有變化。必需的第三個參數告訴瀏覽器您正在擴展哪個標簽

  • 調用方式一:

<button is="fancy-button" disabled>Fancy button!</button>
  • 調用方式二:

let button = document.createElement('button', {is: 'fancy-button'});
button.textContent = 'Fancy button!';
button.disabled = true;
document.body.appendChild(button);
  • 調用范式三

let button = new FancyButton();
button.textContent = 'Fancy button!';
button.disabled = true;

關于“怎么使用Web組件自定義元素”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

web
AI

和田县| 乌什县| 河间市| 方正县| 肥西县| 淳安县| 宁安市| 揭东县| 封丘县| 虎林市| 临洮县| 南宁市| 白朗县| 平谷区| 呼伦贝尔市| 多伦县| 营口市| 衡水市| 肥东县| 安徽省| 济宁市| 陆良县| 沙雅县| 元谋县| 景洪市| 东阿县| 随州市| 如皋市| 西青区| 邻水| 奉化市| 清徐县| 元阳县| 商城县| 盘山县| 色达县| 固阳县| 茂名市| 长武县| 丰宁| 东至县|