могу ли я передать функцию как атрибут веб-компоненту?
Я пытаюсь создать собственный веб-компонент для элемента ввода. Я хотел, чтобы компонент имел пользовательскую функцию проверки, аналогичную функции пользовательского валидатора ввода бумаги polymer. Я не уверен, что смогу передать пользовательскую функцию валидатора в качестве атрибута экземпляру входного элемента (веб-компонента). Любые предложения будут оценены.
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}});