最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - Get the element from above or below - Stack Overflow

matteradmin3PV0评论

Is there a way to get the element that is visually underneath or above a certain element?

The elements are part of a list, and I want to be able to navigate through the list using the arrow keys. Left/right moves to the previous/next sibling, but I have no idea what to do with up/down.

$(document).on('keydown', function(e) {
  console.log(e.which);

  var current = $('li.selected');

  switch (e.which) {
    case 37:
      current.prev().addClass('selected').siblings().removeClass('selected');
      break;

    case 39:
      current.next().addClass('selected').siblings().removeClass('selected');
      break;

    default:
      return true;
  }

  e.preventDefault();
});

$('li').on('click', function(e) {
  $(this).addClass('selected').siblings().removeClass('selected');
});
ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}
li {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 1px solid red;
}
li.selected {
  background: red;
}
<script src=".1.1/jquery.min.js"></script>
<ul>
  <li class="selected"></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

Is there a way to get the element that is visually underneath or above a certain element?

The elements are part of a list, and I want to be able to navigate through the list using the arrow keys. Left/right moves to the previous/next sibling, but I have no idea what to do with up/down.

$(document).on('keydown', function(e) {
  console.log(e.which);

  var current = $('li.selected');

  switch (e.which) {
    case 37:
      current.prev().addClass('selected').siblings().removeClass('selected');
      break;

    case 39:
      current.next().addClass('selected').siblings().removeClass('selected');
      break;

    default:
      return true;
  }

  e.preventDefault();
});

$('li').on('click', function(e) {
  $(this).addClass('selected').siblings().removeClass('selected');
});
ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}
li {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 1px solid red;
}
li.selected {
  background: red;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="selected"></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

Share Improve this question edited Jan 16, 2015 at 1:38 Mr. Polywhirl 48.9k12 gold badges94 silver badges145 bronze badges asked Jan 16, 2015 at 1:36 nice assnice ass 16.7k8 gold badges53 silver badges92 bronze badges 4
  • you can read elements' positions and find the one to navigate to. – akonsu Commented Jan 16, 2015 at 1:41
  • 1 I would remend using a <table> instead. Then you can navigate the rows and columns. – Ian Hazzard Commented Jan 16, 2015 at 1:41
  • No, he means that if the div flows, can you detect a neighboring div. (Think line wrapping) – Mr. Polywhirl Commented Jan 16, 2015 at 1:41
  • I want to avoid tables, because the number of columns is variable (as much as they can fit). But heights should be equal like in tables, that's why I chose flex... – nice ass Commented Jan 16, 2015 at 1:45
Add a ment  | 

3 Answers 3

Reset to default 5

I wrote a function to search sibling nodes and check their left position within the bounds of the element width.

function findDown(node) {
  return findInSiblings(node, node.nextAll());
}

function findUp(node) {
  return findInSiblings(node, node.prevAll());
}

function findInSiblings(node, siblings) {
  var x = node.offset().left,
    w = node.width() / 2;
  for (var i = 0; i < siblings.length; i++) {
    var sibling = $(siblings[i]);
    if (sibling[0].nodeType === 1) {
      var offset = sibling.offset().left;
      if (offset - w < x && offset + w > x) {
        return sibling;
      }
    }
  }
  return null;
}

Demo

$(document).on('keydown', function(e) {
  var current = $('li.selected');
  var node = getNode(current, e.which);
  if (node == null) {
    return true;
  }
  select(node);
  e.preventDefault();
});

$('li').on('click', function(e) {
  select($(this));
});

function select(node) {
  node.addClass('selected').siblings().removeClass('selected');
}

function getNode(selected, direction) {
  switch (direction) {
    case 37: // Left
      return selected.prev();
    case 38: // Up
      return findUp(selected);
    case 39: // Right
      return selected.next();
    case 40: // Down
      return findDown(selected);
  }
  return null;
}

function findDown(node) {
  return findInSiblings(node, node.nextAll());
}

function findUp(node) {
  return findInSiblings(node, node.prevAll());
}

function findInSiblings(node, siblings) {
  var x = node.offset().left,
    w = node.width() / 2;
  for (var i = 0; i < siblings.length; i++) {
    var sibling = $(siblings[i]);
    if (sibling[0].nodeType === 1) {
      var offset = sibling.offset().left;
      if (offset - w < x && offset + w > x) {
        return sibling;
      }
    }
  }
  return null;
}
ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}
li {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 1px solid red;
}
li.selected {
  background: red;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="selected"></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

A couple ideas:

1) You could always just calculate the number that are shown on each line since you can get the width of the page.

2) You could use document.elementFromPoint and test a point that is below your current element.

Get the offsetLeft property of the current element.

var currentLeft = current.prop("offsetLeft");

Look at each next or previous element until you find the one with the same offsetLeft property.

case 38:
  var el = current.prev();
  while (el.length && el.prop("offsetLeft") != currentLeft) {
    el = el.prev();
  }
  if (el.length) {
    current.removeClass("selected");
    el.addClass("selected");
  }
  break;

$(document).on('keydown', function(e) {
  console.log(e.which);

  var current = $('li.selected');
  var currentLeft = current.prop("offsetLeft");

  switch (e.which) {
case 37:
  current.prev().addClass('selected').siblings().removeClass('selected');
  break;

case 39:
  current.next().addClass('selected').siblings().removeClass('selected');
  break;

case 38:
  var el = current.prev();
  while (el.length && el.prop("offsetLeft") != currentLeft) {
    el = el.prev();
  }
  if (el.length) {
    current.removeClass("selected");
    el.addClass("selected");
  }
  break;

case 40:
  var el = current.next();
  while (el.length && el.prop("offsetLeft") != currentLeft) {
    el = el.next();
  }
  if (el.length) {
    current.removeClass("selected");
    el.addClass("selected");
  }
  break;

default:
  return true;
  }

  e.preventDefault();
});

$('li').on('click', function(e) {
  $(this).addClass('selected').siblings().removeClass('selected');
});
ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}
li {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 1px solid red;
}
li.selected {
  background: red;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="selected"></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

Post a comment

comment list (0)

  1. No comments so far