javascript - meteor /火焰 : updating list properties with minimal redraw

标签 javascript meteor iron-router meteor-blaze

我遇到了与 Blaze 重画相关的严重性能问题。我知道我的数据结构有问题,但我找不到修复它的方法。这有点长:我会尽力把它讲清楚。

目标/问题
我想创建一个计划 View ,用户可以在其中安排测试。用户应该能够拖放测试槽,但由此产生的重绘速度太慢,以至于无法正常工作。

数据
我有一个 Sittings 集合,其中存储有关测试时间的详细信息。每次考试都有一个 scheduleGroups 列表(即,考试 1 和考试 2 在星期二进行,考试 3 和考试 4 在星期三进行)结构看起来或多或少像这样:

var sitting = {
  "_id" : "sittingId",
  "name" : "Amazing Sitting",
  "locationIds" : [
    "room1_id",
    "room2_id"
  ],
  "startDate" : ISODate("2015-07-01T04:00:00Z"),
  "endDate" : ISODate("2015-07-02T04:00:00Z"),
  "scheduleGroups" : [
    {
        "_id" : "dEb3mC7H8RukAgPG3",
        "name" : "New group",
        "booths" : [
            {
                "boothNumber" : 1,
                "slots" : [
                    {
                        "examId" : "exam1",
                        "dayNumber" : 1,
                        "startTime" : {
                            "hour" : 8,
                            "minutes" : 0
                        },
                        "endTime" : {
                            "hour" : 9,
                            "minutes" : 30
                        },
                        "candidateId" : "odubbD42kHDcR8Egc",
                        "examinerIds" : [
                            "GQmvyXbcmMckeNKmB",
                            "GfoBy4BeQHFYNyowG"
                        ]
                    }
                ]
            }
        ]
        "locationId" : "room1_id"
    }],
  "examIds" : [
      "exam1",
      "exam2",
      "exam3"
  ]

};

HTML
Sitting 在 Router.current().data Hook 中定义为全局上下文。这是重绘问题的一部分。不管怎样,下面的 HTML 会产生下面的布局(下面的图片)。

<template name='scheduler'>
<div class='container'>
    <div class='tabpanel'>
        <div class='tab-content' id='scheduler-content'>
            {{#each getScheduleGroups}}
            <div class='container-fluid schedule-wrapper'>
                <div class='row'>
                    <div class='scheduler-inner-box placeholder-box'></div>
                    {{#each booths}}
                    <div class='group-column-head scheduler-inner-box'>{{boothNumber}}</div>
                    {{/each}}
                </div>
                <!-- Sittings can take place over several days, normally 2 days -->
                {{#each sittingDays}}
                <div class='day-wrapper'>
                    <h3 class='text-center'>Day {{this}}</h3>

                    <!-- This helper returns a list of start times: [June 1 9AM, June 1 915AM....] -->
                    {{#each getScheduleTimes ..}}
                    <div class='row time-row'>
                        <div class='group-row-head scheduler-inner-box'>
                            <span class='box-content'>{{this}}</span>
                        </div>
                        <!-- Loop through each booth, so that each slot has a square for that boot
                            i.e. June 1 9AM has space for booth 1, and booth 2, and booth 3, etc
                         -->
                        {{#each ../../booths}}
                        <!-- Paper starting now tells us if there is a slot scheduled to begin at this time or wher its empty-->
                        <div  class='scheduler-inner-box {{#unless paperStartingNow ../.. ..}}open-booth{{/unless}}'>
                            {{#with paperStartingNow ../.. .. boothNumber}}
                            <!--
                                getSlotStyle calculates height and colour, depending on how long the paper is and whether
                                it's ready to go: i.e. does it have a candidate and the right number of examiners?
                            -->
                                <div  class='paper-tile tile' {{getSlotStyle this ../boothNumber 'paper'}}>
                                    <span class='slot-name'>{{getSlotName}}</span>
                                </div>
                                {{#if slotHasCandidate}}
                                <div class='candidate-tile tile' {{getSlotStyle this ../boothNumber 'candidate'}}>
                                    <span class='slot-name candidate-name'>{{getCandidateDisplay}}</span>
                                </div>
                                {{/if}}
                                    {{#each slotExaminers}}
                                    <div class='examiner-tile tile' {{getSlotStyle .. ../../boothNumber 'examiner' index}}>
                                        <span class='slot-name examiner-name'>{{profile.name}}</span>
                                    </div>
                                    {{/each}}
                            {{/with}}
                        </div>
                        {{/each}}
                    </div>
                    {{/each}}
                </div>
                {{/each}}
            </div>
            {{/each}}
        </div>
    </div>
</div>

Rendered layout

问题 当用户将插槽(紫色图 block )放到空白处,或者将考生或考官拖动到另一个图 block 时,我会更新集合并让 Meteor 重新绘制。然而,整个事情重新绘制,我找不到隔离的方法。

这是移动整个位置、考生、考官和所有内容的代码。

moveSlot: function (originalBoothNumber, originalSlot, dropBoothNumber, newSlot) {
    check( originalBoothNumber, Number );
    check( originalSlot, Object );
    check( dropBoothNumber, Number );
    check( newSlot, Object );

    //pull the old slot
    var originalBooth = _.findWhere( this.booths, {boothNumber: originalBoothNumber} );
    originalBooth.slots = _.without( originalBooth.slots, originalSlot );

    //insert the new one
    var dropBooth = _.findWhere( this.booths, {boothNumber: dropBoothNumber} );
    dropBooth.slots.push( newSlot );

    var modifier = {
        $set: {}
    };

    modifier["$set"]["scheduleGroups." + this.getIndex() + ".booths"] = this.booths;
    return Sittings.update({_id: this.getSitting()._id }, modifier);
},

我需要改变存储 Sitting.booths 的方式吗?如果有人可以推荐一个更好的数据结构来触发插槽的重绘,我'真的很感激。我发现了一种技巧,可以将每个槽放入 session 变量中,但必须有另一种方法。

感谢您的耐心和帮助, 分贝

最佳答案

问题

这是因为您将整套slots存储在booth的一个文档中。一旦您更新插槽,整个文档就会被视为更新。

解决方案

恕我直言,我认为您不需要更改结构,除非您已经构建了一个功能来搜索slotbooth 。您可以通过创建一系列 reactiveVariablereactiveDictionary 来设置它,您的模板应该仅依赖于该 react 变量。每次更新时,请考虑手动或自动在其中两个之间同步。

PS。我没有与此网站建立任何附属关系:https://www.sportsplus.me 。但如果你注册 -> 主页 -> MLB -> 任何比赛 -> 点击加号,你可以看到他们的杰作无限滚动,部分重画。 (打开您的开发控制台并观察元素的变化)。它们所做的事情与您尝试使用最少重画所做的事情完全相同。

关于javascript - meteor /火焰 : updating list properties with minimal redraw,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31396582/

相关文章:

meteor 面包屑

authentication - 将 Google 登录限制为 Meteor 中的 .edu 帐户

javascript - 是否保证 for...of 循环内的异步调用将按顺序返回?

javascript - 如何在网页中集成 AIML 聊天机器人

javascript - HTML5 正确检测语言

ssl - 在 Kubernetes 上使用 Nginx SSL 代理运行 Meteor 应用程序

meteor - 如何想出 Paypal IPN url?

meteor - 如何使用Iron Router返回404

javascript - Spring Maven Angjular JS 问题

javascript - 将一天中的时间保存为 mongodb 中的数字,但以人类格式显示(使用 meteor 自动格式)