2013-10-16 5 views
0

working tool (첫 번째 코드 블록 참조)에 클릭하여 고정 기능을 포함하고 싶습니다.OnMouseUp/Down 기능 통합?

왼쪽 버튼을 누르고 있으면 빠르게 추가하고 오른쪽 버튼을 누르면 빨리 감속하고 싶습니다. 단일 클릭 기능과 마찬가지로 이미 있지만 더 빠른 옵션입니다.

저는 초보자이기 때문에 작업 데모를 크게 환영합니다. 고맙습니다.

코드 :

<!DOCTYPE html> 
<html> 
<head> 
<script> 

var Alexander = 
    { 
     Strength: "AlexanderStrengthVal", 
     Bonus: "AlexanderRemainingBonusVal", 
     Limits: { 
     Strength: { 
      max: 80, 
      min: 60 
     } 
       } 
    }; 

function add(character, stat) 
{ 
    var txtNumber = document.getElementById(character[stat]); 
    var newNumber = parseInt(txtNumber.value) + 1; 
    if(newNumber > character.Limits[stat].max) return; 
    var BonusVal = document.getElementById(character["Bonus"]); 
    if(BonusVal.value == 0) return; 
    var newBonus = parseInt(BonusVal.value) - 1; 
    BonusVal.value = newBonus; 
    txtNumber.value = newNumber; 
} 

function subtract(e, character, stat) 
{ 
    e.preventDefault(); 
    var txtNumber = document.getElementById(character[stat]); 
    var newNumber = parseInt(txtNumber.value) - 1; 
    if(newNumber < character.Limits[stat].min) return; 
    var BonusVal = document.getElementById(character["Bonus"]); 
    var newBonus = parseInt(BonusVal.value) + 1; 
    BonusVal.value = newBonus; 
    txtNumber.value = newNumber; 
} 

</script> 
</head> 
<body> 

    <table cellpadding='5' border='1' style="text-align:center; color:#ffffff; background-color:#444444; font-family:arial; font-size:14px"> 
    <tr> 
     <td><b>Character</b></td> 
     <td><b>Strength</b></td> 
     <td><b>Spending Bonus</b></td> 
    </tr> 
    <tr> 
     <td>Alexander</td> 
     <td> 
     <input 
     id="AlexanderStrengthVal" 
     type="text" value="60" 
     style="width:30px; border:none; color:#ffffff; background-color:transparent; text-align:center" 
     onfocus="this.blur()" 
     onClick="add(Alexander, 'Strength')" 
     onContextMenu="subtract(event, Alexander, 'Strength');" 
     /> 
     </td> 

     <td> 
     <input 
     id="AlexanderRemainingBonusVal" 
     type="text" 
     value="30" 
     style="width:30px; border:none; color:#ffffff; background-color:transparent; text-align:center" 
     /> 
     </td> 

    </tr> 
    </table> 
</body> 
</html> 
+1

함께 코드의 다른 비트를 볼트 노력의 문제입니다! 클릭 및 보류 기능으로 무엇을하려고하는지 정확히 모르겠지만 이론적으로 버튼 대신 문서에 핸들러를 할당 할 수 있어야합니다. –

+2

발견 한 코드는 버튼이 없으면 작동하지 않습니다. 버튼없이 마우스 이벤트를 조사해야합니다 ... http://www.w3schools.com/jsref/event_onmousedown.asp를보고 어떤 버튼이 눌러 졌는지 탐지하는 예제를 확인하십시오. –

답변

1

어떻게 그 방법을 시도, 타이머 .setTimeout() 사용하는 함수, .setInterval().onmousedown에, .onmouseup, .onmouseout 후크를 부착 어떻습니까?

또는 이와 비슷한 작업을 수행 할 준비가되었습니다. fiddle.

// 
// #Timer 
// 
// if you are unfamiliar with this code construct, 
// (I think it is called 'module' pattern IIRC) 
// this is base structure behind it: 
// 
// defines/runs/sets_context/passes_arguments of anonymous function in one go 
// makes 'safe' (private) scope for module definition 
// module assignment is performed at the top 
// where it is easy to spot, rename, and shift around where needed 
// 'factory' is a function that is supposed to return whatever the 'module' is 
// be it a function, object, or whatever, 
// and to assign it to arbitrary 'host' object, 
// providing room to rename it in case of naming collisions 
// 
// ;((function (name, factory) { 
// 
// // this === module's context 
// 
// this[name] = factory(); 
// 
// }).call(
// 
// hostObject,  // object to attach module to 
// "customModuleName", // arbitrary name to use for it 
// function() {  // factory method that is supposed to define/return (preferably independent) piece of functionality 
// 
//  // save to do whatever is required in this scope 
//  // without the impact on globals. 
//  // declare identifiers, etc. 
//  // whatever this function returns is assigned to context above 
// 
//  function doStuff() { 
//  return Math.random() > .5; 
//  } 
// 
//  var 
//  _api = 
//  { 
//   props : 1, 
//   methods : function() { 
//   var stuff; 
//   stuff = doStuff(); 
//   return stuff; 
//   } 
//  }; 
// 
//  // ...code 
// 
//  // and return whatever the module's goal is 
//  return _api; 
// 
// } 
// 
// )); 
// 
;((function (field, dfn) { 
    // add 'Timer' identifier to global scope 
    this[field] = dfn(); 
}).call(
window, // object to asign function to 
"Timer", // property name to use 
function() { 

    // helpers and 
    // shortcuts for use by code bellow 

    var undef; // === undefined 
    var aproto = Array.prototype; 
    var _ = { 

     // used to filter functions in timer api arguments 
     isfn  : function (o) { 
     return typeof o == "function"; 
     }, 

     // is provided parameter an object 
     isobj : function (o) { 
     return o === Object(o); 
     }, 

     // checks provided parameter, 
     // returns false for: null, undefined, NaN 
     // used to check if parameter is passed to timer methods 
     isvalid : function (o) { 
     return (o != null) && (o === o); 
     }, 

     // removes array elements that match passed arguments 
     // supposed to be used through .call/.apply function method: 
     // _.gc.call(arr, "a", "b", "c"), etc. 
     // iterates array backward, '.splice-ing' it by 1 if current value 
     // matches one of provided arguments 
     // returns gc-ed array 
     // used by .off() method to remove scheduled function(s) 
     gc  : function() { 

     // this === (array) target_array_to_cleanup 

     // provided arguments[] to remove 
     var togc = _.slice(arguments); 

     for (
      var i = this.length; 
      --i >= 0; 
      (togc.indexOf(this[i]) != -1) 
      && this.splice(i, 1) 
     ); 
     return this; 
     }, 

     // empties passed array and returns it 
     // used by .off() method to remove scheduled functions 
     empty : function (arr) { 
     return (arr.length = 0, arr); 
     }, 

     // loops array 
     // uses native .forEach if available 
     // otherwise simulates the behaviour 
     // returns iterated array 
     // used by .fire() method to loop through registered function[] and 
     // to execute them in order 
     arreach : (function() { 
     return (typeof aproto.forEach == "function") 
       ? function (arr, fn) { 
        arr.forEach(fn); 
        return arr; 
       } 
       : function (arr, fn) { 
       for (
        var i = 0, 
        l = arr.length; 
        i < l; 
        (i in arr) 
        && fn.call(this, arr[i], i, arr), 
        i++ 
       ); 
       return arr; 
       }; 
     })(), 

     // substitues content of array (arr) 
     // with provided array's content (arrnew) 
     // returns modified array (arr) 
     // used by .start() method to quickly switch timer handler arguments 
     // if any are passed to it 
     arrsub : function (arr, arrnew) { 
     return (aproto.push.apply(_.empty(arr), arrnew), arr); 
     }, 

     // loops own properies of an object and retuns it 
     // used by .off() method, ant _.init() function 
     // to perform appropriate tasks (object cleanup/property_assignment) 
     owneach : function (obj, fn) { 
     for (
      var l in obj 
     ) { 
      _.owns(obj, l) 
      && fn.call(obj, l, obj[l]); 
     } 
     return obj; 
     }, 

     // asyns a function 
     // returns new function based on provided one 
     // that will run asyncrounously 
     // used to async 'tick' handlers 
     async : function (fn) { 
     return function() { 
      var host = this; 
      var args = _.slice(arguments); 
      var origfn = fn; 
      setTimeout(
      function() { 
       origfn.apply(host, args); 
      } 
     ); 
      return this; 
     }; 
     }, 

     // asigns properties of an object (propsObj) 
     // to provided (obj) object 
     // used in couple of places to quickly assign properties/values to objects 
     init  : function (obj, propsObj) { 
     _.owneach(
      propsObj, 
      function (field, value) { 
      obj[field] = value; 
      } 
     ); 
     return obj; 
     }, 

     // core {}.hasOwnProperty shortcut 
     owns  : function (obj, field) { 
     return Object(obj).hasOwnProperty(field); 
     }, 

     // native [].slice shortcut 
     // used to turn dynamic arguments[] to real array 
     slice : function (args, m, n) { 
     return aproto.slice.call(args, m, n); 
     }, 

     // empties an object 
     // used by .off() method to empty evHandler functions cache 
     vacate : function (obj) { 
     for (
      var l in obj 
     ) { 
      try { 
      _.owns(Object.prototype, l) 
      || (delete obj[l]); 
      } catch(xc) {} 
     } 
     return obj; 
     } 
    }; 

    // main function uses this strings 
    // for subscribing/removing/executing handlers 
    var timerEvent = { 
     start : "tickStart", 
     stop : "tickStop", 
     tick : "tick", 
     end : "tickEnd" 
    }; 
    return (function (listener) { 


     // main timer function 
     // @param1, float, optional, how often to fire 'tick' events, default == 1000, (== 1sec) 
     // @param2, integer, optional, how many times to fire 'tick' event, default == Infinity 
     // returns, Object, object with following api: 
     // 
     // registering functions for 'timerEvent' events: 
     // 
     // .on(evType, func) 
     // # caches a function for given event type (of 'timerEvent' object) 
     // .off([ evType, func]) 
     // # unregisteres function for given event type 
     // # if no function is provided removes all functions registered for event 'evType' 
     // # if nothing is provided removes all registered functions 
     // .fire(evType [, ...params_for_registered_handlers ]) 
     // # runs functions registered for given event type 
     // # passing provided arguments to them, if any 
     // # used internaly when .start() method is called 
     // 
     // these are for controling timer object: 
     // 
     // .start([ ...params]) 
     // # starts triggering 'tick' events updating internal state 
     // # passes provided parameters to triggerd functions, 
     // # (available through .data property of object passed to handlers) 
     // .stop() 
     // # pauses triggering 'tick' events (if Timer object is in 'running state') 
     // # triggers 'tickStop' event 
     // .reset() 
     // # nulls internal state, stops dispatching 'ticks', resets counter 
     // # triggers 'tickEnd' event 
     // 
     // these are for quering internal timer state: 
     // 
     // .currentCount() 
     // # how many times Timer fired so far 
     // # returns, integer 
     // .delay() 
     // # gives timer's delay 
     // # returns, float 
     // .repeatCount() 
     // # how many times timer will dispatch 'tick' events 
     // # returns, integer 
     // .running() 
     // # 'is running' state 
     // # returns, boolean 
     // 
     return function (delay, fireCount) { 
     return (function (delay, fireCount) { 

      // preconfigured object that will handle 'tick' events 
      var host = this; 

      // timer object's internal state 
      // used/updated by timer 
      var timerState = 
      { 
       currentCount : 0, 
       delay  : Math.abs(parseFloat(delay)) || 1000, 
       repeatCount : Math.abs(parseInt(fireCount)) || Infinity, 
       running  : false, 
       interval  : undef 
      }; 

      // hack to reset .currentCount property asynchronously in .reset() method 
      // without using it this way, (by zeroing it directly, like: timerState.currentCount = 0) 
      // will make last 'tick' function call report: .currentCount() == 0, 
      // instead of whatever the currentCount was 
      // at the time the 'last tick' dispatch was performed 
      // 
      // because the handlers are runned asyncronously, and 
      // because setting currentCount to 0 manualy (synchronously) 
      // will reset it before last function gets to be runned 
      // reseting it asyncronously schedules a function to reset a property 
      // making 'last tick' function report correct currentCount (not 0). 
      var zer0CurrentCount = 
      _.async(
       function() { 
       timerState.currentCount = 0; 
       } 
      ); 

      // holds arguments passed to last .start() call 
      // uses these for further .start() calls if no new arguments are given 
      // passes them to triggered functions 
      var fireargs = []; 

      // attaches timer api 
      // (.start, .stop, .reset, .currentCount, .delay, .repeatCount, .running) 
      // to timer object 
      _.init(
       host, 
       { 

       // handles starting event dispatch 
       // if arguments are given, caches and 
       // uses them for further calls 
       // 'keeps an eye' on timer's configuration options 
       // updating/aborting dispatch when/if necessary 
       // triggering corresponding events and functions 
       // does nothing if timer is already in 'active' state 
       start: function() { 
        var startargs; 
        host.running() 
        || (
        timerState.running = true, 
        (startargs = _.slice(arguments)).length 
        && _.arrsub(fireargs, startargs), 
        host.fire.apply(
         host, 
         [timerEvent.start] 
         .concat(fireargs) 
        ), 
        timerState.currentCount += 1, 
        host.fire.apply(
         host, 
         [timerEvent.tick] 
         .concat(fireargs) 
        ), 
        (timerState.currentCount == timerState.repeatCount) 
        && host.reset() 
        || (
         timerState.interval = 
         setInterval(
         function() { 
          timerState.currentCount += 1; 
          host.fire.apply(
          host, 
          [timerEvent.tick] 
          .concat(fireargs) 
         ); 
          (timerState.currentCount >= timerState.repeatCount) 
          && host.reset(); 
         }, 
         timerState.delay 
        ) 
        ) 
       ); 
        return host; 
       }, 

       // pauses running functions (if timer{} is in 'running' state) 
       // fires 'tickStop' event 
       // passes arguments (given in .start call) to cached functions 
       // updates timer's internal state 
       stop: function() { 
        host.running() 
        && (
        (timerState.interval !== undef) 
        && (
         clearInterval(timerState.interval), 
         timerState.interval = undef 
        ), 
        timerState.running = false, 
        host.fire.apply(
         host, 
         [timerEvent.stop] 
         .concat(fireargs) 
        ) 
       ); 
        return host; 
       }, 

       // cancels event dispatch 
       // nulls internal state 
       // fires 'tickEnd' functions 
       reset: function() { 
        (timerState.interval !== undef) 
        && (
        clearInterval(timerState.interval), 
        timerState.interval = undef 
       ); 
        timerState.running = false; 
        host.fire.apply(
        host, 
        [timerEvent.end] 
        .concat(fireargs) 
       ); 
        zer0CurrentCount(); 
        return host; 
       }, 

       // query timer's current state: 

       currentCount: function() { 
        return timerState.currentCount; 
       }, 
       delay: function() { 
        return timerState.delay; 
       }, 
       repeatCount: function() { 
        return timerState.repeatCount; 
       }, 
       running: function() { 
        return timerState.running; 
       } 

       } 
      ); 
      return host; 
     }).call(listener({}), delay, fireCount); 
     } 
    })(

     // function to configure an object to handle custom events 
     // gives basic event handling functionality to provided object 
     // attaches .on/.off/.fire methods to it, 
     // used by main Timer function 
     // (to generate base objects for handling timer events) 
     // passed as single (private) argument to code above 
     function (obj) { 

      if (
      _.isobj(obj) 
     ) { 

      // evHandler parameter object is used to store provided handlers in 
      (function (evHandlers) { 

       // plain object to configure for custom event handling 
       var host = this; 

       // attaches api (.on, .off, .fire) to provided object 
       _.init(
        host, 
        { 

        // if function is provided cache it in 'evHandlers' object 
        // (to be called when needed) 
        // both, event type and function argument, are required 
        on: function (evtype, fn) { 
         if (
         _.isvalid(evtype) 
         && _.isfn(fn) 
        ) { 
         _.owns(evHandlers, evtype) 
         && evHandlers[evtype].push(fn) 
         || (evHandlers[evtype] = [fn]); 
         } 
         return host; 
        }, 

        // deletes a function (registered for evtype) from evHandlers{} 
        // both parameters are optional 
        off: function (evtype, fn) { 
         if (
         _.isvalid(evtype) 
        ) { 
         if (
          _.owns(evHandlers, evtype) 
         ) { 
          _.isfn(fn) 
          && (
          _.gc.call(evHandlers[evtype], fn), 
          evHandlers[evtype].length 
          || (delete evHandlers[evtype]), 1 
         ) 
          || (
          _.empty(evHandlers[evtype]), 
          delete evHandlers[evtype] 
         ); 
         } 
         } else { 
         _.owneach(
          evHandlers, 
          function (evtype, fns) { 
          _.empty(fns); 
          } 
         ); 
         _.vacate(evHandlers); 
         } 
         return host; 
        }, 

        // triggers functions registered for (string) evtype event 
        // passes 'event{}' to handlers 
        // it holds event type (.type), 
        // data[] (.data) provided through .fire call, 
        // object through which method is called (.target) 
        // and current execting function (.handler) 
        // runs handlers asynchronusly by passing them to 
        // _.async() method before execution 
        fire: function (evtype) { // (any)...args 
         if (
         _.isvalid(evtype) 
        ) { 
         if (
          _.owns(evHandlers, evtype) 
         ) { 
          var fireargs = _.slice(arguments, 1); 
          _.arreach(
           evHandlers[evtype], 
           function (evhandler) { 
           _.async(evhandler).call(
           host, 
           { 
            type : evtype, 
            data : fireargs, 
            target : host, 
            handler : evhandler 
           } 
          ); 
           } 
          ); 
         } 
         } 
         return host; 
        } 
        } 
      ); 
      }).call(
       obj, // passed object to apply event handling functionality to 
       {} // plain object to cache registered functions in 
      ); 
      } 

     // gives back passed/configued object 
     return obj; 

     } 
    ); 
} 
)); 
// 
// use: 
// 
// set event dispatch frequency 2x/sec 
// run it 5x (skip second argument to run functions indefinitely) 
// check out the console 
var timerObj = Timer(1000/2, 5); 

// shortcut function to start the timer 
function goTimer() { 
    // start 'ticking' functions, 
    // pass arbitrary arguments to handlers 
    timerObj.start(
    Math.random(), 
    (new Date).valueOf() 
); 
} 

// register functions for 'tick' cycle 
timerObj 
.on(
    "tickStart", 
    function (e) { 
    console.clear(); 
    console.log(
     e.type + ", \n", 
     (new Date).valueOf() 
    ); 
    } 
) 
.on(
    "tick", 
    function (e) { 
    // updateStuff(); 
    console.log(
     e.type + "#1, " 
     , "#", this.currentCount(),", " 
     , e.data 
    ); 
    } 
) 
.on(
    "tick", 
    function (e) { 
    // updateStuff(); 
    console.log(
     e.type + "#2, " 
     , "Math.random() < Math.random(): " 
     , Math.random() < Math.random() 
    ); 
    } 
) 
.on(
    "tickEnd", 
    function (e) { 
    console.log(
     e.type + ", \n" 
     , "e.target === this: " 
     , e.target === this 
    , ", e.target === timerObj: " 
     , e.target === timerObj 
     , "." 
    ); 
    setTimeout(goTimer, 10000 * Math.random()); 
    } 
); 
// 
setTimeout(goTimer, 2000); 
// 
// 
// 
// 
+0

이것은 굉장한 것처럼 보입니다. 그것이 정확히 무엇을하는지 이해할 수 있도록 문서화 되었으면 좋겠습니다. – Sunyatasattva

+0

아아, 만약 당신이 preffer, 나는 당신을 위해 특별한 관심을 끌기를 원한다면 몇 가지 코멘트를 달아 주겠습니까? –

1

나는 setIntervalclearInterval을 사용하십시오 및 mousedownmouseup 이벤트를 후크. 이 예제에서는 jQuery을 사용하고 있습니다. 귀하의 예제에 코드를 추가하지 않고 있습니다. 왜냐하면 당신이 이벤트 바인딩을 잘못하고 있기 때문입니다. one of my other answers에서 언급했듯이.

도 이벤트를 DOM에 바인딩하고 함수를 구조화하는 방법에 대한 예제를 제공합니다.

var mouseDown; 
jQuery(document).ready(function($){ 
    $('#number').on('mousedown',function(e){ 
    mouseDown = setInterval(add,150,this,1); // 150 is the number of ms you want 
              // to delay each number addition 
    }) 
    .on('mouseup',function(e){ 
    clearInterval(mouseDown); 
    }); 
}); 

function add(n,val){ 
    var currentValue = parseInt($(n).text()); 
    $(n).text(currentValue+val); 
} 

여기에 따라서 Working demo

+0

대상 요소에서 마우스를 떼었을 때 예약 된 간격을 취소하거나 요소가 활성화 될 때마다 여러 간격을 추가하는 것을 잊지 마십시오. 버튼을 누른 상태에서 마우스를 내려 놓고 다시 쥐어 짜내십시오. –