【问题标题】:jQuery UI Sortable with multiple elements throws "TypeError: Cannot read property 'insertBefore' of null"具有多个元素的 jQuery UI 可排序抛出“TypeError:无法读取属性 'insertBefore' of null”
【发布时间】:2018-03-26 13:06:33
【问题描述】:

我正在尝试按照this answer 中的示例使用多个元素实现拖放:http://jsfiddle.net/hQnWG/614/

该示例适用于 jQuery 1.9.1 和 jQuery UI 1.9.2(最高 1.10.1),但只要我使用更新版本,如 jQuery 1.11.3 和 jQuery UI 1.10.2 或更新版本,我得到以下问题。

选择多个元素并开始将底部最选择的元素慢慢向顶部拖动到顶部时,右在它将捕捉到下一个位置,则以下js错误是蜂窝:

Uncaught TypeError: Cannot read property 'insertBefore' of null
   at t.(/hQnWG/614/anonymous function).(anonymous function)._rearrange (https://code.jquery.com/ui/1.10.2/jquery-ui.min.js:7:15171)
   at t.(/hQnWG/614/anonymous function).(anonymous function)._rearrange (https://code.jquery.com/ui/1.10.2/jquery-ui.min.js:5:5028)
   at t.(/hQnWG/614/anonymous function).(anonymous function)._mouseDrag (https://code.jquery.com/ui/1.10.2/jquery-ui.min.js:7:6)
   at t.(/hQnWG/614/anonymous function).(anonymous function)._mouseDrag (https://code.jquery.com/ui/1.10.2/jquery-ui.min.js:5:5028)
   at t.(/hQnWG/614/anonymous function).(anonymous function)._mouseMove (https://code.jquery.com/ui/1.10.2/jquery-ui.min.js:5:12328)
   at t.(/hQnWG/614/anonymous function).(anonymous function)._mouseMove (https://code.jquery.com/ui/1.10.2/jquery-ui.min.js:5:5028)
   at HTMLDocument.o._mouseCapture._mouseDistanceMet._mouseDelayMet._mouseMoveDelegate (VM687 jquery-ui.min.js:5)
   at HTMLDocument.dispatch (VM251 jquery-1.11.3.min.js:4)
   at HTMLDocument.r.handle (VM251 jquery-1.11.3.min.js:4)

这是一个带有升级 jQuery 版本的示例 jsfiddle 的分支: http://jsfiddle.net/v3p6wsk2/6/

我尝试调试它,但找不到任何解释如何拖动项的 parentNode 可以为空。

我什至在 jQuery UI 1.10.2. change log 中找不到任何关于可能破坏该脚本的更改的提示。

很遗憾,我无法更改我正在处理的项目中的版本。是否有可能使用上述版本?

【问题讨论】:

  • 不是一个完整的例子。请查看:stackoverflow.com/help/mcve 我们需要查看您的代码。另外,我怀疑您可能需要为 Sortable 定义 items 选项。
  • 第二个 jsfiddle 链接实际上是有错误的代码,也是我隔离问题的地方。与第一个 jsfiddle 的唯一区别在于 lib 版本。
  • 感谢您的澄清,不清楚。我试图复制你描述的问题。我拖了 1 个项目,没问题。我拖了2个项目,没问题。我“慢慢地”拖了 2 个项目(你能定义一下你的意思吗?),没问题。我正在 Ubuntu 上使用 FireFox 59(32 位)进行测试。
  • 注意到您没有正确使用资源进行小提琴,将 jQuery 移动到资源部分并进行了测试:jsfiddle.net/Twisty/wzuak8as/1 我仍然无法复制该问题。
  • 好的,我只能在 Chromium 中复制错误。此外,它不是一个表演停止者。我仍然可以继续使用适当的功能进行拖放。你也是这种情况吗?我将从 Minimized 版本切换到 Uncompressed 版本,以确定失败的确切代码行。

标签: jquery jquery-ui jquery-ui-sortable


【解决方案1】:

据我所知,问题在于调用parentNode.insertBefore 的元素是被拖动元素之一(已从原始表中删除),因此实际上不再具有父元素。

真正让我感到困惑的是,我认为问题不直接出现在 helperstop 函数中,而是介于两者之间,因为错误是在 sort-event 之后立即触发的。

我不知道这个问题出在哪里,因为它与旧版本一起运行,但通过反复试验,我可能找到了解决您问题的方法。

您可以隐藏它们并在将删除的元素插入列表后删除隐藏的元素,而不是删除助手中的元素。

twistys fiddle I just updated

这可能会解决您的问题,尽管这并不能解决(甚至找不到)此问题的原因。

【讨论】:

  • 谢谢,这对我来说很完美。我最终更改了 onClick,以便您可以通过再次单击取消选择单击:jsfiddle.net/wzuak8as/123
【解决方案2】:

所以问题的根源就在这里:

_rearrange: function(event, i, a, hardRefresh) {
  a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));

  //Various things done here to improve the performance:
  // 1. we create a setTimeout, that calls refreshPositions
  // 2. on the instance, we have a counter variable, that get's higher after every append
  // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
  // 4. this lets only the last addition to the timeout stack through
  this.counter = this.counter ? ++this.counter : 1;
  var counter = this.counter;

  this._delay(function() {
    if(counter === this.counter) {
      this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
    }
  });
}

当我使用未压缩版本生成错误时,我看到:

Uncaught TypeError: Cannot read property 'insertBefore' of null
    at $.(anonymous function).(anonymous function)._rearrange (https://code.jquery.com/ui/1.10.3/jquery-ui.js:4628:68)
    at $.(anonymous function).(anonymous function)._rearrange (https://code.jquery.com/ui/1.10.3/jquery-ui.js:401:25)
    at $.(anonymous function).(anonymous function)._mouseDrag (https://code.jquery.com/ui/1.10.3/jquery-ui.js:3879:11)
    at $.(anonymous function).(anonymous function)._mouseDrag (https://code.jquery.com/ui/1.10.3/jquery-ui.js:401:25)
    at $.(anonymous function).(anonymous function)._mouseMove (https://code.jquery.com/ui/1.10.3/jquery-ui.js:933:9)
    at $.(anonymous function).(anonymous function)._mouseMove (https://code.jquery.com/ui/1.10.3/jquery-ui.js:401:25)
    at HTMLDocument._mouseMoveDelegate (https://code.jquery.com/ui/1.10.3/jquery-ui.js:911:16)
    at HTMLDocument.dispatch (https://code.jquery.com/jquery-1.11.3.min.js:4:8549)
    at HTMLDocument.r.handle (https://code.jquery.com/jquery-1.11.3.min.js:4:5252)
Location: jquery-ui.js:4628

_rearrange 函数以条件操作开始。如果 a 存在,则 append 占位符 Else insertBefore() parentNode 在数组中的特定元素。

所以,我猜,.insertBefore() 是 DOM 方法而不是 jQuery 方法。根据该结构,parentNode 正在返回一个 null 元素。

HTML DOM parentNode 属性

返回值:一个Node对象,代表一个节点的父节点,如果该节点没有父节点,则null

好的,所以我们确定 i.item[0].parentNode 正在重新调整 null 值并导致问题。

我怀疑问题的关键在于helper 没有包装,因此stop 的每个项目都没有parent;因此,没有parentNode。我认为解决方法是删除 1 个项目,然后在其后附加其他元素或将元素附加到另一个回调事件中。

我会在获得更多信息后更新。

同样,这并不总是一个阻碍,到目前为止,这只是基于 Chrome 的浏览器中的一个问题。

更新 1

看起来从 stop 切换到 update 回调有帮助。两者的细微差别:

停止(事件,用户界面)

当排序停止时触发此事件。

VS

更新(事件,用户界面)

当用户停止排序并且DOM位置发生变化时触发该事件。

我曾希望这就是诀窍。更新后我最初没有得到它,然后我得到了它。必须继续工作。

更新 2

这个小提琴在 FF 和 Chromium 中没有错误:https://jsfiddle.net/Twisty/wzuak8as/99/

我能够隔离创建helper 的错误。我认为这个问题与这行代码有关:

return helper.append(elements);

所以这段代码表明我们正在返回一个 jQuery 对象,helper,它是一个 <li> 元素作为匿名函数的结果。同时,我们尝试将额外的 jQuery 对象 elements 添加到 <li> 元素中。

当我将代码调整为:

helper.append(elements);
return helper;

错误不再出现。

我回去查看了 jQuery UI 1.9.2 中的相同功能:

_rearrange: function(event, i, a, hardRefresh) {
  a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));
  //Various things done here to improve the performance:
  // 1. we create a setTimeout, that calls refreshPositions
  // 2. on the instance, we have a counter variable, that get's higher after every append
  // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
  // 4. this lets only the last addition to the timeout stack through
  this.counter = this.counter ? ++this.counter : 1;
  var counter = this.counter;
  this._delay(function() {
    if(counter == this.counter) this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
  });
}

我找不到这两个库的区别。我也无法找出为什么一个人操作没有错误而一个人没有。它们应该是相同的。

在我的测试中,我已经能够无错误地运行代码。我希望这会有所帮助,您会将其标记为答案。

开发者工具正在缓存控制台结果,但我没有看到错误出现。我回到您的原始代码,应用了更改,得到了同样的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2015-10-25
    • 2022-12-20
    • 1970-01-01
    相关资源
    最近更新 更多