【问题标题】:can i pass function as attribute to web component?我可以将函数作为属性传递给 Web 组件吗?
【发布时间】:2018-06-14 20:40:28
【问题描述】:

我正在尝试为输入元素创建本机 Web 组件。我希望该组件具有自定义验证功能,类似于聚合物的纸张输入自定义验证器功能。我不确定是否可以将自定义验证器函数作为属性传递给(Web 组件)输入元素的实例。任何建议,将不胜感激。

【问题讨论】:

    标签: javascript web-component custom-element native-web-component


    【解决方案1】:

    属性是字符串,而不是函数。您可以将一个函数作为字符串传递,然后使用eval() 函数评估它。出于安全原因,这不是一种好的做法。

    另一种解决方案是将其作为 Javascript 属性传递给自定义元素:

    function validate( value ) { return Number.isInteger( value) }
    myCustomElement.validation = validate
    

    或者,使用箭头函数:

    myCustomElement.validation = v => Number.isInteger( va )
    

    class CustomInput extends HTMLElement {
        constructor() {
            super()
            var sh = this.attachShadow( { mode: 'open' } )
            sh.appendChild( tpl.content.cloneNode( true ) )
            
            var div = sh.querySelector( 'div' )
            div.addEventListener( 'input', () => { 
               if ( !this.validate( Number( div.textContent ) ) )
                div.classList.add( 'error' )
               else
                div.classList.remove( 'error' ) 
            } )        
        }
    }
    
    customElements.define( 'custom-input', CustomInput )
    
    integer.validate = v => Number.isInteger( v )
    <template id="tpl">
      <style>
        :host {
           display: inline-block ;
           min-width: 150px ;
           border: 1px solid cyan ;
        }
        
        div.error {
           color: red ;
        }
    
      </style>
      <div contenteditable></div>
    </template>
        
    <custom-input id="integer"></custom-input>

    【讨论】:

    • 也不是最佳实践,但可以将全局方法名称作为字符串传递,并且可以在没有 eval 的情况下执行。
    • @abraham 你是对的。示例:window[attribute_string]()
    【解决方案2】:

    最好通过属性传入函数,因为所有属性都是字符串。

    如果您必须将其作为属性传递,那么您需要将该字符串转换为函数。然后问题就变成了该函数的范围。

    如果您假设该函数在范围内是全局的,那么您可以使用该字符串作为window 对象的属性名称。要执行代码,您可以这样做:

    window[fnName]();
    

    但这非常有限,因为您可能想要调用自己的类或对象的成员函数。

    您可以在名称中使用点符号,例如 func="myObj.fnName()",如果您不担心使用 eval 的警告,您可以这样做:

    eval(el.getAttribute('func'));

    当然,这会让您面临各种可能的注入攻击。但是,img 标签和script 标签也是如此。

    您可以尝试更安全并这样做:

    设置不带()的属性:

    `func="myObj.fnName"`
    

    您尝试拨打电话的代码如下所示:

    var parts = el.getAttribute('func').split('.');
    var obj = window;
    var found = parts.some( part => {
      var next = obj[part];
      if (next) {
        obj = next;
        return true;
      }
    });
    
    if (found) {
      obj();
    }
    

    但这也会阻止你传入任何参数。

    这种复杂性正是 AngularJS、React、Vue 等存在的原因。这也是我避免通过属性传入函数的原因。

    如果你通过一个属性传递它,那么你的代码可以是这样的:

    el.callme = globalfunc; // or
    el.callme = this.localFunc; // or
    el.callMe = (some params) => { /* do something */ };
    

    或者任何你想要的。

    活动

    现在说了这么多,我还建议做大多数原生组件所做的事情。也就是在需要做某事时,或者当某事发生变化而外界可能对这些变化感兴趣时调度一个事件。

    在你刚刚调用的元素中

    this.dispatchEvent(new CustomEvent('event name', {bubbles: true, detail: {your detail}});
    

    那么任何关心你的活动的人都会倾听它。

    【讨论】:

      【解决方案3】:

      只需将其传递给构造函数即可。 您的自定义元素声明:

      class CustomInput extends HTMLElement {
        constructor(validator) {
          super()
          this.validate = validator
        }
      
        /* Your Custom Input Methods */
      }
      

      然后通过new 运算符而不是document.createElement 实例化您的组件。

      实例化:

      const customInputEl = new CustomInput((inputString) => {
        // your validation code
      })
      

      如果你想将一个函数传递给组件,那一定意味着你无论如何都要通过javascript实例化它。

      【讨论】:

        猜你喜欢
        • 2018-05-13
        • 1970-01-01
        • 2015-10-26
        • 1970-01-01
        • 2020-02-28
        • 2023-04-04
        • 1970-01-01
        • 2023-04-01
        • 2022-11-02
        相关资源
        最近更新 更多