12

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

4

3 回答 3

9

属性是字符串,而不是函数。您可以将 aa 函数作为字符串传递,然后使用该函数对其进行评估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>

于 2018-06-14T21:52:41.697 回答
4

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

如果必须将其作为属性传递,则需要将该字符串转换为函数。然后问题成为该功能的范围。

如果您假设该函数在范围内是全局的,那么您可以使用该字符串作为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}});

然后任何关心您的活动的人都会倾听它。

于 2018-06-15T15:39:54.573 回答
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 实例化它。

于 2019-05-31T22:36:24.760 回答