web-dev-qa-db-ja.com

関数を属性としてWebコンポーネントに渡すことはできますか?

Input要素のネイティブWebコンポーネントを作成しようとしています。コンポーネントに、ポリマーの紙入力カスタムバリデーター機能と同様のカスタム検証機能を持たせたかったのです。 (Webコンポーネント)入力要素のインスタンスに属性としてカスタムバリデーター関数を渡すことができるかどうかわかりません。任意の提案をいただければ幸いです。

8
PS.

属性は文字列であり、関数ではありません。関数を文字列として渡してから、eval()関数を使用してevaluateすることができます。セキュリティ上の理由から、これはグッドプラクティスとは見なされません。

別の解決策は、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>
6
Supersharp

すべての属性は文字列であるため、プロパティを介して関数を渡すことをお勧めします。

それを属性として渡す必要がある場合は、その文字列を関数に変換する必要があります。その後、問題はその機能の範囲になります。

関数のスコープがグローバルであると想定する場合は、文字列を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}});
_

そうすれば、あなたのイベントを気にする人は誰でもそれを聞くでしょう。

5
Intervalia

コンストラクターに渡すだけです。 カスタム要素ステートメント:

class CustomInput extends HTMLElement {
  constructor(validator) {
    super()
    this.validate = validator
  }

  /* Your Custom Input Methods */
}

次に、document.createElementの代わりにnew演算子を使用してコンポーネントをインスタンス化します。

インスタンス化:

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

関数をコンポーネントに渡したい場合は、とにかくjavascriptを介して関数をインスタンス化することを意味する必要があります。

1
spti