knockoutjs single and double click

2019-03-24 09:27发布

I want to be able to bind a single and double click event to a span of text. I know I can use

data-bind ="event: { dblclick: doSomething }

for a double click, but I also need the ability to perform a different function on single click. Any suggestions?

5条回答
放我归山
2楼-- · 2019-03-24 09:43

First, I wouldn't recommend click binding at all. Instead you should use "click" and "dblclick" handlers from jQuery:

$(someParentElement).on('click', 'your span selector', function (event) {
    var myViewModelFragment = ko.dataFor(this);
    // your code here
});

$(someParentElement).on('dblclick', 'your span selector', function (event) {
    var myViewModelFragment = ko.dataFor(this);
    // your code here
});

Edit: see also Niko's suggestion regarding supporting both single and double clicks. Basically, you should count the number of clicks manually and call different functions accordingly. I assumed jQuery handles this for you but, unfortunately, it doesn't.

查看更多
smile是对你的礼貌
3楼-- · 2019-03-24 09:44
<div data-bind="singleClick: clicked, event : { dblclick: double }">
    Click Me
</div>

This will filter out the single clicks that are also double clicks.

ko.bindingHandlers.singleClick= {
    init: function(element, valueAccessor) {
        var handler = valueAccessor(),
            delay = 200,
            clickTimeout = false;

        $(element).click(function() {
            if(clickTimeout !== false) {
                clearTimeout(clickTimeout);
                clickTimeout = false;
            } else {        
                clickTimeout = setTimeout(function() {
                    clickTimeout = false;
                    handler();
                }, delay);
            }
        });
    }
};

Here is a demo.

查看更多
The star\"
4楼-- · 2019-03-24 09:44

The above answers were very helpful, but didn't give the exact solution I believe the OP was after: a simple Knockout binding that allows for exclusive single and double click events. I know the post was a year ago, but I found this article when looking to do the same thing today, so I'm posting in case this answer is useful for someone else.

The below example seems to fit the OPs requirement and may save someone some time (disclaimer: limited cross browser testing). JSFiddle: http://jsfiddle.net/UxRNy/

Also, there are the questions around whether you should use this in the first place (mobile browsers, slowing down the page, accessibility etc.) - but that is another post (e.g. https://ux.stackexchange.com/questions/7400/should-double-click-be-avoided-in-web-applications)

Example view usage:

<div data-bind="singleOrDoubleClick: { click: singleClick, dblclick: doubleClick }">
    Click or double click me...
</div>

Binding:

ko.bindingHandlers.singleOrDoubleClick= {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var singleHandler   = valueAccessor().click,
            doubleHandler   = valueAccessor().dblclick,
            delay           = valueAccessor().delay || 200,
            clicks          = 0;

        $(element).click(function(event) {
            clicks++;
            if (clicks === 1) {
                setTimeout(function() {
                    if( clicks === 1 ) {
                        // Call the single click handler - passing viewModel as this 'this' object
                        // you may want to pass 'this' explicitly
                        if (singleHandler !== undefined) { 
                            singleHandler.call(viewModel, bindingContext.$data, event); 
                        }
                    } else {
                        // Call the double click handler - passing viewModel as this 'this' object
                        // you may want to pass 'this' explicitly
                        if (doubleHandler !== undefined) { 
                            doubleHandler.call(viewModel, bindingContext.$data, event); 
                        }
                    }
                    clicks = 0;
                }, delay);
            }
        });
    }
};

The above was put together from a combination of the examples above and examples from here: https://gist.github.com/ncr/399624 - I just merged the two solutions.

查看更多
forever°为你锁心
5楼-- · 2019-03-24 09:59

@madcapnmckay provided a great answer, below is a modified version using the same idea to provide double click. And by using latest version of knockout, the vm get passed to handler as context. This can works at the same time with single click.

<div data-bind="doubleClick: clicked">
    Double click Me
</div>

--

ko.bindingHandlers.doubleClick= {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var handler = valueAccessor(),
            delay = 200,
            clickTimeout = false;

        $(element).click(function() {
            if(clickTimeout !== false) {
                handler.call(viewModel);
                clickTimeout = false;
            } else {        
                clickTimeout = setTimeout(function() {
                    clickTimeout = false;
                }, delay);
            }
        });
    }
};
查看更多
兄弟一词,经得起流年.
6楼-- · 2019-03-24 10:06

Here is my programming solution to the question:

var ViewModel = function() {
  var self = this;
  this.onSingleClick = function() {
    self.lastTimeClicked = undefined;
    console.log('Single click');
  };

  this.onDoubleClick = function() {
    console.log('Double click');
  };

  this.timeoutID = undefined;

  this.lastTimeClicked = undefined;
  this.clickDelay = 500;
  this.clickedParagraph = function(viewModel, mouseEvent) {
    var currentTime = new Date().getTime();
    var timeBetweenClicks = currentTime - (viewModel.lastTimeClicked || currentTime);
    var timeToReceiveSecondClick = viewModel.clickDelay - timeBetweenClicks;

    if (timeBetweenClicks > 0 && timeBetweenClicks < viewModel.clickDelay) {
      window.clearTimeout(viewModel.timeoutID); // Interrupt "onSingleClick"
      viewModel.lastTimeClicked = undefined;
      viewModel.onDoubleClick();
    } else {
      viewModel.lastTimeClicked = currentTime;
      viewModel.timeoutID = window.setTimeout(viewModel.onSingleClick, timeToReceiveSecondClick);
    }
  };
};

ko.applyBindings(new ViewModel(), document.getElementById("myParagraph"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-debug.js"></script>
<p id="myParagraph" data-bind="click: clickedParagraph">Click me</p>

Every "double click" is created from two single clicks. If there is a "double click", we have to make sure that the event handler for the first single click does not get executed (this is why I use window.setTimeout & window.clearTimeout). When setting the timers, we also have to consider that the first click on an element can be already a double click.

In my code I set the clickDelay to 500ms. So two clicks within 500ms are recognized as a "double click". You can also increase this value to test the behaviour of my clickedParagraph function.

查看更多
登录 后发表回答