【问题标题】:Vanilla Web Component custom event attributes and propertiesVanilla Web 组件自定义事件属性和属性
【发布时间】:2017-02-18 22:44:52
【问题描述】:

在没有任何框架的情况下使用 Web 组件,实现自定义事件的正确方法是什么?例如,假设我有一个自定义元素 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() 是从属性执行字符串的适当方式吗?

【问题讨论】:

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


    【解决方案1】:

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

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

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

    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' ) )
    <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>

    【讨论】:

    • 谢谢!这似乎是正确的,我想知道是否有某种方法可以一次在所有 3 种模式中注册某个事件,但我相信你是正确的,但没有。令人惊讶的是,每个带有自定义事件的 Web 组件都应该是eval(string),但我没有看到其他建议。
    • 实际上 eval() 的使用并没有链接到自定义元素,而是链接到属性中的内联 javascript。它也用于标准元素。这就是应用受限内容政策时不允许使用内联 JavaScript 的原因。
    【解决方案2】:

    基于 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>

    【讨论】:

    • 不工作。 attr 类型始终是 Object 并且现在是函数
    • @ahmadalibaloch 你能告诉我错误吗?只需运行代码 sn-p 即可正常工作
    猜你喜欢
    • 2015-06-11
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2011-03-02
    相关资源
    最近更新 更多