jQuery在拖动时使用右键单击旋转div

Posted

技术标签:

【中文标题】jQuery在拖动时使用右键单击旋转div【英文标题】:jQuery use right click to rotate div while dragging 【发布时间】:2018-06-03 08:31:45 【问题描述】:

我正在为我正在开发的游戏使用拖放界面。我目前正在使用 jQuery 可拖动和可放置来管理我的还原、限制、网格捕捉等,但我也想让它使得如果用户在拖动时右键单击,游戏块会旋转但不会停止拖动。但是,即使我在右键单击时放置了带有event.stopPropagation()event.preventDefault() 的事件侦听器,鼠标右键单击也会自动结束拖动事件。任何想法如何实现这一目标?

我在这里有一个半工作的 sn-p,右键单击确实会旋转游戏块,但会导致拖动停止。请注意,从我的源代码复制它会导致一些缩放和偏移,但用于此演示目的的功能仍然完好无损。

var board = function(parentDIV, size, options = ) 
    this.ship = this.ship.bind(this);
    this.flip = this.flip.bind(this);
    this.update = this.update.bind(this);
    this.ajaxExport = this.ajaxExport.bind(this);
    this.scale = this.scale.bind(this);
    
    this.size = size / 10;
    this.callback = 
        onvalid: options.onvalid,
        oninvalid: options.oninvalid,
        ondrag: options.ondrag,
        onstart: options.onstart,
        ondrop: options.ondrop
    ;
    
    this.containerDIV = $("<div>").css("position": "relative", "padding": "-1px").attr("id", "board-container");
    this.boardDIV = $("<div>").css("display": "table", "border-collapse": "collapse").on("contextmenu", function()  event.stopPropagation; event.preventDefault(); );
    var rowDIV = $("<div>").css("display": "table-row");
    var cellDIV = $("<div>").css("display": "table-cell", "border": "2px #000 solid", "padding": "-1px", "width": this.size.toString() + "px", "height": this.size.toString() + "px")
    for(var i = 0; i < 10; i++) 
        var cloneRow = rowDIV.clone();
        for(var ii = 0; ii < 10; ii++) cloneRow.append(cellDIV.clone());
        this.boardDIV.append(cloneRow);
    
    
    this.ships = [
        this.ship("carrier", 1, 5, 1, 1),
        this.ship("battleship", 4, 1, 4, 3),
        this.ship("cruiser", 1, 3, 8, 6),
        this.ship("submarine", 3, 1, 2, 8),
        this.ship("destroyer", 1, 2, 0, 8)
    ];
    

    this.containerDIV.append(this.boardDIV);
    $(parentDIV).append(this.containerDIV);
    

    this.update();
;
board.prototype.update = function() 
    this.layout = [
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0]
    ];
    
    for(var i = 0; i < this.ships.length; i++) 
        var width = depx(this.ships[i].css("width")) / this.size;
        var height = depx(this.ships[i].css("height")) / this.size;
        var left = depx(this.ships[i].css("left")) / this.size;
        var top = depx(this.ships[i].css("top")) / this.size;
        
        if(width == 1) for(var ii = top; ii < top + height; ii++) this.layout[ii][left] = i + 1;
        if(height == 1) for(var ii = left; ii < left + width; ii++) this.layout[top][ii] = i + 1;
    
    
    var pattern = new RegExp(/(?=^[^1]*(?:1,1,1,1,1|1\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+1\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+1\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+1\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+1)[^1]*$)(?=^[^2]*(?:2,2,2,2|2\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+2\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+2\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+2)[^2]*$)(?=^[^3]*(?:3,3,3|3\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+3\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+3)[^3]*$)(?=^[^4]*(?:4,4,4|4\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+4\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+4)[^4]*$)(?=^[^5]*(?:5,5|5\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+5)[^5]*$)^\[\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\]\]$/);
    
    if(pattern.test(JSON.stringify(this.layout))) if(this.callback.onvalid) this.callback.onvalid();
    else if(this.callback.oninvalid) this.callback.oninvalid();
    
    
    function depx(str) 
        return Number(str.substring(0, str.length - 2));
    
;
board.prototype.ajaxExport = function() 
    var inputs = 
        type: "uploadGameBoard",
        game: null,
        board: this.layout
    ;
    AJAXrequest("GET", inputs, function(response) 
        if(response == "success") 
            
        
    );
;
board.prototype.random = function() 
    
;
board.prototype.default = function() 
    
;
board.prototype.scale = function() 
    console.log(this.containerDIV.parent());
;
board.prototype.set = function() 
    
;
board.prototype.ship = function(name, width, height, left, top) 
    return $("<div>")
        .attr("id", name)
        .addClass("ship")
        .draggable(
            containment: "parent",
            preventCollision: true,
            grid: [this.size, this.size], 
            cursor: "none", 
            start: function()  ,
            stop: this.update,
            drag: this.validate )
        .css(
            "position": "absolute", 
            "width": (width * this.size).toString() + "px", 
            "height": (height * this.size).toString() + "px", 
            "background-color": "#000", 
            "top": (top * this.size).toString() + "px", 
            "left": (left * this.size).toString() + "px")
        .on("contextmenu", function()  event.stopPropagation(); event.preventDefault(); )
        .on("mousedown", this.flip)
        .appendTo(this.boardDIV);
;
board.prototype.validate = function() 

;
board.prototype.flip = function() 
    if(event.which == 3)  
        var ship = $(event.target); 
        var width = ship.css("height"); 
        var height = ship.css("width");
        var left = ship.css("left");
        var top = ship.css("top");
        
        ship.css("width": width, "height": height); 
        
        var offsetx = depx(width) + depx(left);
        var offsety = depx(height) + depx(top);
        var size = this.size * 10;
        
        if(offsetx > size) ship.css("left", String(size - depx(width)) + "px");
        else if(offsety > size) ship.css("top", String(size - depx(height)) + "px");
        
        this.update();
    
    
    function depx(str) 
        return Number(str.substring(0, str.length - 2));
    
;
board.prototype.disable = function() 
    for(var i = 0; i < this.ships.length; i++) this.ships[i].draggable( "option", "disabled", true );
;
board.prototype.enable = function() 
    for(var i = 0; i < this.ships.length; i++) this.ships[i].draggable( "option", "enable", true );
;

window.onload = function() new board(document.body, 500); ;
<!doctype html>
<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <style>
      body 
        margin 0;
       
    </style>
  </head>
  <body>
  </body>
</html>

【问题讨论】:

用户是否从左键开始,然后添加右键?对游戏中的动作有点困惑。 我知道这有点古怪,但是是的。如果你玩小提琴,你可以看到右击时碎片旋转 90 度,左击时拖动。 当我运行 sn-p 时,我得到控制台错误。将首先解决这些问题。 通过 jshint 运行它,我看到许多 event.stopPropagation; 被警告,应该是 event.stopPropagation(); 处理完所有其他警报后,我只剩下两个:第 1 行 'default parameters' is only available in ES6 (use 'esversion: 6'). 第 187 行 Do not use 'new' for side effects. 【参考方案1】:

我让它工作了......我不确定我到底做了什么改变,但是当我将 .on() 切换到这个时,它开始在大多数情况下按预期工作:

  .on(
    contextmenu: function(event) 
      console.log("EVENT: " + event.type, event.target.id);
      event.preventDefault();
      event.stopImmediatePropagation();
    ,
    mousedown: me.flip,
    mouseup: function(event) 
      console.log("EVENT: " + event.type, event.target.id);
      console.log(event);
      if (event.which === 3) 
        return false;
      
    
  )

基本上,我可以看到发生的事件是mousedowncontextmenumouseup 等事件会触发dragstopmouseup 是有意义的,因为 draggable 可能正在寻找该事件来触发 dragstop

工作测试:https://jsfiddle.net/Twisty/ue2qpp2z/6/

JavaScript

function Board(parentDIV, size, options) 
  if (options == "undefined") 
    options = ;
  

  var me = this;
  /**
  // Define Functions
  ***/
  this.ship = function(name, width, height, left, top) 
    console.log("Creating Ship: " + name, width, height, left, top);
    return $("<div>", 
        id: name,
        class: "ship"
      )
      .draggable(
        containment: "parent",
        preventCollision: true,
        grid: [me.size, me.size],
        cursor: "none",
        start: function(event, ui) 
          console.log("EVENT: " + event.type, event.target.id);
          console.log(event);
          me.dragging = true;
        ,
        stop: function(event, ui) 
          console.log("EVENT: " + event.type, event.target.id);
          me.dragging = false;
          me.update.apply(me);
        ,
        drag: function(event, ui) 
          console.log("EVENT: " + event.type, event.target.id);;
          //me.validate();
        
      )
      .css(
        position: "absolute",
        width: (width * me.size).toString() + "px",
        height: (height * me.size).toString() + "px",
        "background-color": "#000",
        top: (top * me.size).toString() + "px",
        left: (left * me.size).toString() + "px"
      )
      .on(
        contextmenu: function(event) 
          console.log("EVENT: " + event.type, event.target.id);
          event.preventDefault();
          event.stopImmediatePropagation();
        ,
        mousedown: me.flip,
        mouseup: function(event) 
          console.log("EVENT: " + event.type, event.target.id);
          console.log(event);
          if (event.which === 3) 
            return false;
          
        
      )
      .appendTo(me.boardDIV);
  ;

  this.flip = function(event) 
    if (event.which == 3) 
      console.log("EVENT: " + event.type, event.target.id);
      console.log("Performing Flip: ", event.target.id);
      var ship = $(event.target);
      var width = ship.css("height");
      var height = ship.css("width");
      var left = ship.css("left");
      var top = ship.css("top");

      ship.css(
        "width": width,
        "height": height
      );

      var offsetx = depx(width) + depx(left);
      var offsety = depx(height) + depx(top);
      var size = me.size * 10;

      if (offsetx > size) ship.css("left", String(size - depx(width)) + "px");
      else if (offsety > size) ship.css("top", String(size - depx(height)) + "px");
      if ($(event.target).hasClass("ui-draggable-dragging")) 
        // Restart Drag Event
        console.log("drag & mousedown, triggering `drag` again");
        $(event.target).trigger(jQuery.Event("drag"));
      
      me.update(event);
    

    function depx(str) 
      return Number(str.substring(0, str.length - 2));
    
  ;

  this.update = function(event) 
    console.log("Board Update");
    me.layout = [
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    ];

    for (var i = 0; i < me.ships.length; i++) 
      var width = depx(me.ships[i].css("width")) / me.size;
      var height = depx(me.ships[i].css("height")) / me.size;
      var left = depx(me.ships[i].css("left")) / me.size;
      var top = depx(me.ships[i].css("top")) / me.size;
      var ii;

      if (width == 1)
        for (ii = top; ii < top + height; ii++) me.layout[ii][left] = i + 1;
      if (height == 1)
        for (ii = left; ii < left + width; ii++) me.layout[top][ii] = i + 1;
    

    var pattern = new RegExp(/(?=^[^1]*(?:1,1,1,1,1|1\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+1\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+1\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+1\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+[^1]\D+1)[^1]*$)(?=^[^2]*(?:2,2,2,2|2\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+2\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+2\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+[^2]\D+2)[^2]*$)(?=^[^3]*(?:3,3,3|3\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+3\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+[^3]\D+3)[^3]*$)(?=^[^4]*(?:4,4,4|4\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+4\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+[^4]\D+4)[^4]*$)(?=^[^5]*(?:5,5|5\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+[^5]\D+5)[^5]*$)^\[\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\],\[[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5],[0-5]\]\]$/);

    if (pattern.test(JSON.stringify(me.layout)))
      console.log("Update: Calling Callbacks");
    if (me.callback.onvalid) 
      console.log("Uopdate: Calling 'onvalid'");
      me.callback.onvalid.apply(me);
     else if (me.callback.oninvalid) 
      console.log("Update: Calling 'oninvalid'");
      me.callback.oninvalid.apply(me);
    

    function depx(str) 
      return Number(str.substring(0, str.length - 2));
    

    if (event) 
      console.log("Update: Event found: " + event.type);
      if (event.type == "mousedown" && me.dragging) 
        $(event.target).trigger(jQuery.Event("dragstart"));
        event.stopImmediatePropagation();
      
    
  ;

  this.scale = function() 
    console.log(me.containerDIV.parent());
  ;

  this.disable = function() 
    console.log("Disable");
    for (var i = 0; i < me.ships.length; i++) me.ships[i].draggable("option", "disabled", true);
  ;

  this.enable = function() 
    console.log("Enable");
    for (var i = 0; i < me.ships.length; i++) me.ships[i].draggable("option", "enable", true);
  ;

  /***
  // Define Variables
  ***/

  this.size = size / 10;
  this.callback = 
    onvalid: options.onvalid,
    oninvalid: options.oninvalid,
    ondrag: options.ondrag,
    onstart: options.onstart,
    ondrop: options.ondrop
  ;
  this.dragging = false;

  this.containerDIV = $("<div>").css(
    "position": "relative",
    "padding": "-1px"
  ).attr("id", "board-container");

  this.boardDIV = $("<div>").css(
    "display": "table",
    "border-collapse": "collapse"
  ).on("contextmenu", function(event) 
    console.log("EVENT: " + event.type, event.target.id);
    if ($(event.target).not(".ui-draggable-dragging")) 
      event.stopPropagation();
      event.preventDefault();
    
  );

  var rowDIV = $("<div>").css(
    "display": "table-row"
  );

  var cellDIV = $("<div>").css(
    "display": "table-cell",
    "border": "2px #000 solid",
    "padding": "-1px",
    "width": this.size.toString() + "px",
    "height": this.size.toString() + "px"
  );

  for (var i = 0; i < 10; i++) 
    var cloneRow = rowDIV.clone();
    for (var ii = 0; ii < 10; ii++) cloneRow.append(cellDIV.clone());
    this.boardDIV.append(cloneRow);
  

  this.ships = [
    this.ship("carrier", 1, 5, 1, 1),
    this.ship("battleship", 4, 1, 4, 3),
    this.ship("cruiser", 1, 3, 8, 6),
    this.ship("submarine", 3, 1, 2, 8),
    this.ship("destroyer", 1, 2, 0, 8)
  ];

  this.containerDIV.append(this.boardDIV);
  $(parentDIV).append(this.containerDIV);

  this.update();


$(function() 
  Board(document.body, 500, );
);

希望对您有所帮助。

更新

我想我知道问题出在哪里,与事件 xy 有关。当元素被翻转时,在某些情况下,鼠标不再元素上,我认为这会导致dragstop 触发。我会看看我是否可以深入研究 jQuery UI,看看我是否可以找到 draggable 是如何处理这种情况的。

【讨论】:

这很好用,谢谢。我想我可以修改代码,让飞船围绕被点击的单元格旋转,从而使界面更加流畅,同时消除拖动错误。 另一种选择是将光标捕捉到任何被拖动的船的右上角,这只是定义可拖动对象时的一个参数:.draggable(cursorAt: top: y, left: x)

以上是关于jQuery在拖动时使用右键单击旋转div的主要内容,如果未能解决你的问题,请参考以下文章

单击时将图像添加到屏幕并允许其可拖动/可旋转

jquery拖动并旋转到角度

用右键单击或滚轮单击窗口在 Python Kivy 中添加红色可拖动圆圈

div旋转时jQuery可拖动跳跃

VB.Net 如何通过鼠标单击和拖动来旋转矩形

jQuery可拖拽3D万花筒旋转特效