微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用SortableJS对元素进行排序时,防止Mithril创建的重复项

如何解决使用SortableJS对元素进行排序时,防止Mithril创建的重复项

我正在制作dahboard创建者工具。仪表板是一组行,每行都有一个框。所以我试图列出项目清单。项目可以在列表之间移动。列表可以在彼此之间排序。 一切都保存在一个对象中,可以轻松地以JSON格式导出。很好。

_________          ______________
| A  B  |   move   | A  B  C  C |  
|-------|   C up   |------------|   
| C     |   ===>   |            |  
|_______|          |____________|

如果我将框C移到第一行并调用重画,则C框将复制自身。一个C是第二行的原始框,第二个C框是由mithril根据模型创建的。

关键是我只想在行之间移动框,而不要复制它。

我尝试过使用onbeforeupdate和m.redraw(),但这不是解决方案,因为我需要工作重绘周期。

class Grid {

    private BoxMap = new Map<TDashboardBox,IEditor>();

    constructor(
        public readonly dashboard: DashboardDAO,private readonly editorFactory: IBoxFactory
    ) {
        for (const row of dashboard.dashboard.config) {
            for (const Box of row) {
                this.BoxMap.set(Box,editorFactory.create(Box.title,Box))
            }
        }
    }

    public BoxView(Box: TDashboardBox): Vnode {
        return m(this.BoxMap.get(Box) || null);
    }

    public rowView(row: TDashboardRow): Vnode[] {
        return row.map(b => m('.Box',{},this.BoxView(b)));
    }

    public view(): Vnode {
        return m('.Grid',this.dashboard.dashboard.config.map(r => m('.Row',this.rowView(r)))
        );
    }

    public oncreate(vnode: VnodeDOM): void {
        Sortable.create(<HTMLElement>vnode.dom,{
            group: "rows",animation: 150,onEnd: (e: SortableEvent) => {
                this.dashboard.swapRows(e.oldindex,e.newIndex);
            },});

        const rows = vnode.dom.getElementsByClassName('Row');
        for (let i = 0; i < rows.length; i++)
        {
            const row = <HTMLElement>rows[i];
            Sortable.create(row,{
                group: "Boxes",onEnd: (e: SortableEvent) => {
                    const children = e.from.parentElement.childNodes;
                    // Search row indexes of "from row" and "to row"
                    let fromIndex,targetIndex;
                    for (let j = 0; j < children.length; j++) {
                        if (children[j] === e.from) {
                            fromIndex = j;
                        }
                        if (children[j] === e.to) {
                            targetIndex = j;
                        }
                        if (fromIndex !== undefined && targetIndex !== undefined) {
                            break;
                        }
                    }
                    this.dashboard.moveBox(fromIndex,e.oldDraggableIndex,targetIndex,e.newDraggableIndex);

                    m.redraw();
                },});
        }
    }
}

编辑1

可以在onEnd()回调中删除复制的框。它解决了复制问题。

如果我在一行上交换框,它们将在模型中交换。但是在重画后在屏幕上将它们换回了。

编辑2

我找到了解决方案。快到了。

// End of onEnd() event
// if Boxes moved,then...
m.render(vnode.dom,m(this)); // redraw Grid scratch

我只是扔掉了Grid的整个html,然后让秘银重建它。

但是现在在Grid中只是HTML,没有事件,没有重绘周期。

解决方法

好,我知道了。 它不是“同类最佳”的解决方案,但效果很好。

我创建从其父组件传递给Grid组件的回调函数。移动盒子后,该回调函数只会破坏Grid并创建一个新的。

父组件

public recreateGrid(): void {
    this.grid = new Grid(
        this.editor.currentDashboard,this.factory,() => this.recreateGrid()
    )
}
...

public view(): Vnode { // example of view method 
     return m('.Layout.selected-dashboard',{},[
         ... // some other components
         m(this.grid),]);
}

网格构造器

constructor(
    public readonly dashboard: DashboardDAO,// model
    private readonly editorFactory: IBoxFactory,// boxes factory
    private readonly onBoxMoved: ()=>void,// callback       <--
    ) { ... }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。