如何仅对水平和垂直进行框过渡?

问题描述 投票:1回答:4

我正在尝试使箭头按下时使框沿水平和垂直方向移动。但是,当我以up arrowright arrow为例时,它是对角线的。这是我的codepen

.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;
  }
});

javascript css animation transition
4个回答
0
投票

尝试以下操作:

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

let moving = false;

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

  console.log(box.style.marginLeft, box.style.marginTop)
  if (!moving && [37, 38, 39, 40].includes(keycode)){
      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;
      }
      moving = true;
      window.setTimeout(() => moving = false, 400); // Not 500, because visually it is very slow towards the end anyway.
  }
});

0
投票

您都可以在此处实现Promise解决方案,但我认为这没有必要。基本上,我们可以做的是将所有按下的键存储在一个数组中,并确保javascript每x毫秒仅通过一次按下的键数组once

const box = document.getElementsByClassName('box')[0];
let pressedKeys = [];
let timeoutHandler = -1;

document.addEventListener('keydown', function({keyCode, which}) {
  // As soon as the user presses a key we will clear the time out
  clearTimeout(timeoutHandler);

  const keycode = keyCode ? keyCode : which,
    startValue = '0px',
    shiftValue = '400px';

  pressedKeys.push(keycode);

  // register the timeout to a variable in order for this function 
  // only run once every x second. This implementation is also 
  // known as 'debounce function to poor people'
  timeoutHandler = setTimeout(() => {
    pressedKeys.forEach((key, index) => {
      // The animation time for each key pressed will be incremental
      // which means the second key pressed will have an animation delay
      // higher than the first one
      const timeoutSeconds = index === 0 ? 1 : index + (index * 100);
      setTimeout(() => {
        switch(key) {
          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;
        }
      }, timeoutSeconds)
    });

    pressedKeys = [];
  }, 100)
});


0
投票

一种可能的解决方案:您可以跟踪请求了哪些移动,并等待执行移动,直到上一个移动完成为止。示例:

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;
  }
});

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


0
投票

因此,我决定在每次按下带有动画的键之间设置500毫秒的间隔,如果不使用动画但没有任何其他异步代码的话,它设置得更快。感谢您的帮助。

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

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

  diff = currentTime - prevTime;

  if (diff > 500) {
    //shift with animation
    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;
    }
  } else {
    //shift without animation
  }

  prevTime = currentTime;
});
© www.soinside.com 2019 - 2024. All rights reserved.