如何使用箭头键移动选定的元素

How to move selected elements using arrow keys

jquery ui draggable 不允许使用键盘上的箭头键移动元素。 只能用鼠标

为此键盘事件处理程序是使用

创建的
$(".designer-panel-body").keydown(function(e) {
    switch(e.which) {
        case 37: // left
           $(".ui-selected").each(function() {
             var $this = $(this);
                $this.css({
                  left: $this.left -2
                });
              });
            break;

        case 38: // up
           $(".ui-selected").each(function() {
             var $this = $(this);
                $this.css({
                  top: $this.top -2
                });
              });
        break;

        case 39: // right
           $(".ui-selected").each(function() {
             var $this = $(this);
                $this.css({
                  left: $this.left +2
                });
              });
        break;

        case 40: // down
            $(".ui-selected").each(function() {
             var $this = $(this);
                $this.css({
                  top: $this.top +2
                });
              });
        break;

        default: return; // exit this handler for other keys
    }
    e.preventDefault(); // prevent the default action (scroll / move caret)
});

但是按键事件没有发生。要重现,运行 下面的代码,select 元素并尝试使用箭头拖动。 箭头键被忽略。如何解决此问题,以便可以使用数组键逐像素拖动?

Fiddle: https://jsfiddle.net/bgx8gpwc/2/

<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
  <link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
  <style>
    .designer-panel-body {
      min-height: 1px;
      overflow: hidden;
      margin: 0;
      padding: 0;
    }
    .panel-footer {
      background-color: inherit;
    }
    .designer-panel,
    .designer-resetmargins {
      margin: 0;
      padding: 0;
    }
    .designer-verticalline,
    .designer-horizontalline,
    .designer-rectangle {
      font-size: 1pt;
      border: 1px solid #000000;
    }
    .designer-field {
      border: 1px solid lightgray;
      white-space: pre;
      overflow: hidden;
    }
    .ui-selecting {
      background-color: lightskyblue;
      color: white;
    }
    .ui-selected {
      background-color: lightskyblue;
      border-color: darkblue;
      color: white;
    }
    .designer-label {
      white-space: pre;
      /*overflow: hidden;*/
    }
    .designer-field,
    .designer-label {
      font-family: "Times New Roman";
      font-size: 10pt;
      z-index: 2;
    }
    .designer-verticalline,
    .designer-horizontalline,
    .designer-rectangle,
    .designer-field,
    .designer-image,
    .designer-label {
      position: absolute;
    }
  </style>
  <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
  <script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>

  <script>
    function getpos(e) {
      return {
        X: e.pageX,
        Y: e.pageY
      };
    }

    function Rect(start, stop) {
      this.left = Math.min(start.X, stop.X);
      this.top = Math.min(start.Y, stop.Y);
      this.width = Math.abs(stop.X - start.X);
      this.height = Math.abs(stop.Y - start.Y);
    }

    $(function() {
      var startpos;
      var selected = $([]),
        offset = {
          top: 0,
          left: 0
        };
      $(".designer-verticalline, .designer-rectangle, .designer-field, .designer-image").resizable();

      // 
      // teha: seal on ka mousedown mis andis viga, kaseda kasutada
      var $liigutatavad = $(".designer-verticalline, .designer-horizontalline, .designer-rectangle, .designer-field, .designer-image, .designer-label");
      $liigutatavad.draggable({
        start: function(event, ui) {
          var $this = $(this);

          if ($this.hasClass("ui-selected")) {
            // if this is selected, attach current offset
            // of each selected element to that element
            selected = $(".ui-selected").each(function() {
              var el = $(this);
              el.data("offset", el.offset());
            });
          } else {
            // if this is not selected, clear current selection
            selected = $([]);
            $liigutatavad.removeClass("ui-selected");
          }
          offset = $this.offset();
        },

        drag: function(event, ui) {
          // drag all selected elements simultaneously
          var dt = ui.position.top - offset.top,
            dl = ui.position.left - offset.left;
          selected.not(this).each(function() {
            var $this = $(this);
            var elOffset = $this.data("offset");
            $this.css({
              top: elOffset.top + dt,
              left: elOffset.left + dl
            });
          });

          // this does not fix the issue:
          //$(".designer-verticalline, .designer-rectangle, .designer-field, .designer-image").resizable();
        }
      });

      // ...but manually implement selection to prevent interference from draggable()
      $(".designer-panel-body").on("click", "div", function(e) {
        if ( /*!e.metaKey &&*/ !e.shiftKey && !e.ctrlKey) {
          // deselect other elements if meta/shift not held down
          $(".designer-panel-body").removeClass("ui-selected");
          $(this).addClass("ui-selected");
        } else {
          if ($(this).hasClass("ui-selected")) {
            $(this).removeClass("ui-selected");
          } else {
            $(this).addClass("ui-selected");
          }
        }

        //var selectable = $("#container").data("selectable");
        //selectable.refresh();
        //$( ".designer-panel-body" ).data("selectable")._mouseStop(null);
      });

      $(".designer-panel-body").selectable({});


$(".designer-panel-body").keydown(function(e) {
switch(e.which) {
    case 37: // left
       $(".ui-selected").each(function() {
         var $this = $(this);
            $this.css({
              left: $this.left -2
            });
          });
        break;

    case 38: // up
       $(".ui-selected").each(function() {
         var $this = $(this);
            $this.css({
              top: $this.top -2
            });
          });
    break;

    case 39: // right
       $(".ui-selected").each(function() {
         var $this = $(this);
            $this.css({
              left: $this.left +2
            });
          });
    break;

    case 40: // down
        $(".ui-selected").each(function() {
         var $this = $(this);
            $this.css({
              top: $this.top +2
            });
          });
    break;

    default: return; // exit this handler for other keys
}
e.preventDefault(); // prevent the default action (scroll / move caret)
});


    });
  </script>

</head>

<body>
  <div class='panel designer-panel'>
    <div class='panel-body designer-panel-body panel-warning' style='height:9.37cm'>

      <div class='designer-field' contenteditable='true' style='top:2.30cm;left:5.84cm;width:10.24cm;height:0.63cm;font-family:Arial;font-size:14pt;font-weight:bold;'>vnimi+&#39; &#39;+dok.tasudok</div>
      <div class='designer-field' contenteditable='true' style='top:2.30cm;left:16.37cm;width:2.68cm;height:0.61cm;font-size:14pt;'>DOK.kuupaev</div>
      <div class='rectangle' style='border-width: 1px;background-color:#FFFFFF;top:2.99cm;left:1.34cm;width:18.05cm;height:5.29cm'></div>
      <div class='designer-field' contenteditable='true' style='top:3.01cm;left:1.53cm;width:9.71cm;height:0.55cm;font-size:12pt;'>m.FIRMA</div>
      <div class='designer-field' contenteditable='true' style='top:3.01cm;left:12.13cm;width:3.13cm;height:0.53cm;font-size:12pt;'>ise.telefon</div>
      <div class='designer-field' contenteditable='true' style='top:3.01cm;left:17.11cm;width:1.89cm;height:0.55cm;font-size:12pt;text-align:right;'>ise.regnr</div>
      <div class='designer-label' contenteditable='true' style='top:3.04cm;left:11.39cm;text-align:right;font-size:12pt;'>Tel.</div>
      <div class='designer-label' contenteditable='true' style='top:3.04cm;left:15.71cm;font-size:12pt;'>Reg.Nr</div>
      <div class='designer-field' contenteditable='true' style='top:3.62cm;left:1.55cm;width:9.45cm;height:0.55cm;font-size:12pt;'>ise.tanav</div>
      <div class='designer-field' contenteditable='true' style='top:3.70cm;left:15.16cm;width:3.37cm;height:0.55cm;font-size:12pt;'>ise.vatpayno</div>
      <div class='designer-label' contenteditable='true' style='top:3.72cm;left:12.89cm;text-align:right;font-size:12pt;'>KMKR nr</div>
      <div class='designer-field' contenteditable='true' style='top:4.30cm;left:1.58cm;width:9.08cm;height:0.55cm;font-size:12pt;'>rtri(ise.postiindek)+&#39; &#39;+rtri(ise.piirkond)</div>
      <div class='designer-field' contenteditable='true' style='top:4.30cm;left:14.66cm;width:4.34cm;height:0.55cm;font-size:12pt;text-align:right;'>aarve(dok.arvekonto, &#39;konto.arveldusar&#39;)</div>
      <div class='designer-label' contenteditable='true' style='top:4.33cm;left:13.89cm;font-size:12pt;'>A/A</div>
      <div class='designer-horizontalline' style='border-width: 1px;top:4.96cm;left:1.34cm;width:18.03cm;height:0.00cm'></div>
      <div class='designer-field' contenteditable='true' style='top:5.04cm;left:17.13cm;width:1.89cm;height:0.55cm;font-size:12pt;text-align:right;'>klient.regnr</div>
      <div class='designer-field' contenteditable='true' style='top:5.06cm;left:4.18cm;width:12.71cm;height:0.55cm;font-size:12pt;'>klient.nimi</div>
      <div class='designer-label' contenteditable='true' style='top:5.06cm;left:15.74cm;font-size:12pt;'>Reg.Nr</div>
      <div class='designer-label' contenteditable='true' style='top:5.09cm;left:1.63cm;font-size:12pt;'>Maksja</div>
      <div class='designer-field' contenteditable='true' style='top:5.72cm;left:1.53cm;width:11.68cm;height:0.55cm;font-size:12pt;'>klient.tanav</div>
      <div class='designer-field' contenteditable='true' style='top:5.72cm;left:15.18cm;width:3.37cm;height:0.55cm;font-size:12pt;'>klient.vatpayno</div>
      <div class='designer-label' contenteditable='true' style='top:5.75cm;left:12.92cm;text-align:right;font-size:12pt;'>KMKR nr</div>
      <div class='designer-field' contenteditable='true' style='top:6.38cm;left:1.53cm;width:11.84cm;height:0.55cm;font-size:12pt;'>rtri(klient.postiindek)+&#39; &#39; +rtri(klient.piirkond)</div>
      <div class='designer-field' contenteditable='true' style='top:6.38cm;left:13.47cm;width:3.37cm;height:0.55cm;font-size:12pt;'>sql(&quot;sele transfld(&#39;nimetus&#39;, &#39;riik&#39;, rapopref()) from riik where kood=klient.riik2&quot;, &#39;&#39; )</div>
      <div class='designer-field' contenteditable='true' style='top:6.99cm;left:3.71cm;width:12.16cm;height:1.16cm;font-size:12pt;'>klient.aadress</div>
      <div class='designer-label' contenteditable='true' style='top:7.01cm;left:1.45cm;text-align:right;font-size:12pt;'>Postiaadress</div>
      <div class='designer-field' contenteditable='true' style='top:8.33cm;left:3.95cm;width:2.11cm;height:0.55cm;font-size:12pt;'>dok.tasukuup</div>
      <div class='designer-field' contenteditable='true' style='top:8.33cm;left:6.08cm;width:8.05cm;height:0.55cm;font-size:12pt;'>eval( &#39;maksetin.&#39; +left(rapopref()+&#39;tingimus&#39;,10))</div>
      <div class='designer-label' contenteditable='true' style='top:8.35cm;left:1.45cm;font-size:12pt;'>Makset&#228;htaeg</div>
      <div class='designer-field' contenteditable='true' style='top:8.91cm;left:1.45cm;width:13.66cm;height:0.45cm;'>iif(!empty(dok.saaja), IR(&quot;Saaja: &quot;)+sql(&#39;sele rtri(nimi)+&quot; &quot;+rtri(tanav)+&quot; &quot;+rtri(piirkond)+&quot; &quot;+rtri(postiindek) from klient where kood=dok.saaja&#39;,&#39;&#39;),&#39;&#39;)</div>
    </div>
    <div class='bg-warning'>
      <div class='panel-footer'><i class='glyphicon glyphicon-chevron-up'></i> GroupHeader 1: str(dokumnr)+str(koopia,2)</div>
    </div>
  </div>
</body>

</html>

这是一个示例,说明如何在不使用 jQuery UI draggable.

的情况下使用箭头键 "drag" DOM 元素

在此示例中 jQuery .before().after() 函数用于将元素放置到新位置。

$('.el').click(function(){     
   $('.el').removeClass('active'); 
      $(this).addClass('active');  
});

$('body').on('keyup',function(e){

switch(e.which) {
        case 37: // left
          var tmp_id = $('.el.active').prev().attr('id'); 
          $('#' + tmp_id).animate({ opacity: 0 }, 100, function(){
            $('.el.active').after($('.el.active').prev());  
          });         
          $('#' + tmp_id).animate({ opacity: 1 }, 300);
        break;

        case 38: // up
          var active_index = $('.el.active').index();
          var index_min = $('.el.active').parent().children().first().index();          
          var index_max = $('.el.active').parent().children().last().index();   
          var next_element = $('.el.active').parent().prev().children(':eq('+active_index+')');
          
          if(index_min === active_index){
           var prev_el = next_element.next();
            $('.el.active').before(next_element);
           $(prev_el).before($('.el.active'));
          }
          
          if(index_max === active_index || (active_index > index_min && active_index < index_max )){
           var prev_el = next_element.prev(); 
            $('.el.active').before(next_element);
            $(prev_el).after($('.el.active'));
          }
                              
        break;

        case 39: // right
          var tmp_id = $('.el.active').next().attr('id');
          $('#' + tmp_id).animate({ opacity: 0 }, 100, function(){
            $('.el.active').before($('.el.active').next());
          });                   
          $('#' + tmp_id).animate({ opacity: 1 }, 300);                   
        break;

        case 40: // down
          var active_index = $('.el.active').index();
          var index_min = $('.el.active').parent().children().first().index();          
          var index_max = $('.el.active').parent().children().last().index();          
       var next_element = $('.el.active').parent().next().children(':eq('+active_index+')');
          var prev_el = next_element.prev(); 
          
          if(index_min === active_index){
           var prev_el = next_element.next();
            $('.el.active').before(next_element);
           $(prev_el).before($('.el.active'));
          }
          
          if(index_max === active_index || (active_index > index_min && active_index < index_max )){
           var prev_el = next_element.prev(); 
            $('.el.active').before(next_element);
           $(prev_el).after($('.el.active'));
          }
                                   
        break;

        default: return; // exit this handler for other keys
    }
    e.preventDefault();

});
.container{
  width: 100%;    
}

div[id^="el-wr"]{  
  width: 280px;  
  margin: 0 auto;  
}

.el{
  width: 60px;
  height: 60px;
  background-color: #aaa; 
  margin: 5px;
  float: left; 
  cursor: pointer;   
  text-align: center;
  line-height: 60px;
  font-size: 28px;
  color: white;
}

.active{
  background-color: #525252;   
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div class="container">

  <div id="el-wr0">

          <div class="el" id="index1">1</div>

          <div class="el" id="index2">2</div>

          <div class="el" id="index3">3</div>
          
          <div class="el" id="index4">4</div>

  </div>
  
  <div id="el-wr1">

          <div class="el" id="index5">5</div>

          <div class="el" id="index6">6</div>

          <div class="el" id="index7">7</div>
          
          <div class="el" id="index8">8</div>

  </div>
  
  <div id="el-wr2">

          <div class="el" id="index9">9</div>

          <div class="el" id="index10">10</div>

          <div class="el" id="index11">11</div>
          
          <div class="el" id="index12">12</div>

  </div>

  


</div>