5

如何使用 Cycle 聚焦输入?我是否需要进入 DOM 并.focus()使用或不使用 jQuery 进行调用,或者是否有其他使用 Cycle/RxJS 的方法?

4

3 回答 3

6

的,您确实需要进入 DOM 内部并.focus()使用或不使用 jQuery 进行调用。然而,这是一个副作用,将这些副作用转移到所谓的驱动程序是 Cycle.js 的惯例。

司机需要知道的两个问题是:

  • 你想关注哪个元素?
  • 你什么时候想聚焦元素?

这两个问题的答案都可以通过一个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集中注意力。

于 2016-03-25T11:04:18.687 回答
5

您可以根据自己的情况进行调整,但这应该说明如何解决您的问题。假设您有一个文本输入和一个按钮。单击按钮时,您希望焦点保持在文本输入上。

首先编写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中。

于 2016-02-03T21:16:12.893 回答
2

这是一个例子,由 Staltz 先生自己编写:https ://github.com/cyclejs/cycle-examples/blob/master/autocomplete-search/src/main.js#L298

于 2016-01-28T08:00:40.837 回答