解决Ember和Dragula对DOM的看法

Rya*_*sch 9 jquery dom ember.js dragula

我正在使用Dragula在Ember中创建一组拖放组件.我将项目列表传递给包含多个可丢弃存储桶的父包装器.最初过滤此项目列表,以便它们在正确的存储桶中呈现正确的项目.然后将Dragula连接起来,以便可以拖放项目.当发生drop事件时,我尝试更新底层的Ember对象.这可能导致重新应用过滤器并进行一些渲染.问题是DOM已被Dragula操纵,并且与Ember认为它应该是不同的并且DOM节点刚刚消失.

当他们认为自己拥有DOM及其当前代表时,我怎么能让Ember和Dragula玩得很好?我已经尝试取消了draggle drop事件,然后让Ember设置了有限的成功值.

dnd-wrapper/template.hbs

{{yield (action "register")}}
Run Code Online (Sandbox Code Playgroud)

dnd-wrapper/component.js

export default Ember.Component.extend({
  drake: null,
  buckets: [],
  items: [],
    initDragula: Ember.on('willInsertElement', function() {
    this.set('drake', window.dragula());
  }),
  setupDragulaEvents: Ember.on('didInsertElement', function() {
    this.get('drake').on('drop', (itemEl, destinationEl, sourceEl) => {
      let dest = this.buckets.findBy('element', destinationEl);
      let source = this.buckets.findBy('element', sourceEl);
      let item = this.items.findBy('element', itemEl);

      item.component.set('item.bucket', dest.component.get('value'));
    });
  }),
  actions: {
    register(type, obj) {
      if(type === 'bucket') {
        this.get('drake').containers.push(obj.element);
        this.buckets.pushObject(obj);
      }
      else {
        this.items.pushObject(obj);
      }
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

dnd-bucket/template.hbs

<h2>bucket {{value}}</h2>
<ul>
    {{#each filteredItems as |item|}}
    {{dnd-item item=item register=register}}
  {{/each}}
</ul>
Run Code Online (Sandbox Code Playgroud)

dnd-bucket/component.js

export default Ember.Component.extend({
  items: null,
  registerWithWrapper: Ember.on('didInsertElement', function() {
    this.register('bucket', {
      component: this,
      element: this.$('ul')[0]
    });
  }),
  filteredItems: Ember.computed('items.@each.bucket', function() {
    return this.get('items').filterBy('bucket', this.get('value'));
  })
});
Run Code Online (Sandbox Code Playgroud)

dnd-item/template.hbs

{{item.title}}
Run Code Online (Sandbox Code Playgroud)

dnd-item/component.js

export default Ember.Component.extend({
  registerWithWrapper: Ember.on('didInsertElement', function() {
    this.register('item', {
      component: this,
      element: this.$()[0]
    });
  })
});
Run Code Online (Sandbox Code Playgroud)

在线演示:http://ember-twiddle.com/c086d2853a926c310a23

GitHub演示:https://github.com/RyanHirsch/dragula-ember-example

小智 2

我遇到了你所描述的完全相同的问题。我花了几个小时尝试不同的方法来解决这个问题,我想我终于想出了一个虽然简单但可行的解决方案。其核心是我必须在触发 drop 事件后强制“源”存储桶重新渲染其项目。

不幸的是,我必须使用蛮力才能使重新渲染正常工作,在任何父视图上调用重新渲染都不起作用。Ember 认为从 DOM 中消失的项目仍然存在并且正确呈现。

我最终在 dnd-bucket 模板中使用{{#if listVisible}}{{/if}}. 如果您随后将 itemsVisible 设置为 false 和 true,它会强制列表重新渲染并修复 DOM 损坏。我还必须确保这些集合在运行循环中渲染之前和之后。

resetView: function() {
  Ember.run.scheduleOnce('render', this, () => {
    this.set("listVisible", false);
  });
  Ember.run.scheduleOnce('afterRender', this, () => {
    this.set("listVisible", true);
  });
}
Run Code Online (Sandbox Code Playgroud)

就我而言,我在更新 drop 回调中的模型后触发了 ResetView。虽然这个修复很hacky,但视觉结果是可以接受的。如果 DOM 元素确实消失了,它们就会被替换,这有点不和谐。但在 99.9% 的情况下,当没有 DOM 元素丢失时,根本不存在视觉问题。