我正在使用Dragula在Ember中创建一组拖放组件。我将项目列表传递给包含多个可丢弃存储桶的父包装器。最初过滤此项目列表,以便它们在正确的存储桶中呈现正确的项目。然后将Dragula连接起来,以便可以拖放项目。当发生drop事件时,我尝试更新底层的Ember对象。这可能导致重新应用过滤器并进行一些渲染。问题是DOM已被Dragula操纵,并且与Ember认为它应该是不一样,DOM节点就会消失。
如果Ember和Dragula都认为他们拥有DOM及其当前的代表性,我怎么能让他们玩得很好?我已经尝试取消掉落拖放事件,然后让Ember设置价值的成功有限。
dnd-wrapper/template.hbs
{{yield (action "register")}}
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);
}
}
}
});
dnd-bucket/template.hbs
<h2>bucket {{value}}</h2>
<ul>
{{#each filteredItems as |item|}}
{{dnd-item item=item register=register}}
{{/each}}
</ul>
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'));
})
});
dnd-item/template.hbs
{{item.title}}
dnd-item/component.js
export default Ember.Component.extend({
registerWithWrapper: Ember.on('didInsertElement', function() {
this.register('item', {
component: this,
element: this.$()[0]
});
})
});
在线演示:http://ember-twiddle.com/c086d2853a926c310a23
GitHub演示:https://github.com/RyanHirsch/dragula-ember-example
答案 0 :(得分:2)
我遇到了你正在描述的完全相同的问题。我花了好几个小时尝试不同的东西来解决它,我想我终于想出了一个hacky但可行的解决方案。它的核心是我不得不强迫“来源”。在触发掉落事件后重新渲染其物品。
不幸的是,我不得不使用蛮力来重新渲染工作,在任何父视图上调用rerender都不起作用。 Ember认为从DOM中消失的项目仍然存在并且正确呈现。
我最终使用{{#if listVisible}}{{/if}}
将dbI-bucket模板中的filteredItems列表包装起来。如果然后设置itemsVisible false和true,它会强制列表重新渲染并修复DOM损坏。我还必须确保这些集合在runloop中渲染之前和之后。
resetView: function() {
Ember.run.scheduleOnce('render', this, () => {
this.set("listVisible", false);
});
Ember.run.scheduleOnce('afterRender', this, () => {
this.set("listVisible", true);
});
}
在我的情况下,我在更新drop回调中的模型后触发了resetView。虽然这个修复很麻烦,但视觉效果是可以接受的。如果DOM元素确实消失了,它们就会被替换掉,这有点不和谐。但是,99.9%的时间没有丢失DOM元素,根本没有视觉故障。