могу ли я передать функцию как атрибут веб-компоненту?


Я пытаюсь создать собственный веб-компонент для элемента ввода. Я хотел, чтобы компонент имел пользовательскую функцию проверки, аналогичную функции пользовательского валидатора ввода бумаги polymer. Я не уверен, что смогу передать пользовательскую функцию валидатора в качестве атрибута экземпляру входного элемента (веб-компонента). Любые предложения будут оценены.

2 3

2 ответа:

Атрибут-это строка, а не функция. Вы можете передать функцию a в виде строки, а затем вычислить ее с помощью функции 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>

Лучше всего передать функцию через свойство, так как все атрибуты являются строками.

Если вы должны передать его в качестве атрибута, то вам нужно будет преобразовать эту строку в функцию. Тогда проблема становится областью действия этой функции.

Если предполагается, что функция является глобальной по области видимости, то можно использовать строку в качестве имени свойства объекта window. Для выполнения кода Вы можете сделать следующее:

window[fnName]();

Но это довольно ограничивает, так как вы могли бы вы хотите вызвать функцию-член вашего собственного класса или объекта.

Вы можете использовать точечную нотацию в имени, например func="myObj.fnName()" , и если вы не беспокоитесь о предупреждениях использования eval, Вы можете просто сделать что-то вроде этого:

Эвал (Эл.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}});
Тогда любой, кто заботится о вашем событии, будет слушать его.