17

在我的 Web 应用程序中,我尝试实现一些拖放功能。我有一个全局 JavaScript 组件来完成基本工作。该对象还负责根据当前的拖动操作(移动、复制、链接)更改鼠标光标。在我的网页上,有各种 HTML 元素定义了自己的光标样式,可以是内联的,也可以是通过 CSS 文件。

那么,有没有办法让我的中央拖放组件全局更改鼠标光标,而与鼠标光标所在元素的样式无关?

我试过:

document.body.style.cursor = "move"

document.body.style.cursor = "move !important"

但它不起作用。每次我拖动定义光标样式的元素时,光标都会更改为该样式。

当然,我可以更改当前拖动的元素的样式,但是当我离开元素时我必须重置它。这似乎有点复杂。我正在寻找一个全球性的解决方案。

4

6 回答 6

17

重要更新(2021 年):

element.setCapture()的 MDN 页面清楚地表明此功能已弃用且非标准,不应在生产中使用。

该页面底部的浏览器支持表表明它仅在 Firefox 和 IE 中受支持。

原答案如下


请:不要屠杀你的 CSS!

要实现拖放功能,您必须使用一个非常重要的 API:element.setCapture(),它执行以下操作:

  • 所有鼠标事件都被重定向到捕获的目标元素,无论它们发生在哪里(甚至在浏览器窗口之外)
  • 光标将是捕获的目标元素的光标,无论鼠标指针在哪里。

您必须调用element.releaseCapture()document.releaseCapture()在操作结束时切换回正常模式。

当心拖放的幼稚实现:您可能会遇到很多痛苦的问题,例如(以及其他):如果将鼠标释放到浏览器窗口之外,或者在具有停止传播的处理程序的元素上释放会发生什么. 使用 setCapture() 解决了所有这些问题,以及光标样式。

如果你想自己实现拖放,你可以阅读这个优秀的教程,它详细解释了这一点。

如果可能的话,也许您也可以在您的上下文中使用可拖动的 jQuery UI 。

于 2012-05-25T12:27:22.740 回答
6
document.body.style.cursor = "move"

应该可以正常工作。

但是,我建议通过 CSS 进行全局样式设置。

定义以下内容:

body{
   cursor:move;
}

问题是,其他元素上定义的光标会覆盖主体样式。

你可以这样做:

your-element.style.cursor = "inherit"; // (or "default")

将其重置为从正文或使用 CSS 继承的样式:

body *{
   cursor:inherit;
}

但是请注意,这*通常被认为是错误的选择器选择。

于 2012-05-25T08:05:53.793 回答
5

不幸的是element.setCapture()不适用于IE

我使用蛮力方法 - 在拖放期间在整个页面顶部打开一个透明 div。

.tbFiller {
   position:absolute;
   z-index:5000; 
   left:0;
   top:0;
   width:100%;
   height:100%; 
   background-color:transparent;
   cursor:move;
}

...

function dragStart(event) {
    // other code...
    document.tbFiller=document.createElement("div");
    document.tbFiller.className="tbFiller"
}

function dragStop(event) {
    // other code...
    document.tbFiller.parentNode.removeChild(document.tbFiller);
}
于 2012-06-26T12:20:20.390 回答
2

感谢这里的一些其他答案的线索,这很好用:

/* Disables all cursor overrides when body has this class. */
body.inheritCursors * {
    cursor: inherit !important;
}

注意:我不需要使用<html>and document.documentElement; 相反,<body>工作document.body得很好:

document.body.classList.add('inheritCursors');

这会导致(因为它现在具有此类)的所有 后代元素从其自身继承其光标,即您将其设置为:<body>inheritCursors<body>

document.body.style.cursor = 'progress';

然后要将控制权交还给后代元素,只需删除该类:

document.body.classList.remove('inheritCursors');

并将光标取消设置<body>为默认值:

document.body.style.cursor = 'unset';
于 2020-07-22T20:41:41.230 回答
2

我尝试使用setPointerCapture效果很好。不利的一面是,(原因)所有指针事件都不会像以前那样工作。所以我失去了悬停样式等。

我现在的解决方案非常简单,并且对于我的用例来说比上面的 CSS 解决方案更适合。

为了设置光标,我在 head 中添加了一个新样式表:

const cursorStyle = document.createElement('style');
cursorStyle.innerHTML = '*{cursor: grabbing!important;}';
cursorStyle.id = 'cursor-style';
document.head.appendChild(cursorStyle);

要重置它,我只需删除样式表:

document.getElementById('cursor-style').remove();
于 2021-05-18T11:12:05.450 回答
1

这就是我所做的,它在 2017 年开始在 Firefox、Chrome、Edge 和 IE 中运行。

将此 CSS 规则添加到您的页面:

html.reset-all-cursors *
{
    cursor: inherit !important;
}

<html>元素具有“reset-all-cursors”类时,这会覆盖在其style属性中为元素单独设置的所有游标——而无需实际操作元素本身。不需要到处清理。

然后,当您想用 any 覆盖整个页面上的光标时element,例如。G。被拖动的元素,在 JavaScript 中执行此操作:

element.setCapture && element.setCapture();
$("html").addClass("reset-all-cursors");
document.documentElement.style.setProperty("cursor", $(element).css("cursor"), "important");

它使用setCapture可用的功能。这目前只是 Firefox,尽管他们说它是 Microsoft API。然后将特殊类添加到整个文档中,从而禁用所有自定义光标。最后在文档上设置你想要的光标,让它出现在任何地方。

结合捕获事件,这甚至可以将拖动光标扩展到页面和浏览器窗口之外。setCapture在 Firefox 中可靠地做到这一点。但在其他地方,它并非每次都有效,具体取决于浏览器、它的 UI 布局以及鼠标光标离开窗口的路径。;-)

完成后,清理:

element.releaseCapture && element.releaseCapture();
$("html").removeClass("reset-all-cursors");
document.documentElement.style.setProperty("cursor", "");

这包括 jQueryaddClassremoveClass. 在简单的场景中,您可以简单地比较并class设置document.documentElement. 不过,这会破坏像 Modernizr 这样的其他库。如果您已经知道元素所需的光标,则可以摆脱该css功能,或者尝试类似element.style.cursor.

于 2017-12-22T19:28:05.003 回答