2012-06-13 135 views
13

我希望能夠以一個單一的和雙擊事件綁定到文本的跨度。我知道我可以使用knockoutjs單並雙擊

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

的雙擊,但我還需要在單一的點擊執行不同的功能的能力。有什麼建議麼?

+1

您可以簡單地附加click事件的事件處理程序,但這會導致大多數瀏覽器只觸發click事件(如果雙擊,則會發生兩次)。這是JavaScript中的一個普遍限制。你會在單擊事件處理程序中做一些這樣的技巧來「僞造」雙擊事件:http://stackoverflow.com/questions/6330431/jquery-bind-double-click-and-single-點擊單獨 – Niko

回答

5

首先,我不會推薦click約束力可言。相反,你應該使用"click""dblclick"處理從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 
}); 

編輯:又見Niko's suggestion關於支持單,雙點擊。基本上,you should count the number of clicks manually並相應地調用不同的功能。我認爲jQuery爲你處理這個,但不幸的是,它沒有。

+2

你爲什麼不推薦? – Niko

+0

主要是因爲它的行爲與plain-old-js'onclick'屬性類似。它將事件處理程序直接附加到元素。這有兩個問題。首先,如果你有很多這樣的元素,你最終會得到許多處理程序。 JS運行時必須分別優化它們,並增加內存使用量。其次,如果你通過Knockout'click'附加一個處理程序到某個元素,並且這個元素有一個附加了_live_'click'事件的子元素,那麼ko-click將會影響實時點擊。實時點擊不會被調用,你不會得到正確的行爲。 –

+0

史蒂夫桑德森還建議:http://blog.stevensanderson.com/2011/12/21/knockout-2-0-0-released/(見第4點。清潔事件處理) –

23
<div data-bind="singleClick: clicked, event : { dblclick: double }"> 
    Click Me 
</div> 

這將過濾出也是雙擊的單擊。

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是一個演示。

+0

我終於得到這個工作,但它是令人難以置信的緩慢。想法? –

+0

只需將延遲變量更改爲更容易的數字 –

4

@madcapnmckay提供了極大的答案, 下面是使用了同樣的想法,提供雙擊修改後的版本。通過使用最新版本的knockout,vm會作爲上下文傳遞給處理程序。這可以在單擊時同時工作。

<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); 
      } 
     }); 
    } 
}; 
+0

這對我而言不起作用。我在handler.call()上得到類似「Undefined has no method:call()」的東西。 –

+0

我喜歡這個解決方案,但它不會將正常的模型和事件參數傳遞給你的函數。 – Grandizer

+0

好吧,想出我需要讓模型和事件屬性像正常的KO事件一樣出現。只需改變以'$(element).click(function(){'到'$(element).click(function(e){'**)開頭的類似的形式,然後使用'handler.call 'to'handler.call(this,bindingContext。$ data,e);''bindingContext。$ data'是KO希望基於[this]的首選方式(http://knockoutjs.com/documentation /custom-bindings.html)以KO 3.0開頭 – Grandizer

11

以上的答案是非常有益的,但並沒有給出確切的解決方案,我相信OP是後:一個簡單的淘汰賽綁定允許獨家單並雙擊事件。我知道後是一年前,但我發現這篇文章的時候看今天做同樣的事情,所以我的情況下,發佈這個答案是對別人有用。

下面的例子似乎適合的有機磷要求,可以節省一些某人時間(聲明:有限的跨瀏覽器測試)。的jsfiddle:http://jsfiddle.net/UxRNy/

此外,有在你身邊是否應該首先使用這個問題(移動瀏覽器,減慢頁面,可訪問性等) - 但那是另一篇文章(如https://ux.stackexchange.com/questions/7400/should-double-click-be-avoided-in-web-applications

實施例視圖用法:

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

裝訂:

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); 
      } 
     }); 
    } 
}; 

以上是從一個組合放在一起上述兩例和示例從這裏:https://gist.github.com/ncr/399624 - 我只是合併了兩種解決方案。

+0

到目前爲止,最好的解決方法,謝謝:) –

+0

這個解決方案對我來說的問題是,單擊不會被處理,直到用於檢測雙擊的延遲之後,由於我想單擊選擇一行並雙擊以打開詳細信息,這會導致行選擇延遲0.2秒,這是不理想的。對於很多情況,這可能是正確的。 – dhochee

+0

@dhochee - 聽起來像是你希望點擊內部的旗幟,然後 - 你不是真的在雙擊後作爲一個獨特的事件。 這對我很好,謝謝克里斯 –

0

這裏是我的編程解決的問題:

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>

每一個 「雙擊」 是由兩個單點擊創建。如果有「雙擊」,我們必須確保第一次單擊的事件處理程序沒有得到執行(這就是爲什麼我使用window.setTimeout & window.clearTimeout)。設置定時器時,我們也必須考慮到第一次點擊某個元素可能已經是雙擊。

在我的代碼設置clickDelay到500毫秒。因此,500ms內的兩次點擊被視爲「雙擊」。您也可以增加此值來測試我的clickedParagraph函數的行爲。