Cycle で入力をフォーカスするにはどうすればよいですか? DOM 内にアクセスして、.focus()
jQuery を使用するかどうかに関係なく呼び出す必要がありますか、それとも Cycle/RxJS を使用する別の方法がありますか?
3 に答える
はい、DOM 内にアクセスして、.focus()
jQuery を使用するかどうかに関係なく呼び出す必要があります。ただし、これは副作用であり、これらの種類の副作用をいわゆるdriverに移動するのが Cycle.js の規則です。
ドライバーが知っておく必要がある 2 つの質問は次のとおりです。
- どの要素に注目したいですか?
- いつ要素にフォーカスしたいですか?
両方の質問に対する答えは、DOM 要素の単一のストリームによって提供できます。
ドライバーを作成する
まず、ドライバーを作成します。と呼びましょうSetFocus
。いわゆる読み取り専用ドライバーにします。アプリのシンクから読み取りますが、アプリにソースを提供しません。を読んでいるため、ドライバーの関数は、ストリームとなる正式なパラメーターを受け入れる必要があります。それを呼び出しますelem$
。
function makeSetFocusDriver() {
function SetFocusDriver(elem$) {
elem$.subscribe(elem => {
elem.focus();
});
}
return SetFocusDriver;
}
このドライバーは、ストリームに到着した DOM 要素を受け取り、それを呼び出します.focus()
。
ドライバーを使用する
Cycle.run
関数に提供されるドライバーのリストに追加します。
Cycle.run(main, {
DOM: makeDOMDriver('#app'),
SetFocus: makeSetFocusDriver() // add a driver
});
次に、メイン関数で:
function main({DOM}) {
// setup some code to produce the elem$ stream
// that will be read by the driver ...
// [1]: say _when_ we want to focus, perhaps we need to focus when
// the user clicked somewhere, or maybe when some model value
// has changed
// [2]: say _what_ we want to focus
// provide the textbox dom element as actual value to the stream
// the result is:
// |----o-----o-----o--->
// where each o indicates we want to focus the textfield
// with the class 'field'
const textbox$ = DOM.select('.field').observable.flatMap(x => x); // [2]
const focusNeeded = [
clickingSomewhere$, // [1]
someKindofStateChange$ // [1]
];
const focus$ = Observable.merge(...focusNeeded)
.withLatestFrom(textbox$, (_, textbox) => textbox); // [2]
// ...
// [*]: Add driver to sinks, the driver reads from sinks.
// Cycle.js will call your driver function with the parameter
// `elem$` being supplied with the argument of `focus$`
return {
DOM: vtree$,
SetFocus: focus$, // [*]
};
}
次に、集中しfocusNeeded
たいときに言うように構成できます。.field
独自の状況に合わせて調整できますが、これは問題を解決する方法を示しているはずです。テキスト入力とボタンがあるとしましょう。ボタンがクリックされたときに、テキスト入力にフォーカスを置いたままにする必要があります。
最初にインテント()関数を書きます:
function intent(DOMSource) {
const textStream$ = DOMSource.select('#input-msg').events('keyup').map(e => e.target);
const buttonClick$ = DOMSource.select('#send-btn').events('click').map(e => e.target);
return buttonClick$.withLatestFrom(textStream$, (buttonClick, textStream) => {
return textStream;
});
}
次に、失われたフォーカスの副作用を処理するためのシンクを持つメイン
function main(sources) {
const textStream$ = intent(sources.DOM);
const sink = {
DOM: view(sources.DOM),
EffectLostFocus: textStream$,
}
return sink;
}
次に、この副作用を処理するドライバーは次のようになります
Cycle.run(main, {
DOM: makeDOMDriver('#app'),
EffectLostFocus: function(textStream$) {
textStream$.subscribe((textStream) => {
console.log(textStream.value);
textStream.focus();
textStream.value = '';
})
}
});
例全体はこのcodepenにあります。
以下は、Staltz 氏自身が書いた一例です: https://github.com/cyclejs/cycle-examples/blob/master/autocomplete-search/src/main.js#L298