区分onClick和onDoubleClick在同一元素上,以在Dart中执行不同的操作 [英] Distinguish between onClick and onDoubleClick on same element to perform different actions in Dart

查看:266
本文介绍了区分onClick和onDoubleClick在同一元素上,以在Dart中执行不同的操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做错误的建议,并将onClick和onDoubleClick置于同一元素上,每种类型的事件都会导致不同的操作。具体来说,在图像上,单击以前进到下一个图像,双击即可切换到全屏。

I want to do the ill-advised and place both an onClick and onDoubleClick on the same element with each type of event resulting in a different action. Specifically on an image, click to advance to the next image, double-click to toggle fullscreen.

当然,我得到两次点击,然后双击(虽然我知道一些浏览器只在双击之前点击一次)。

Naturally I get two clicks followed by a double-click (though I understand that some browsers only fire one click before the double-click).

我曾经想过让自己容易,将每个事件放入缓冲区(List) - 或者将event.type字符串添加到一个列表中,然后,在合适的时间,例如250或300毫秒检查缓冲区中的最后一个项目,如果doubleclick然后去全屏,否则递增列表的长度。

I had thought to make it easy on myself and place each event into a buffer (List) - or rather to add the event.type string to a list, then, after a suitable elapse of time, say 250 or 300 milliseconds examine the last item in the buffer and if doubleclick then go fullscreen else advance the length of the list.

我发现,有一个项目,我还没有弄清楚如何让计时器工作。

I have found that the list only ever has one item, and I have not worked out how to get the timer to work..

我的尝试是这一个:

void catchClickEvents(Event e) {
  var eventTypes = new List<String>();
  eventTypes.add(e.type);
  Duration duration = const Duration(milliseconds: 300);
  var timeout = new Timer(duration, () => processEvents(eventTypes));
}

void processEvents(List eTypes) {
  // just to see what is going on...
  print(eTypes);
}

这将导致此输出打印到控制台:

this results in this output printed to the console:

[click]
[click]
[dblclick]

而不是

[click, click, dblclick]

如果我放慢速度,那么在打印这三种事件类型之前会有明显的延迟

If I slow it down there is a clear delay before those three event types are printed together

所以...

更大的问题是
'darty在单击和双击并对每个执行不同的操作?'

The bigger question is 'What is the darty way to distiguish between single and double-click and perform a different action for each?'

其他问题是:

连续事件(后来清除它) - 甚至如何使用Dart的事件流作为缓冲区...

How do I fill a buffer with successive events (and later clear it down) - or even how do I use Dart's Stream of events as a buffer...

在检查之前,真正的超时方式是什么缓冲区的内容?

What is the real way timeout before examining the contents of the buffer?

(我猜最终的问题是我应该放弃努力,并解决一个常规的按钮与图标符号吗? )

(and I guess the final question is 'should I abandon the effort and settle for a conventional set of buttons with glyph-icons?'!)

推荐答案

您的网页应尽快对用户输入做出反应。如果您等待确认双击 - 您的onClick将变得不那么敏感。您可以通过在第一次单击后更改元素的可视状态(例如,播放动画)来隐藏问题,但它可能会混淆用户。而且对于手持设备来说更糟。另外,如果元素只对onClick事件作出反应,你可以欺骗并听onmousedown - 它将使你的UI更加灵敏。

Your page should react on user inputs as fast as possible. If you wait to confirm double click - your onClick will become much less responsive. You can hide the problem by changing visual state of the element(for example, playing animation) after first click but it can confuse user. And it gets even worse with handheld. Also if element has to react only on onClick event, you can "cheat" and listen to onmousedown instead - it will make your UI much more responsive.

最重要的是,从客户端到客户端,双击可能有明显不同的触发时间间隔,这不直观,对于用户,你可以双点击一些东西。

On top of all this, double click, from client to client, may have noticeably different trigger time interval and it isn't intuitive, for user, that you can double click something. You will have to bloat your interface with unnecessary hints.

编辑:添加了我的解决方案。它应该是相当可扩展的和未来的证明。

edit: Added my solution. It should be fairly extensible and future proof.

import 'dart:html';
import 'dart:async';
import 'dart:math';

//enum. Kinda... https://code.google.com/p/dart/issues/detail?id=88
class UIAction {
  static const NEXT = const UIAction._(0);
  static const FULLSCREEN = const UIAction._(1);
  static const ERROR = const UIAction._(2);
  final int value;
  const UIAction._(this.value);
}

/**
 *[UIEventToUIAction] transforms UIEvents into corresponding  UIActions.
 */
class UIEventToUIAction implements StreamTransformer<UIEvent, UIAction> {

/**
 * I use "guesstimate" value for [doubleClickInterval] but you can calculate
 * comfortable value for the user from his/her previous activity.
 */
  final Duration doubleClickInterval = const Duration(milliseconds: 400);

  final StreamController<UIAction> st = new StreamController();

  Stream<UIAction> bind(Stream<UIEvent> originalStream) {
    int t1 = 0,
        t2 = 0;
    bool isOdd = true;
    Duration deltaTime;
    originalStream.timeout(doubleClickInterval, onTimeout: (_) {
      if ((deltaTime != null) && (deltaTime >= doubleClickInterval)) {
        st.add(UIAction.NEXT);
      }
    }).forEach((UIEvent uiEvent) {
      isOdd ? t1 = uiEvent.timeStamp : t2 = uiEvent.timeStamp;
      deltaTime = new Duration(milliseconds: (t1 - t2).abs());
      if (deltaTime < doubleClickInterval) st.add(UIAction.FULLSCREEN);
      isOdd = !isOdd;
    });
    return st.stream;
  }
}


void main() {

  //Eagerly perform time consuming tasks to decrease the input latency.
  Future NextImageLoaded;
  Future LargeImageLoaded;
  element.onMouseDown.forEach((_) {
    NextImageLoaded = asyncActionStub(
        "load next image. Returns completed future if already loaded");
    LargeImageLoaded = asyncActionStub(
        "load large version of active image to show in fullscreen mode."
            "Returns completed future if already loaded");
  });


  Stream<UIEvent> userInputs = element.onClick as Stream<UIEvent>;

  userInputs.transform(new UIEventToUIAction()).forEach((action) {
    switch (action) {
      case UIAction.FULLSCREEN:
        LargeImageLoaded.then( (_) =>asyncActionStub("fullscreen mode") )
        .then((_) => print("'full screen' finished"));
        break;
      case UIAction.NEXT:
        NextImageLoaded.then( (_) =>asyncActionStub("next image") )
        .then((_) => print("'next image' finished"));
        break;
      default:
        asyncActionStub("???");
    }
  });
}


final DivElement element = querySelector("#element");

final Random rng = new Random();
final Set performed = new Set();
/**
 *[asyncActionStub] Pretends to asynchronously do something usefull.
 * Also pretends to use cache.
 */
Future asyncActionStub(String msg) {
  if (performed.contains(msg)) {
    return new Future.delayed(const Duration(milliseconds: 0));
  }
  print(msg);
  return new Future.delayed(
      new Duration(milliseconds: rng.nextInt(300)),
      () => performed.add(msg));
}

这篇关于区分onClick和onDoubleClick在同一元素上,以在Dart中执行不同的操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆