【问题标题】:how to move a div with arrow keys如何使用箭头键移动 div
【发布时间】:2011-02-09 21:20:21
【问题描述】:

我想使用 jQuery 用我的箭头键移动一个 div。 所以右、左、下和上。

找到了我想要完成的演示here

我希望能够在另一个 div 中移动一个 div。

如何做到这一点?

【问题讨论】:

  • 1) 使用绝对定位的div 创建 HTML 和 CSS。 2) 跟踪箭头键被按下。 3) 适当更改 div 的 CSS topleft 属性。您遇到了以下哪一个问题?
  • 2 号因为我不知道如何将箭头键链接到 div
  • 您在问题中发布了一个示例.. 带有代码.. 您需要我们提供什么?
  • 对不起,没有更短的版本吗?
  • 这个例子展示了如何在 HTML5 Canvas 中重新绘制一个正方形。与移动 div 不同。

标签: javascript jquery events html


【解决方案1】:

var pane = $('#pane'),
    box = $('#box'),
    w = pane.width() - box.width(),
    d = {},
    x = 3;

function newv(v,a,b) {
    var n = parseInt(v, 10) - (d[a] ? x : 0) + (d[b] ? x : 0);
    return n < 0 ? 0 : n > w ? w : n;
}

$(window).keydown(function(e) { d[e.which] = true; });
$(window).keyup(function(e) { d[e.which] = false; });

setInterval(function() {
    box.css({
        left: function(i,v) { return newv(v, 37, 39); },
        top: function(i,v) { return newv(v, 38, 40); }
    });
}, 20);
#pane {
  position: relative;
  width: 300px;
  height: 300px;
  border: 2px solid red;
}

#box {
  position: absolute;
  top: 140px;
  left: 140px;
  width: 20px;
  height: 20px;
  background-color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="pane">
  <div id="box"></div>
</div>

变量说明:
w - 框可以具有的最大左/顶值(保持在边界内)
x - 框在每个间隔中移动的距离(以 px 为单位)
d - 此对象存储有关正在按下的键的信息。例如,当用户按住左箭头键时,d['37']true。否则为false。顺便说一句,37 是左箭头键的键码,该值存储在事件对象的e.which 属性中。 d 对象会在每个 keydownkeyup 事件上更新。

每 20 毫秒执行一次的 setInterval,更新 box 元素的左侧和顶部 CSS 属性。新值通过newv 函数计算。

newv 函数将根据 a) 旧值 v 和 b) d 对象计算新的左/上值。

表达式n &lt; 0 ? 0 : n &gt; w ? w : n 确保新值在允许的范围内(即0 to w)。如果 n w,则返回 w。


现场演示:http://jsfiddle.net/simevidas/bDMnX/1299/


更新:此代码与上面的原始代码具有相同的功能。唯一的区别是我为变量和参数使用了更有意义的名称。如您所见,它看起来很糟糕 - 原始版本显然更好。 :P

var pane = $('#pane'),
    box = $('#box'),
    maxValue = pane.width() - box.width(),
    keysPressed = {},
    distancePerIteration = 3;

function calculateNewValue(oldValue, keyCode1, keyCode2) {
    var newValue = parseInt(oldValue, 10)
                   - (keysPressed[keyCode1] ? distancePerIteration : 0)
                   + (keysPressed[keyCode2] ? distancePerIteration : 0);
    return newValue < 0 ? 0 : newValue > maxValue ? maxValue : newValue;
}

$(window).keydown(function(event) { keysPressed[event.which] = true; });
$(window).keyup(function(event) { keysPressed[event.which] = false; });

setInterval(function() {
    box.css({
        left: function(index ,oldValue) {
            return calculateNewValue(oldValue, 37, 39);
        },
        top: function(index, oldValue) {
            return calculateNewValue(oldValue, 38, 40);
        }
    });
}, 20);

【讨论】:

  • 无意冒犯,但尽管这段代码运行得非常好(非常好),但变量名让我觉得我是一个混淆代码的竞争者。阅读代码很困难,因为除了panebox 之外没有任何有意义的名称(并且堆叠的三元运算符无济于事)。但就像我说的,它的功能确实很好。
  • @Reid 堆叠的三元运算符不整齐吗? :)一旦你弄清楚他们在做什么,它会让你大吃一惊,呵呵。但是,是的,我可能应该解释一下我的代码。给我一秒钟...
  • @ime Vidas 我还是赞成你,但我认为使用更清晰的变量名比解释你的一个字符更好:)
  • @alex 我不同意。在现实世界的场景中,代码将被记录在案。我不知道我的大脑:) 是否有问题,但我发现与使用更长、更有意义的变量名的代码相比,使用单字母变量名的代码更容易阅读。但是,我已经使用您的建议重写了我的代码,并将结果发布在我的答案中。你觉得哪个版本更好?
  • @ime Vidas 我更喜欢第二个例子。 :)
【解决方案2】:

@Šime Vidas:您的第一个解决方案简直太棒了。 (我认为第二个是多余的=)

我可以建议为垂直和水平宽度制作两个不同的功能吗?因为你几乎不可能在一个完美的正方形内移动一个 div,我相信有这样的东西会更好:

$(function () {
var pane = $('#pane'),
box = $('#box'),
wh = pane.width() - box.width(),
wv = pane.height() - box.height(),
d = {},
x = 5;

function newh(v,a,b) {
    var n = parseInt(v, 10) - (d[a] ? x : 0) + (d[b] ? x : 0);
    return n < 0 ? 0 : n > wh ? wh : n;
}

function newv(v,a,b) {
    var n = parseInt(v, 10) - (d[a] ? x : 0) + (d[b] ? x : 0);
    return n < 0 ? 0 : n > wv ? wv : n;
}

$(window).keydown(function(e) { d[e.which] = true; });
$(window).keyup(function(e) { d[e.which] = false; });

setInterval(function() {
    box.css({
        left: function(i,v) { return newh(v, 37, 39); },
        top: function(i,v) { return newv(v, 38, 40); }
    });
}, 20);
});

这正是我想要的。

如果您有基于 % 值的响应式设计,建议您像这样调整 setInterval:

setInterval(function() {
    box.css({
        left: function(i,v) { return newh(v, 37, 39); },
        top: function(i,v) { return newv(v, 38, 40); }
    });
    wh = pane.width() - box.width();
    wv = pane.height() - box.height();
}, 20);

如果您这样做,它会调整窗格的高度和宽度,并且框仍会停在其边框处。

我在这里做了一个小提琴http://jsfiddle.net/infidel/JkQrR/1/

非常感谢。

【讨论】:

    【解决方案3】:

    我看不到您的演示,但这里有一个简单的“将框沿箭头键方向移动 1px”示例:

    CSS:

    #wrapper { 
        background-color: gray; 
        height:200px; 
        width: 200px; 
        position:absolute;
    }
    #mover { 
        background-color: white; 
        border: 1px solid red;  
        height:20px; 
        width: 20px;
        position:relative;
    }
    

    标记:

    <div id="wrapper">
        <div id="mover"></div>
    </div>
    

    JS(使用 jQuery):

    $("#wrapper").keydown(function(event) { 
        var $mover = $("#mover");
        //if nothing else will move "mover", then track the 
        //position instead of recalculating it every time:
        //   var moverPos = $mover.position();
        //   var left = moverPos.left;
        //   var top = moverPos.top;
        var addTop = function(diff) {
            $mover.css("top", ($mover.position().top + diff) + "px"); 
            //if using tracked position:
            //   top += diff;
            //   $mover.css("top", top) + "px");
        };
    
        var addLeft = function(diff) {
            $mover.css("left", ($mover.position().left + diff) + "px");
            //if using tracked position:
            //   left += diff;
            //   $mover.css("left", left) + "px");
        };
    
        switch(event.keyCode) {
            case 37: //left
                addLeft(-1); break; 
            case 38: //up
                addTop(-1); break;
            case 39: //right
                addLeft(1); break;
            case 40: //down
                addTop(1); break;
        }
    });
    

    这只是一个示例,您可能想要添加边界检查、更大的移动、更流畅的动画、数字键盘支持或其他任何数量的东西,但它应该可以帮助您入门。

    【讨论】:

      【解决方案4】:

      试试这个代码

      <html>
      <head>
           <style>
                #ss{
                     background:#ccc;
                     height:100px;
                     width:100px;
                    position: absolute;
                    top: 0;
                    left: 0;
                   }
           </style>
           <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js">
          </script>
      </head>
      <body>
        <div id="ss"></div>
      </body>
      
      <script type="text/javascript">     
      var $div = $('#ss');
      $(document).keydown(function(e) {
           switch (e.which) {
              case 37:
                    $div.css('left', $div.offset().left - 10);
                    break;
              case 38:
                    $div.css('top', $div.offset().top - 10);
                    break;
              case 39:
                    $div.css('left', $div.offset().left + 10);
                    break;
              case 40:
                    $div.css('top', $div.offset().top + 10);
                    break;
             }
        })
       </script>
      
       </html>
      

      【讨论】: