jQuery UI使用多个元素进行排序会抛出“TypeError:无法读取属性'insertBefore'的null”

时间:2018-03-26 13:06:33

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

我正在尝试实施拖放功能请按照this answerhttp://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如何为null。 enter image description here

我甚至无法在jQuery UI 1.10.2. change log中找到有关可能会破坏该脚本的更改的任何提示。

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

2 个答案:

答案 0 :(得分:4)

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

我真正得到的是,我认为问题并非直接位于helperstop函数中,而是介于两者之间,因为错误会在sort - 事件之后立即触发

我不知道这个问题出在哪里,因为它在旧版本中运行,但通过试用和错误我可能找到了解决问题的方法。

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

请参阅twistys fiddle I just updated

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

答案 1 :(得分:1)

问题的根源在于:

_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

  

更新(event,ui)

     

当用户停止排序并且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
  });
}

我无法在两个库中找到差异。我也无法找出为什么一个人没有错误而且一个人没有错误。它们应该是一样的。

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

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

相关问题