首页 > 解决方案 > 如何仅对水平和垂直进行框过渡?

问题描述

我试图让一个盒子在箭头按下时水平和垂直移动。但是,例如up arrow,当我按下它时,right arrow它是对角线的。这是我的代码笔

.box {
  background-color: gray;
  height: 100px;
  width: 100px;
  transition: margin 0.5s cubic-bezier(0, .7, 0, 1);
}
const box = document.getElementsByClassName('box')[0];

document.addEventListener('keydown', function({keyCode, which}) {
  const keycode = keyCode ? keyCode : which,
        startValue = '0px',
        shiftValue = '400px';

  console.log(box.style.marginLeft, box.style.marginTop)
  switch(keycode) {
    case(40):
      box.style.marginTop = shiftValue;
      break;
    case(39):
      box.style.marginLeft = shiftValue;
      break;
    case(38):
      box.style.marginTop = startValue;
      break;
    case(37):
      box.style.marginLeft = startValue;
      break;
  }
});

标签: javascriptcssanimationtransition

解决方案


一种可能的解决方案:您可以跟踪已请求的移动并等待执行移动,直到前一个移动完成。例子:

const box = document.getElementsByClassName('box')[0];

const startValue = '0px';
const shiftValue = '400px';

function moveDown() {
  // The move* functions only perform the move if is valid - i.e., 
  // if it would actually cause a visible change.
  if (box.style.marginTop !== shiftValue) {
    box.style.marginTop = shiftValue;
    return true;
  }
  // The move* functions return true iff the move was made.
  return false;
}

function moveRight() {
  if (box.style.marginLeft !== shiftValue) {
    box.style.marginLeft = shiftValue;
    return true;
  }
  return false;
}

function moveUp() {
  if (box.style.marginTop !== startValue) {
    box.style.marginTop = startValue;
    return true;
  }
  return false;
}

function moveLeft() {
  if (box.style.marginLeft !== startValue) {
    box.style.marginLeft = startValue;
    return true;
  }
  return false;
}

const moves = [];
let timeOfLastMoveInMilliseconds = null;
const animationDurationInSeconds = 0.5; // should match css transition duration
const animationDurationInMilliseconds = animationDurationInSeconds * 1000; 

function onFrame() {
  if (!timeOfLastMoveInMilliseconds) {
    timeOfLastMoveInMilliseconds = performance.now();
  }
  const timeSinceLastMove = performance.now() - timeOfLastMoveInMilliseconds;
  if (moves.length > 0 && timeSinceLastMove >= animationDurationInMilliseconds) {
    const wasMoved = moves.pop()();
    if (wasMoved) {
      timeOfLastMoveInMilliseconds = performance.now();
    }
  }
  window.requestAnimationFrame(onFrame);
}
window.requestAnimationFrame(onFrame);

document.addEventListener('keydown', function({keyCode, which}) {
  const keycode = keyCode ? keyCode : which;
  switch(keycode) {
    case(40):
      moves.unshift(moveDown);
      break;
    case(39):
      moves.unshift(moveRight);
      break;
    case(38):
      moves.unshift(moveUp);
      break;
    case(37):
      moves.unshift(moveLeft);
      break;
  }
});

请注意,上面的代码会跟踪用户所做的每一个动作,因此,例如,如果您快速按下、上、下、上、下,该序列将播放。根据您的应用程序,您可能希望添加限制,例如,仅允许水平+对角线移动和/或仅允许在短时间内发生的按键移动。


推荐阅读