【问题标题】:lag while dragging element拖动元素时滞后
【发布时间】:2020-09-14 15:21:34
【问题描述】:

我正在实现一个功能,我可以在其中添加、拖动和删除网页上的“便笺”。该应用程序是在 Vue js 中构建的,但它也在 iframe 中呈现内容。添加到页面的所有注释都必须位于 iframe 顶部(几乎是 .vue 主页面的 80%),因此在这里定位很重要,我还必须保留位置,因为我必须渲染注释在下一页重新加载的相同位置。问题是拖动“note”元素有很多滞后。 “便笺”本身是一个非常轻量级的独立组件。
我注意到这是因为 vue 页面上存在 iframe,因为当我在浏览器中检查 DOM 并删除 iframe,然后尝试拖动“note”组件时,它可以顺利运行。

我尝试过的事情:

  1. 使用节流:我尝试使用loadsh.throttle,但这没有任何区别。
  2. 在 iframe 中注入“便笺”代码:我尝试将便笺元素注入 iframe 并将其附加到 iframe 的正文中。它实际上使拖动非常顺畅。但是我不想继续使用这个解决方案,因为那样我将不得不编写大量额外的代码来维护多个笔记的状态(这可以使用 Vue js 轻松完成)。 在这个解决方案中,我没有使用主页的document来附加拖动事件,而是将所有事件附加到iframe.contentDocument

所以这里的问题是如何在使用 vue.js 时使拖动平滑
沙盒链接:https://codesandbox.io/s/affectionate-jang-3c1hw?file=/src/components/HelloWorld.vue

在这个 gif 中,背景实际上是 iframe,我降低了它的不透明度来隐藏它。
由于跨域问题,我实际上无法将 iframe 包含在沙盒代码中,但我在该沙盒中包含了许多额外内容以使其繁重

更新: 使用 chrome 任务管理器,我发现页面只占用了最大 200MB 内存,而 GPU 进程又占用了 200MB。我在具有 16GB RAM 的系统上运行它。所以我认为这不是内存问题。但是当我开始拖动元素时,CPU 消耗突然激增(高达 40%)。

更新:
我已经找到了解决这个问题的方法。实际问题不是滞后,而是鼠标拖尾,即可拖动元素无法赶上快速移动的鼠标光标。缓慢是由于Note.vue 内部的dragMouseDown 方法中的e.preventDefault。只需删除 e.preventDefault 即可解决所有问题。此外,在dragMouseDown 方法的末尾添加一个return false 似乎会导致相同数量的延迟。

function dragMouseDown(e) {
     e = e || window.event;
     
     // e.preventDefault(); --> this line causes the mouse trailing issue
   
     document.onmouseup = closeDragElement;     
     document.onmousemove = elementDrag;

     // return false; --> adding this line also causes mouse trailing problem.
}

所以现在我刚刚从这个函数中删除了preventDefault。但我尝试搜索并找不到这种行为的任何解释。另外我不确定不取消活动是否会导致任何其他问题。

【问题讨论】:

  • 代码笔只是为我呈现白屏?
  • @JohnSnow 确实需要一些时间来初始化。
  • 我试过你Code Sandbox中的便签,效果不错。
  • 当屏幕上有很多其他内容时,它开始滞后。沙盒中有一个v-for。让它做更多的迭代,它会开始滞后
  • 是否有可能只是在您打开检查器工具时才滞后?或试试这个codesandbox.io/s/white-bird-9vvu0

标签: javascript vue.js iframe draggable


【解决方案1】:

问题是您正在使用mousemove 而不使用requestAnimationFrame 去抖动。这是一个使用 debounce 的工作示例 (CodeSandbox link)

一般来说,每当您尝试使用 javascript 制作动画时,您都希望使用 requestAnimationFrame。您可以尝试的另一件事是使用变换来更改元素的位置而不是绝对位置。

这是 requestAnimationFrame 上的MDN reference

这是一个article by Paul Irish,关于使用变换而不是绝对定位来加速拖放。

【讨论】:

    【解决方案2】:

    作为您在 cmets 中的额外描述,

    当屏幕上有很多其他内容时,它开始滞后。有 沙盒中的 v-for。让它做更多的迭代,它会开始 迟钝

    您遇到的问题是您页面上的 Dom 元素过多,导致内存使用率过高。 (其实我试过<div v-for="i in 10000" :key="i">",然后用了大约3GB的内存),最后,一切都运行缓慢且滞后

    如果您的页面有大量 Dom 元素,您可能必须考虑在滚动时仅将可见项动态添加到 Dom 树中。

    即使有一些包已经实现了这个功能。

    下面是一个演示,它使用vue-virtual-scrollerRecycleScroller

    100K items in the Codepen

    您会看到即使项目数量为 100,000,它仍然可以顺利运行。

    PS:您可能会注意到上述包的用户指南中的以下声明=vue-virtual-scroller

    浏览器对 DOM 元素有大小限制,这意味着 目前虚拟滚动条不能显示超过 ~500k 的项目 取决于浏览器。

    【讨论】:

    • 就像问题中提到的那样,我只使用v-for 来模拟我页面中的iframe。 iframe(具有自动生成的 HTML)确实有很多 absolute 定位的 DOM 元素。我不认为你提到的包可以帮助我。此外,就像我提到的,如果将FormNote 组件的 HTML 附加到 iframe 内的 body 上,滚动会更加顺畅。由于最后一种行为,我很难相信滞后是因为 DOM 元素太多。 (我可能完全错了)
    • 我提到的包只是一个可以动态构建可见项目的示例。如果它不符合您的要求,您可能想要实现自己的或在 NPM 中找到您需要的东西。无论如何,如果您的 iframe 中有大量 Dom 节点并且已经对性能产生了很大影响,您可能必须考虑根据您的实际需求动态构建 Dom 节点。即使您在 iframe 中放置了数百万个可见项,用户也应该只能看到其中的一部分,因为屏幕尺寸有限,并且可能导致用户无法从 UI 中快速找到所需的内容。
    • 我刚刚在 chrome 任务管理器中检查了该页面在任何给定时间最多只占用 200MB,而且我还看到大约 120MB GPU 进程。然而,当我开始拖动元素时,CPU 消耗突然激增(高达 40%)。我在一台 16GB RAM 的机器上运行它。所以我认为这里的内存不是问题。
    • 抱歉,由于保密协议,我不能这样做
    猜你喜欢
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多