Vanilla Web Component自定义事件属性和属性

时间:2017-02-18 22:44:53

标签: javascript event-handling web-component custom-element

在没有任何框架的情况下使用Web Components,实现自定义事件的正确方法是什么?例如,假设我有一个自定义元素x-pop-out,其自定义事件为pop我希望以下所有内容都能正常工作:

<x-pop-out onpop="someGlobal.doSomething()"/>

var el = document.getElementsByTagName('x-pop-out')[0];
el.onpop = ()=> someGlobal.doSomething();
//or
el.addEventListener('pop', ()=> someGlobal.doSomething());

我得到的最后一个怎么做,但我是否需要为每个人自定义实现属性和getter / setter?另外,eval()是从属性执行字符串的适当方法吗?

2 个答案:

答案 0 :(得分:3)

事件监听器解决方案(第三个)是最简单的,因为您不必定义任何特殊的事件来捕获事件。

事件处理程序解决方案需要创建eval()(第一个,来自属性)或明确调用该函数(第二个)。

如果您不能使用eval,则可以改为解析属性字符串。

&#13;
&#13;
customElements.define( 'x-pop-out', class extends HTMLElement {
    connectedCallback() {
        this.innerHTML = `<button id="Btn">pop</button>`

        this.querySelector( 'button' ).onclick = () => {
            this.dispatchEvent( new CustomEvent( 'pop' ) )
            if ( this.onpop )
                this.onpop()
            else
                eval( this.getAttribute( 'onpop' ) )
        }            
    }
} )

XPO.addEventListener( 'pop', () => console.info( 'pop' ) )
&#13;
<x-pop-out id=XPO onpop="console.log( 'onpop attribute' )"></x-pop-out>
<hr>
<button onclick="XPO.onpop = () => console.log( 'onpop override' )">redefine onpop</button>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

基于SuperSharp answer。他的建议只适用于控制台日志而不是事件。我使用的解决方案是覆盖dispatchEvent并使其也创建自定义HTML事件属性。

遵循使用'on'+ event.type的标准。我们使用with在新函数中屏蔽属性,并检查属性是否为函数,并在需要时传入事件。

dispatchEvent(event) {
  super.dispatchEvent(event);
  const eventFire = this['on' + event.type];
  if ( eventFire ) {
    eventFire(event);
  } else {
  const func = new Function('e',
    'with(document) {'
       + 'with(this) {'
         + 'let attr = ' + this.getAttribute('on' + event.type) +';'
         + 'if(typeof attr === \'function\') { attr(e)};
       + }'
     + '}'
   );
   func.call(this, event);
   } 
}

示例:

class UserCard extends HTMLElement {

  constructor() {
    // If you define a constructor, always call super() first as it is required by the CE spec.

    super(); //

  }


  dispatchEvent(event) {
    super.dispatchEvent(event);

    const eventFire = this['on' + event.type];
    if (eventFire) {
      eventFire(event);
    } else {
      const func = new Function('e',

        'with(document) {' +
        'with(this) {' +
        'let attr = ' + this.getAttribute('on' + event.type) + ';' +
        'if(typeof attr === \'function\') { attr(e)};' +
        '}' +
        '}');
      func.call(this, event);
    }

  }

  connectedCallback() {
    this.innerHTML = `<label>User Name</label> <input type="text" id="userName"/>
   <label>Password</label> <input type="password" id="passWord"/>
    <span id="login">login</span>`;
    this.test = this.querySelector("#login");
    this.test.addEventListener("click", (event) => {
      this.dispatchEvent(
        new CustomEvent('pop', {
          detail: {
            username: 'hardcodeduser',
            password: 'hardcodedpass'
          }
        })
      );
    })


  }

}

customElements.define('user-card', UserCard);

function onPop2(event) {
  debugger;
  console.log('from function');
}
<user-card id="XPO" onpop="onPop2"></user-card>
<hr>
<user-card id="XPO" onpop="console.log('direct Console')"></user-card>