在 javascript 中使用箭头键移动所选元素

move selected element with arrow keys in javascript

我有一个项目列表,我希望能够 select 一个项目(通过单击)并仅使用箭头键移动该特定项目。我完成了移动部分,但是当我 select 第二个元素时,它也移动了之前 selected 的元素。或者,如果我双击同一个元素,它会将其弹回到原来的位置。

我猜可能是因为位置是相对的?虽然我已经尝试将其更改为 absolute 并将 parent div 更改为 relative ,但仍然没有用。我也尝试过使用边距,但出现了同样的问题。

move();

function move(){
    let list_items = document.querySelectorAll('.list-item');


    for (let i = 0; i < list_items.length; i ++){
        let list=list_items[i];

        list.addEventListener('click',function(){

            console.log(list);
            var objImage= null;
            objImage=list;              
            objImage.style.position='relative';
            objImage.style.left='0px';
            objImage.style.top='0px';

            
            function getKeyAndMove(e){  
                            
                var key_code=e.which||e.keyCode;
                switch(key_code){
                    case 37: //left arrow key
                    moveLeft();
                    break;
                    case 38: //Up arrow key
                    moveUp();
                    break;
                    case 39: //right arrow key
                    moveRight();
                    break;
                    case 40: //down arrow key
                    moveDown();
                    break;
                    default:
                    console.log(e);                         
                }
            }
            function moveLeft(){
                objImage.style.left=parseInt(objImage.style.left)-5 +'px';
                // objImage.style.position='static';
            }
            function moveUp(){
                objImage.style.top=parseInt(objImage.style.top)-5 +'px';
                // objImage.style.position='static';
            }
            function moveRight(){
                objImage.style.left=parseInt(objImage.style.left)+5 +'px';
                // objImage.style.position='static';
            }
            function moveDown(){
                objImage.style.top=parseInt(objImage.style.top)+5 +'px';
                // objImage.style.position='static';
            }
            window.addEventListener("keydown", getKeyAndMove);
        });
    }
}
.list {
    display: flex;
    flex-flow: column;
    flex: 1;

    width: 100%;
    min-width: 250px;
    max-width: 350px;
    height: 100%;
    min-height: 150px;

    background-color: rgba(0, 0, 0, 0.1);
    margin: 0 15px;
    padding: 8px;
    transition: all 0.2s linear;
}

.list .list-item {
    background-color: #F3F3F3;
    border-radius: 8px;
    padding: 15px 20px;
    text-align: center;
    margin: 4px 0px;
}
            <div class="list" id="list"> 
                <h2>Menu Items</h2>
 
                <div class="list-item" draggable="true">List item 1</div>
                <div class="list-item" draggable="true">List item 2</div>
                <div class="list-item" draggable="true">List item 3</div>
            </div>

EDIT 通过@rexfordkelly 提出的解决方案让它工作。这是他 jsfiddle.net/r7ao2n5f/1

分享的 link 游乐场

如果我理解你的问题,并且你期望的行为是:

Move one or more selected items, selections being made using a mouse, and moving performed via key presses, up, down, left and right.


我想你几乎已经明白了,唯一的问题是你的选择永远不会被清除,这应该是在移动完成后发生任何点击时。

您可以考虑在模式中对行为进行建模。

  • 选择
  • 移动

用伪代码完成的行为是这样的:

let mode = 0; // selection mode
let selections = [];

... key press event Listeners
... click event Listeners

function processAction( action, event ) {
    If ( 'click' == action && 0 != mode ){ // was in move mode
        mode = 0; // Set to selection mode.
        selections = []; // resets the selections made
        ... // reset DOM, and clear any currently decorated elements
    }

    if ( 'click' == action) {
        selections.push(event.targetElement);
        ...// Update DOM and decorate elements
    }

    If ( 'move' === action && mode !== 1) {
        mode = 1; // This enters us into "Move" mode.
    }

    If ( 'move' === action ){
        // Execute moving logic
    }
}

解决您的“双击”问题。

Or if I double click the same element, it snaps it back to it's original position

这是某些“标准”行为的结果,或者当用户拖动元素时浏览器对其行为的“预设”。您可以通过几种方式禁用此“标准”行为,一种是 CSS

.list-item  { 
  -webkit-user-drag: none; 
  -khtml-user-drag: none; 
  -moz-user-drag: none; 
  -o-user-drag: none; 
  user-drag: none; 
}
 

您可以在 MDN here 上了解更多关于此“默认”行为的信息:

If this attribute is not set, its default value is auto, which means drag behavior is the default browser behavior: only text selections, images, and links can be dragged...


哦,我忘了说,你可以简单地将你的事件监听器附加到 id="list" 元素,因为所有 children 的点击事件都会冒泡并被拦截。

您可以找到有关如何确定单击了哪个元素的详细信息here and more about how events bubble here and on MDN here,特别是“冒泡和捕获解释”部分

PS:我在一些应用程序中也看到过,它们有类似的行为,用鼠标进行选择,用箭头键移动。当按住“shift”键并按下箭头键时,它们允许用户移动不同的距离。