2017-11-11 70 views
1

TL; DR; 是否可以在HTML(非JS)中爲自定義事件定義事件偵聽器?針對webcomponents /自定義事件(JS)的基於HTML的事件偵聽器

在此基礎上codepen,我試圖做到以下幾點:

<my-checkreport 
    onclick="myFunction()" 
    oncheck="myFunction1)" 
    check="myFunction()" 
></my-checkreport> 

其中myFunction做一些console.log的東西,我可以在瀏覽器控制檯中看到。本地onlick作品,當然,但既不oncheck也不check工作,爲自定義事件定義如下:(從上面取源鏈接codepen):

customElements.define('my-checkbox', class extends HTMLElement { 
    constructor() { 
    super(); 
    const shadowRoot = this.attachShadow({mode: 'open'}); 
    this.checkEvent = new CustomEvent("check", { 
     bubbles: true, 
     cancelable: false, 
    }); 
    shadowRoot.innerHTML = ` 
     <label> 
     <input type="checkbox" id="my-checkbox"></input> 
     Dummy Enabled 
     </label>`; 
    shadowRoot.querySelector('#my-checkbox').addEventListener('click', (e) => { 
     console.log('checked', e.target.checked); 
     this.dispatchEvent(this.checkEvent); 
    }); 
    } 
}); 

是否有可能把事件偵聽器在HTML自定義事件?

+0

也許這個答案可以幫助你:https://stackoverflow.com/a/41218056/4600982或更可能是這一個:https://stackoverflow.com/a/42321978/4600982 – Supersharp

回答

1

沒有任何JS代碼?但是,您可以在元素的構造函數中定義一個屬性,以獲取元素屬性並對其進行評估。例如,

constructor() { 
    // Other code. 
    const onCheckFunc = this.getAttribute('oncheck') 
    this.addEventListener('check',() => eval(onCheckFunc)) 
    // Rest of your code. 
} 

編輯:由於@Intervalia提到的,你不應該檢查元素的屬性在constructor。你可以在connectedCallback中這樣做。但要記住:

  • 一般來說,工作要推遲到connectedCallback儘可能,尤其是工作介入抓取資源或渲染。但是請注意,connectedCallback可以多次調用,所以任何真正的一次性初始化工作都需要一個警衛來防止它運行兩次。
  • 通常,constructor應該用於設置初始狀態和默認值,並設置事件偵聽器和可能的影子根。
+0

記住,它是反對Web組件規則在構造函數中讀取一個屬性。 https://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance *元素的屬性和孩子不能被檢查... * – Intervalia

2

這是最接近我可以來模擬事件處理程序的DOM聲明。從我所知道的情況來看,這段代碼可以完成所有事情,DOM可以用於內置的事件處理程序。

<!DOCTYPE html> 
<html> 
    <head> 
    <meta charset="utf-8"> 
    <title>On-Event Test</title> 
    <script> 
    function onCheckHandler(event) { 
     console.log('onCheckHandler: %O', event); 
     event.stopPropagation(); 
     event.stopImmediatePropagation(); 
     //event.preventDefault(); 
    } 

    function eventListener(event) { 
     console.log('eventListener: %O', event); 
    } 
    (function() { 
     var template = `<div>Click to Check</div>`; 
     class MyEl extends HTMLElement { 
     constructor() { 
      super(); 

      var rootEl = this.attachShadow({mode: 'open'}); 
      rootEl.innerHTML = template; 
      rootEl.firstChild.addEventListener('click',() => { 
      var checkEvent = new CustomEvent("check", {bubbles:true,cancelable:true}); 
      if (this.dispatchEvent(checkEvent)) { 
       // Do default operation here 
       console.log('Performing default operation'); 
      } 
      }); 
      this._onCheckFn = null; 
     } 

     static get observedAttributes() { 
      return ['oncheck']; 
     } 

     attributeChangedCallback(attrName, oldVal, newVal) { 
      if (attrName === 'oncheck' && oldVal !== newVal) { 
      if (newVal === null) { 
       this.oncheck = null; 
      } 
      else { 
       this.oncheck = Function(`return function oncheck(event) {\n\t${newVal};\n};`)(); 
      } 
      } 
     } 

     get oncheck() { 
      return this._onCheckFn; 
     } 
     set oncheck(handler) { 
      if (this._onCheckFn) { 
      this.removeEventListener('check', this._onCheckFn); 
      this._onCheckFn = null; 
      } 

      if (typeof handler === 'function') { 
      this._onCheckFn = handler; 
      this.addEventListener('check', this._onCheckFn); 
      } 
     } 
     } 

     // Define our web component 
     customElements.define('my-el', MyEl); 
    })(); 
    </script> 
    </head> 
    <body> 
    <my-el oncheck="onCheckHandler(event)"></my-el> 
    </body> 
</html> 

爲了得到這個工作,你需要兩個步驟:

步驟一:

分量代碼必須支持的屬性變化。

當屬性設置爲字符串(要調用的函數)時,代碼將創建一個臨時函數,用於嘗試調用作爲屬性值提供的函數。該函數然後傳遞到第二步。

當屬性設置爲其他任何內容或者屬性被刪除時,代碼將null傳遞給第二步。

第二步:

分量代碼必須支持oncheck屬性。

每當此屬性被更改時,它需要通過調用removeEventListener來刪除此屬性的任何先前定義的事件處理程序。

如果該屬性的新值是一個函數,那麼該函數將調用addEventListener作爲處理函數。

這很好玩搞清楚。起初我以爲基於DOM的oncheck處理程序總是第一個。但通過測試onclickaddEventHandler('click'),我發現事件處理程序是按收到的順序添加的。如果在DOM中提供了onclick,則首先添加事件偵聽器。如果您然後調用removeAttribute('onclick'),然後setAttribute('onclick', 'handler(event)')那麼該事件處理程序將移動到列表的末尾。

所以這段代碼正好與click事件相同。