1

我正在尝试获取 10 个对象的随机 Observable 流,每个对象具有以下属性:

{tileNum: '6', tileName: 'game-of-thrones' clickCount:'1'}

接下来,clickCount每次tileNum对象内部相同的对象通过流使用tileNum. 现在对于流式传输的每个tileNum需要附加到 div (0-9) 的棘手位,这些 div 将需要预先填充并clickCount增加附加到对象的相关 div。例如:

div 6 = clickCount:'1'=> {tileNum: '6'..}=>div 6 = clickCount:'2'

到目前为止,我有:

const tile = (sources) => {
  const incomingMessages$ = sources.socketIO.get('newClickStream'); // continuous Observable
  const state$ = model(incomingMessages$);
  const view$ = view(state$);
  return {
    DOM: view$,
  }
};

index.js

const model = actions =>
  actions.groupBy((tile) => tile.tileNum)
    .flatMap(
      (tile$) =>
        tile$
          .scan((prev, {tileName, tileNum}, index) => ({
          tileNum,
          tileName,
          clickCount: index + 1
        }))
          .do(x => console.log(x))
    );
export default model;

模型.js

const view = (state$) =>
  state$.map(source => {
    return div([
      h(`div#${source.tileNum}`, {}, ['${source.clickCount}']),
    ])
  });
export default view;

视图.js

现在我只能填充一个在每个新流对象上都会发生变化的 div。作为警告但不是必需的,如果可以订购 div,clickCount那将是惊人的。

4

1 回答 1

2

我稍微简化了代码并将解释作为注释插入。

const Cycle = require('@cycle/core');
const {makeDOMDriver, div} = require('@cycle/dom');
const {Observable} = require('rx');

const model = (tiles, actions) =>
  // since we already know all the tiles we just a a stream with one item which represents all the current tiles.
  Observable.just(
    // we map the array of tiles into an array of streams
    tiles.map(
    (t) => {
      return actions.incomingMessages$
        // As each of those streams belongs to one specific tile we filter
        // the click events to match this tile
        .filter((click) => {
          return click.tileNum === t
        })
        // We start with a click count of 0
        .startWith({
          tileNum: t,
          count: 0
        })
        // for each click we increse the click count by 1
        .scan(({tileNum, count}) => ({
          tileNum,
          count: count+1,
        }))
    }
  ))
;

const view = (state$) =>
  // The view is a mapping from the current stream to a vnode tree
  // the state contains the list of all tiles as array
  // This is a stream mapping
  state$.map((tiles) => div(
    // the list of tiles is a plain array
    // we map each tile into a vnode
    // this is a plain array mapping
    tiles.map((tile) => 
      // Each tile itself is a stream of click counts
      // We are only interessted in the latest click count
      // We map this stream into vnodes
      tile.map((t) => 
        // t is the the object containing the tiles id and the current click count
        // We just create a vnode populated with this data.
        div('.tile', {
          attributes: {'data-tile-num': t.tileNum}
        },t.tileNum+': '+t.count))
    )
  )
);

const main = (sources) => {
  // I replaced your incoming messages with a stream I get from click events.
  const incomingMessages$ = sources.DOM
    .select('.tile').events('click')
    .map((evt) => ({tileNum: parseInt(evt.target.dataset.tileNum, 10)}));

  // You already know all the tiles which exist.
  // You do not only want to show clicked tiles but even tiles which have never been clicked.
  // That's why instead of collection the tiles itself from a stream via groubBy
  // which can just create an array with all the tiles.
  const tiles = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,77,18,19];
  const state$ = model(tiles, {incomingMessages$});
  const view$ = view(state$);
  return {
    DOM: view$,
  }
};

const sources = {
  DOM: makeDOMDriver('.app')
}

Cycle.run(main, sources);

您可以在此处粘贴代码以在浏览器中运行它

于 2015-12-18T23:19:13.927 回答