jQuery click / toggle between two functions

前端 未结 10 1539
野的像风
野的像风 2020-11-22 07:58

I am looking for a way to have two separate operations / functions / \"blocks of code\" run when something is clicked and then a totally different block when the same thing

相关标签:
10条回答
  • 2020-11-22 08:26

    Micro jQuery Plugin

    If you want your own chainable clickToggle jQuery Method you can do it like:

    jQuery.fn.clickToggle = function(a, b) {
      return this.on("click", function(ev) { [b, a][this.$_io ^= 1].call(this, ev) })
    };
    
    // TEST:
    $('button').clickToggle(function(ev) {
      $(this).text("B"); 
    }, function(ev) {
      $(this).text("A");
    });
    <button>A</button>
    <button>A</button>
    <button>A</button>
    
    <script src="//code.jquery.com/jquery-3.3.1.min.js"></script>


    Simple Functions Toggler

    LIVE DEMO

    function a(){ console.log('a'); }
    function b(){ console.log('b'); }
    
    $("selector").click(function() { 
      return (this.tog = !this.tog) ? a() : b();
    });
    

    If you want it even shorter (why would one, right?!) you can use the Bitwise XOR *Docs operator like:
    DEMO

      return (this.tog^=1) ? a() : b();
    

    That's all.
    The trick is to set to the this Object a boolean property tog, and toggle it using negation (tog = !tog)
    and put the needed function calls in a Conditional Operator ?:




    In OP's example (even with multiple elements) could look like:

    function a(el){ $(el).animate({width: 260}, 1500); }
    function b(el){ $(el).animate({width: 30}, 1500);  }
    
    $("selector").click(function() {
      var el = this;
      return (el.t = !el.t) ? a(el) : b(el);
    }); 
    

    ALSO: You can also store-toggle like:
    DEMO:

    $("selector").click(function() {
      $(this).animate({width: (this.tog ^= 1) ? 260 : 30 });
    }); 
    

    but it was not the OP's exact request for he's looking for a way to have two separate operations / functions


    Using Array.prototype.reverse:

    Note: this will not store the current Toggle state but just inverse our functions positions in Array (It has it's uses...)

    You simply store your a,b functions inside an array, onclick you simply reverse the array order and execute the array[1] function:

    LIVE DEMO

    function a(){ console.log("a"); }
    function b(){ console.log("b"); }
    var ab = [a,b];
    
    $("selector").click(function(){
      ab.reverse()[1](); // Reverse and Execute! // >> "a","b","a","b"...
    });
    

    SOME MASHUP!

    jQuery DEMO
    JavaScript DEMO

    Create a nice function toggleAB() that will contain your two functions, put them in Array, and at the end of the array you simply execute the function [0 // 1] respectively depending on the tog property that's passed to the function from the this reference:

    function toggleAB(){
      var el = this; // `this` is the "button" Element Obj reference`
      return [
        function() { console.log("b"); },
        function() { console.log("a"); }
      ][el.tog^=1]();
    }
    
    $("selector").click( toggleAB );
    
    0 讨论(0)
  • 2020-11-22 08:29

    I don't think you should implement the toggle method since there is a reason why it was removed from jQuery 1.9.

    Consider using toggleClass instead that is fully supported by jQuery:

    function a(){...}
    function b(){...}   
    

    Let's say for example that your event trigger is onclick, so:

    First option:

    $('#test').on('click', function (event) {
    
        $(this).toggleClass('toggled');
    
        if ($(this).hasClass('toggled')) {
            a();
        } else{
            b();
        }
    }
    

    You can also send the handler functions as parameters:

    Second option:

    $('#test').on('click',{handler1: a, handler2: b}, function (event) {
    
        $(this).toggleClass('toggled');
    
        if ($(this).hasClass('toggled')) {
            event.data.handler1();
        } else{
            event.data.handler2();
        }
    }
    
    0 讨论(0)
  • 2020-11-22 08:30

    If all you're doing is keeping a boolean isEven then you can consider checking if a class isEven is on the element then toggling that class.

    Using a shared variable like count is kind of bad practice. Ask yourself what is the scope of that variable, think of if you had 10 items that you'd want to toggle on your page, would you create 10 variables, or an array or variables to store their state? Probably not.

    Edit:
    jQuery has a switchClass method that, when combined with hasClass can be used to animate between the two width you have defined. This is favourable because you can change these sizes later in your stylesheet or add other parameters, like background-color or margin, to transition.

    0 讨论(0)
  • 2020-11-22 08:32

    one line solution: basic idea:

    $('sth').click(function () {
        let COND = $(this).propery == 'cond1' ? 'cond2' : 'cond1';
        doSomeThing(COND);
    })
    

    examples on jsfiddle

    example 1, changing innerHTML of an element in a toggle-mode:

    $('#clickTest1').click(function () {
        $(this).html($(this).html() == 'click Me' ? 'clicked' : 'click Me');
    });
    

    example 2, toggling displays between "none" and "inline-block":

    $('#clickTest2, #clickTest2 > span').click(function () {
        $(this).children().css('display', $(this).children().css('display') == 'inline-block' ? 'none' : 'inline-block');
    });
    
    0 讨论(0)
  • 2020-11-22 08:37

    jQuery has two methods called .toggle(). The other one [docs] does exactly what you want for click events.

    Note: It seems that at least since jQuery 1.7, this version of .toggle is deprecated, probably for exactly that reason, namely that two versions exist. Using .toggle to change the visibility of elements is just a more common usage. The method was removed in jQuery 1.9.

    Below is an example of how one could implement the same functionality as a plugin (but probably exposes the same problems as the built-in version (see the last paragraph in the documentation)).


    (function($) {
        $.fn.clickToggle = function(func1, func2) {
            var funcs = [func1, func2];
            this.data('toggleclicked', 0);
            this.click(function() {
                var data = $(this).data();
                var tc = data.toggleclicked;
                $.proxy(funcs[tc], this)();
                data.toggleclicked = (tc + 1) % 2;
            });
            return this;
        };
    }(jQuery));
    

    DEMO

    (Disclaimer: I don't say this is the best implementation! I bet it can be improved in terms of performance)

    And then call it with:

    $('#test').clickToggle(function() {   
        $(this).animate({
            width: "260px"
        }, 1500);
    },
    function() {
        $(this).animate({
            width: "30px"
        }, 1500);
    });
    

    Update 2:

    In the meantime, I created a proper plugin for this. It accepts an arbitrary number of functions and can be used for any event. It can be found on GitHub.

    0 讨论(0)
  • 2020-11-22 08:39

    Use a couple of functions and a boolean. Here's a pattern, not full code:

     var state = false,
         oddONes = function () {...},
         evenOnes = function() {...};
    
     $("#time").click(function(){
         if(!state){
            evenOnes();
         } else {
            oddOnes();
         }
         state = !state;
      });
    

    Or

      var cases[] = {
          function evenOnes(){...},  // these could even be anonymous functions
          function oddOnes(){...}    // function(){...}
      };
    
      var idx = 0; // should always be 0 or 1
    
      $("#time").click(function(idx){cases[idx = ((idx+1)%2)]()}); // corrected
    

    (Note the second is off the top of my head and I mix languages a lot, so the exact syntax isn't guaranteed. Should be close to real Javascript through.)

    0 讨论(0)
提交回复
热议问题