【问题标题】:CSS grid layout - how to work out which grid cell the mouse is in with javascript?CSS网格布局 - 如何使用javascript计算鼠标所在的网格单元格?
【发布时间】:2016-12-17 13:15:24
【问题描述】:

"css 网格布局" = https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout

有没有人知道一种 javascript 方法来计算鼠标当前所在的列/行?

我猜这样的事情是获取鼠标所在单元格的开始,但这仅对大小相等的网格有用。

MouseGridColumn = round(mouseX / ( gridContainerWidth  / gridTotalColumnsNumber ) )
MouseGridRow    = round(mouseY / ( gridContainerHeight / gridTotalRowsNumber    ) )

有没有办法对不相等的单元格执行此操作?


更新 1 - 添加代码笔

这是一个代码笔,它显示了 3 个不同百分比的列宽 (grid-template-columns: 25% 50% 25%;)、2 行、一个没有元素的网格单元和一个跨越多行的元素:http://codepen.io/anon/pen/NbeOXp


更新 2 - 尝试计算鼠标所在的网格单元格。

在这里,我为网格中的每个单元格添加了隐藏元素,以检测鼠标所在的单元格。但是它只返回它所在的当前元素的“自动”。添加额外的隐藏元素也很笨拙网格 IMO。

http://codepen.io/anon/pen/gLZBZw提示:使用鼠标悬停在网格上。

【问题讨论】:

  • 如果你知道你所在的当前元素,你就可以知道该元素在它的父元素中的位置(以及他的父元素 [grid-container] 中的父元素 [row])。
  • 您能否准备一个fiddle 以便我们了解您的标记有多复杂?
  • 感谢@Pawel,但是我正在尝试获取鼠标所在的当前单元格而不是元素。如何计算其中没有元素的单元格的网格坐标。类似的问题适用于跨越两个单元格的跨越元素。我能看到的唯一解决方案是,如果我在每个网格单元格中放置“隐藏元素”并定位它,但这感觉有点笨拙并且不是很动态。
  • 这是一个非常有趣的问题,但我怀疑不会有简单的答案。没有任何东西代表 DOM 中的各个网格区域(只有可以放置在区域中的元素 - 但即便如此,它们也可能不会覆盖整个区域),因此没有事件信息的知识来源。在我看来,通用解决方案的唯一可能性是使用所需的项目填充和渲染网格,对网格线及其相对于内容的相应位置进行逆向工程,然后基于此确定位置。不容易,也不高效。

标签: javascript css css-grid


【解决方案1】:

将事件监听器添加到网格列的父级。它称为事件委托。您可以在悬停事件和内部 for 循环中使用 event.target 比较 ev.target.parent element==document.querySelect("#parentElement")[index] 如果您愿意,请发布您的所有代码 html 代码以准确编写它。

【讨论】:

  • 嗨@partizanos,感谢您的回答:) 我在上面添加了一个codepen。我不确定这是否完全有效。这不是假设每个网格单元中都有一个元素吗?如果其中一个单元格是空的怎么办?另外,如果一个元素跨越多个单元格怎么办?
【解决方案2】:

我认为您正在为不同大小的网格寻找解决方案,而网格的概念是它们始终具有相同的大小(totalWidth/gridNumber)。只有元素可能会溢出 1、2、5 或更多网格。我做了一个小对象来检测网格数的变化,如果我误解了什么,请在评论中解释。

http://codepen.io/devrafalko/pen/bBOQbo?editors=1011

gridDetect = {
  gridNum:12,
  currentGrid:null,
  callback:null,
  initGridDetect: function(fun){
    var b = this.detectGrid.bind(this);
    document.addEventListener('mousemove',b);
    this.callback = fun;
  },
  detectGrid: function(event){
    var w = document.body.clientWidth;
    var mouse = event.clientX;
    var limitMouse = mouse > w ? w:mouse;
    var getGridNumber = Math.floor(limitMouse/(w/this.gridNum));
    if(this.currentGrid!==getGridNumber){
      this.currentGrid = getGridNumber;
      this.callback(getGridNumber);
    }
  }
}


gridDetect.initGridDetect(function(grid){
  console.log(grid);
  //it's called when the grid is about change
  //do what you want here with grid argument
});

【讨论】:

  • 嗨@Pawel,感谢您的回答:) 这对于大小相等的网格非常有用,但是 css 网格使您可以拥有不同高度和宽度的列和行。我当前的示例显示了各种宽度的列:grid-template-columns: 25% 50% 25%;.
【解决方案3】:

在这里,我使用可以帮助您的东西,使用 .getComputedStyle,并获取网格的行和列(.gridTemplateRows.gridTemplateColumns)的已计算值,这会将其保存在数组中,您可以随心所欲地迭代它

https://codepen.io/leirbagabo/pen/MWoLYKz

【讨论】:

    【解决方案4】:

    你在这里有两个任务:

    1. 检测元件。
    2. 获取元素的列/行。

    检测元素

    如果您为每个网格项目添加所需的事件处理程序,您可以避免检测元素。

    但是,如果您想添加鼠标悬停(或其他事件处理程序),您可以通过每个网格项添加循环并使用element.getBoundingClientRect() 方法。 Demo(我会为点击添加处理程序以避免污染控制台):

    var grid = document.querySelector(".grid");
    
    grid.addEventListener("click", function(event) {
      var gridItems = this.children;
      for (var i = 0; i < gridItems.length; i++) {
        var gridItem = gridItems[i];
        var rect = gridItem.getBoundingClientRect();
        var elementDetected = event.clientX >= rect.left
        	&& event.clientX <= rect.right
          && event.clientY >= rect.top
          && event.clientY <= rect.bottom;
        if (elementDetected) {
          console.log(gridItem);
          return;
        }
      }
      
      console.log("no element detected!");
    });
    .grid {
      display: grid;
      grid-template-columns: repeat(3, 100px);
      grid-template-rows: repeat(3, 100px);
      grid-gap: 10px;
    }
    
    /* styles just for demo */
    .grid__item {
      background-color: tomato;
      color: white;
      
      /* styles for centering text */
      display: flex;
      align-items: center;
      justify-content: center;
    }
    <div class="grid">
      <div class="grid__item">One</div>
      <div class="grid__item">Two</div>
      <div class="grid__item">Three</div>
      <div class="grid__item">Four</div>
      <div class="grid__item">Five</div>
      <div class="grid__item">Six</div>
      <div class="grid__item">Seven</div>
      <div class="grid__item">Eight</div>
      <div class="grid__item">Nine</div>
    </div>

    由于 is(":hover") 方法,使用 jQuery 会使这项任务更加简单。

    $(".grid").click(function(event) {
      var hoveredGridItems = $(this).children()
        .filter(function() { return $(this).is(":hover"); });
      
      if (hoveredGridItems.length > 0)
        console.log(hoveredGridItems[0]);
      else
        console.log("no element detected!");
    });
    .grid {
      display: grid;
      grid-template-columns: repeat(3, 100px);
      grid-template-rows: repeat(3, 100px);
      grid-gap: 10px;
    }
    
    /* styles just for demo */
    .grid__item {
      background-color: tomato;
      color: white;
      
      /* styles for centering text */
      display: flex;
      align-items: center;
      justify-content: center;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <div class="grid">
      <div class="grid__item">One</div>
      <div class="grid__item">Two</div>
      <div class="grid__item">Three</div>
      <div class="grid__item">Four</div>
      <div class="grid__item">Five</div>
      <div class="grid__item">Six</div>
      <div class="grid__item">Seven</div>
      <div class="grid__item">Eight</div>
      <div class="grid__item">Nine</div>
    </div>

    获取元素的列/行

    我在这里只信任 CSS,因此只有当我们明确设置 grid-columngrid-row 属性时,才能按预期获取列和行。所以你有几行代码可以在任何情况下工作:

    // pure JS
    var styles = window.getComputedStyle(gritItem);
    var gridColumn = styles["grid-column-start"];
    var gridRow = styles["grid-row-start"];
    
    // jquery
    var gridColumn = $gridItem.css("grid-column");
    var gridRow = $griditem.css("grid-row");
    

    如果gridColumn 和/或gridRow 的值不是auto / auto,那么您肯定知道行和列。

    但是在自动放置时检测行和列是非常不可靠的,因为可能的列跨度/行跨度值不同,可能是网格项目的marginsalign-selfjustify-self(元素只能占据一部分的情况)网格区域)等

    【讨论】:

      【解决方案5】:

      将带有自定义标签或类的空元素添加到网格的顶部和左侧边缘,使用“stretch”设置它们的样式,然后将宽度/高度相加以获得网格线的坐标。

      【讨论】:

        猜你喜欢
        • 2020-06-30
        • 1970-01-01
        • 1970-01-01
        • 2021-05-19
        • 2017-12-14
        • 1970-01-01
        • 2014-01-18
        • 2019-10-04
        • 1970-01-01
        相关资源
        最近更新 更多