有没有办法让添加事件侦听器先执行 mousedown,然后 mouseover,最后 mouseup?

Is there a way to have an add event listener first execute a mousedown, then mouseover, and finally mouseup?

所以现在我有一个 20 x 20 的网格,我希望用户能够单击并 select 网格中的多个单元格。我可以在网上找到一种方法,但问题是当鼠标悬停在单元格上时鼠标悬停接管并突出显示单元格,这不是我想要的。我希望用户单击一个单元格,然后基本上拖动他们的鼠标并突出显示他们想要的单元格,然后在他们放开后执行 mouseup。

这些是我的文件。

let graph = document.getElementById("container");
graph.style.display = "flex";


function createGraph() {

  let j = 0;
  for (let i = 0; i < 20; i++) {
    let row = document.createElement("div");
    row.id = "row" + i;


    row.style.height = "50px";
    row.style.width = "50px";

    graph.appendChild(row);

    let currentRow = document.getElementById("row" + i);
    j++;

    for (let j = 0; j < 20; j++) {
      let cell = document.createElement("div");
      cell.classList.add("cells");
      ///id's are used later in the project
      cell.id = "index" + j + i;
      cell.style.border = "1px solid black";
      cell.style.height = "50px";
      cell.style.width = "50px";
      currentRow.appendChild(cell);


    }
  }
}

createGraph();

function main() {

  document.querySelectorAll(".cells").forEach(item => {

    ["mousedown", "mouseover", "mouseup"].forEach(function(e) {
      item.addEventListener(e, function() {
        item.style.backgroundColor = "red";
      })
    })

  })
}

main();
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Document</title>
</head>

<body>
  <div id="container"></div>
</body>

</html>

所以在主要功能中,我为所有单元格添加了一个均匀的侦听器,并且我试图将它们的颜色更改为红色。问题是 mouseover 事件接管了 mousedown,这是我想要首先发生的。我怎样才能做到这一点,以便用户能够首先单击一个单元格,然后拖动他们的鼠标并继续突出显示单元格,一旦他们放开鼠标,突出显示就会停止。有没有办法先执行mousedown,再执行mouseover,最后执行mouseup?

像这样的技巧是只在 mousedown 上添加 mouseover 事件开始。 mouseover 无论如何,这通常是一个昂贵的事件(因为它会触发很多),所以您只在需要时“打开它”,在不需要时将其删除。

此外,如果您将同一事件关联到同一 parent 中的多个元素,最好 far 将事件分配给 parent 然后检查 target 并在它是您想要的 children 之一时采取行动(通常使用 .matches() 方法)。

然后,您不必担心 mousemove 先触发,因为它总是会触发第二个。请注意,每个单元格可能会触发多次,因此您需要编写代码来处理它。

let targetElements = [];
const parent = document.querySelector('.parent');

const mouseoverHandler = ({ target }) => {
  if (!target.matches('.parent span') 
    || targetElements.includes(target)) {
    return;
  }
  
  targetElements.push(target);
};

parent.addEventListener('mousedown', ({ target }) => {
  // use whatever selector makes sense for your children
  if (!target.matches('.parent span')) return;
     
  // reset the list here in case they mouseup-ed outside of the parent
  targetElements = [];
     
  // turn mouseover "on"
  parent.addEventListener('mouseover', mouseoverHandler);
  targetElements.push(target);
  
  console.log('mouseover on');
});

parent.addEventListener('mouseup', ({ target }) => {
  // use whatever selector makes sense for your children
  if (!event.target.matches('.parent span')) return;
  
  // turn mouseover "off"
  parent.removeEventListener('mouseover', mouseoverHandler);
  
  // do something with them
  targetElements.forEach(el => el.classList.toggle('on'));
  
  console.log('mouseover off');
});
.parent {
  border: 2px solid #333;
  width: 150px;
  display: flex;
  flex-wrap: wrap;
}

.parent span {
  flex: 0 0 50px;
  flex-wrap: wrap;
  height: 50px;
  border: 1px solid #CCC;
  margin: -1px;
  height: 50px;
  display: -block;
}

.parent span:hover {
  /* doesn't seem to work in the demo window */
  background: #EEC;
  cursor: pointer;
}

.parent span.on {
  background: #F00;
}
<div class="parent">
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>

我稍微重构了你的代码。这是一个如何使用切换状态的简单示例:

let graph = document.getElementById('container');


function createGraph() {

  for (let i = 0; i < 20; i++) {
    let row = document.createElement('div');
    row.id = 'row' + i;
    row.className = 'rows';

    for (let j = 0; j < 20; j++) {
      let cell = document.createElement('div');
      cell.className = 'cells';
      cell.id = 'index' + j + i;
      row.appendChild(cell);
    }
    
    graph.appendChild(row);
  }
}

createGraph();

function main() {

  let canSelect = false;

  document.addEventListener('mousedown', () => canSelect = true);
  document.addEventListener('mouseup', () => canSelect = false);

  document.querySelectorAll('.cells').forEach(item => {

    ['mousedown', 'mouseover'].forEach(function(e) {
      item.addEventListener(e, () => {
        if (!canSelect && e !== 'mousedown') return;
        
        item.style.backgroundColor = 'red';
      })
    })
  })
}

main();
#container {
  display: flex;
}

.rows, .cells {
  width: 50px;
  height: 50px;
}

.cells {
  border: 1px solid black;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Document</title>
</head>

<body>
  <div id="container"></div>
</body>

</html>