如何使用 Cycle.js 和 RxJS 聚焦输入?
How do I focus an input with Cycle.js and RxJS?
如何使用 Cycle 聚焦输入?我是否需要到达 DOM 内部并在有或没有 jQuery 的情况下调用 .focus()
,还是有其他方法可以使用 Cycle/RxJS?
这是一个例子,由 Staltz 先生亲自编写:https://github.com/cyclejs/cycle-examples/blob/master/autocomplete-search/src/main.js#L298
你可以根据自己的情况量身定做,但是这应该说明如何解决你的问题。假设您有一个文本输入框和一个按钮。单击按钮时,您希望焦点保留在文本输入上。
先写intent()函数:
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;
});
}
然后是 main,它有一个 sink 来处理失去焦点的副作用
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中。
是,你确实需要到达 DOM 内部并在有或没有 jQuery 的情况下调用 .focus()
。然而,这是 side-effect 并且 Cycle.js 约定将这些类型的副作用转移到 so-called driver.
driver 需要知道的两个问题是:
- 您想关注哪个元素?
- 何时要聚焦元素?
这两个问题的答案都可以由单个 DOM 元素流 提供。
创建driver
首先制作你的driver。我们称它为 SetFocus
。我们将其设为 so-called read-only driver。它将从应用程序的接收器中读取,但不会向应用程序提供源。因为是读,所以driver的函数需要接受一个形式参数,将是一个流,称它为elem$
:
function makeSetFocusDriver() {
function SetFocusDriver(elem$) {
elem$.subscribe(elem => {
elem.focus();
});
}
return SetFocusDriver;
}
这个 driver 获取到达流中的任何 DOM 元素并对其调用 .focus()
。
使用Driver
将其添加到提供给 Cycle.run
函数的 driver 列表中:
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
何时聚焦。
如何使用 Cycle 聚焦输入?我是否需要到达 DOM 内部并在有或没有 jQuery 的情况下调用 .focus()
,还是有其他方法可以使用 Cycle/RxJS?
这是一个例子,由 Staltz 先生亲自编写:https://github.com/cyclejs/cycle-examples/blob/master/autocomplete-search/src/main.js#L298
你可以根据自己的情况量身定做,但是这应该说明如何解决你的问题。假设您有一个文本输入框和一个按钮。单击按钮时,您希望焦点保留在文本输入上。
先写intent()函数:
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;
});
}
然后是 main,它有一个 sink 来处理失去焦点的副作用
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中。
是,你确实需要到达 DOM 内部并在有或没有 jQuery 的情况下调用 .focus()
。然而,这是 side-effect 并且 Cycle.js 约定将这些类型的副作用转移到 so-called driver.
driver 需要知道的两个问题是:
- 您想关注哪个元素?
- 何时要聚焦元素?
这两个问题的答案都可以由单个 DOM 元素流 提供。
创建driver
首先制作你的driver。我们称它为 SetFocus
。我们将其设为 so-called read-only driver。它将从应用程序的接收器中读取,但不会向应用程序提供源。因为是读,所以driver的函数需要接受一个形式参数,将是一个流,称它为elem$
:
function makeSetFocusDriver() {
function SetFocusDriver(elem$) {
elem$.subscribe(elem => {
elem.focus();
});
}
return SetFocusDriver;
}
这个 driver 获取到达流中的任何 DOM 元素并对其调用 .focus()
。
使用Driver
将其添加到提供给 Cycle.run
函数的 driver 列表中:
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
何时聚焦。