通知 Polymer dom-重复对本地 DOM 的更改

Inform Polymer dom-repeat of changes to local DOM

我有一个非常基本的自定义元素 tri-playlist,我用它来显示另一个自定义元素的网格 tri-clip

<dom-module id="tri-playlist">
    <template>
        <template is="dom-repeat" items={{clips}}>
            <tri-clip clip-num={{item.clipNum}}></tri-clip>
        </template>
    </template>
</dom-module>

clips 是通过从服务器获取信息动态生成的。我会收到有关此信息(甚至是我自己的)的任何更改的通知,并因此更新 clips,之后模板负责更新视图以反映新数据(剪辑已删除,顺序已更改, ETC)。使用 jQuery UI Sortable,我可以重新排列播放列表中的剪辑或将它们拖到新的播放列表中,然后在 sortstop 上我通知服务器任何更改,以便它保持同步.这一切似乎都很好,分开。

但是, DOM 被我的 jQuery 排序操作后,模板无法正确更新。据我所知,这是因为模板不知道对其(local?/light?)DOM.

的那些更改

例如,假设我在播放列表中有三个剪辑 [A][B][C],我移动第一个剪辑,现在它是最后一个 [B][C][A]。当服务器通知我更改(我自己的)并且我相应地更新 clips 时,模板注意到转换 并第二次执行它 。在此示例中,最终结果为 [C][A][B].

到目前为止,我唯一能让它工作的方法是在正确设置之前设置 clips = [];。这会导致屏幕上的任何 tri-clip 暂时消失,并迫使 Polymer 重新创建元素,这首先打败了 one of the advantages of using a Polymer template(TLDR:聚合物数据绑定使最少量的必要的更改)。

我遇到过this:

When one of the template helper elements updates the DOM tree, it fires a dom-change event.

In most cases, you should interact with the created DOM by changing the model data, not by interacting directly with the created nodes. For those cases where you need to access the nodes directly, you can use the dom-change event.

但是,我不太确定如何将它应用到我的情况中。据我了解,如果我想在 模板 触发更改后对节点执行某些操作,我会使用 dom-change 事件。还是我错了?无论如何通知模板已进行更改并且需要相应地更新其模型?我是不是用错了方法?

不管它值多少钱,我设法想出的解决方法(这并不理想,但解决了我 运行 遇到的问题)本质上是迭代 dom-repeat 并评估对其子项所做的更改(在我的例子中是 jQuery 可排序)。然后执行在 dom-repeatitems 数组上反映这些更改的操作。我使用的是 jQuery multisortable plugin so I had to account for an undetermined amount of changes (where as normally jQuery sortable will only ever change one element at a time) but I figure the code below could easily be optimized for such situations. In the jQuery sortable stop event,我做了以下操作:

1 ) 获取索引(索引是我的 dom-repeat 数组中项目的 属性)反映 dom 元素的位置 before排序

// get indices of selected elements that presumably changed
var target = event.target,
    toRearr = [],
    firstSelected = null;

$( target ).children( '.selected' ).each( function() {
  toRearr.push(this.index);
  // keep reference of first selected for re-ordering start point
  if (firstSelected === null) firstSelected = this;
});

2) 查看 排序后第一个选择的元素在哪里(注意这是与所有子元素相关的,而前一个循环仅选择元素)

// find the index of where we need to 'paste' the elements
var toPaste = -1;
$( target ).children( 'selector' ).each( function( index ) {
  if (this === firstSelected) {

    if (firstSelected.index > index) { // elements were moved to the left
      toPaste = index;
      return false; // breaks out of $.each loop
    }
    else if (firstSelected.index < index){ // elements were moved to the right
      toPaste = index + toRearr.length;
      return false; // breaks out of $.each loop
    }
    //else no elements were changed
 }
});

3) 对 dom-repeatitems 数组(或任何你命名的数组)进行数组突变以反映 DOM 变化

if (toPaste !== -1) { // meaning its children were indeed rearranged

  // inform Polymer of the change
  var tempPaste = toPaste;
  for (var i = toRearr.length - 1; i >= 0; i--) { // start from end to preserve order

    // we're moving an item to the right of our 'paste' index, so decrease
    // tempPaste by 1 so it stays consistent
    if (tempPaste > toRearr[i]) tempPaste--;

    // move element from old index to new index, using two array splices
    // that essentially remove and reinsert the element in the array
    target.splice('items', tempPaste, 0, target.splice('items', toRearr[i], 1)[0]);
  }
}

希望对遇到类似情况的人有所帮助

所以基本上您是在手动更改模型,以便 Polymer 可以与 jQuery sortable 所做的更改保持同步?检查 this 示例是否相关。不确定它是否适用于 jQuery sortable