Mitigating a flickering UI when refreshing content

2019-08-04 08:19发布

The problem

I have a view which displays a list of workers. This view has a button which calls a controller method named refresh. Originally I was setting the content to this list, but noticed that the UI would flicker, which would be especially annoying once this is run on a timer.

I managed to make everything work without flickering using the following:

App.WorkersIndexController = Ember.ArrayController.extend
    refresh: ->
        console.log 'refreshing workers'
        # set a property to a new collection
        @set 'refreshing', App.Worker.find()

    # observer that watches the new collection load
    update: (->
        refreshing = @get 'refreshing'
        return unless refreshing.get('isLoaded')
        # what this question is about...
        Ember.run =>
            @set 'content', refreshing
    ).observes('refreshing.isLoaded')

As you can see I'm setting the refreshed content to a temporary variable, and observing the loading of the content and then updating the content. The content flickered less until I added a call to Ember.run which removed the flicker entirely.

I understand why the flicker is occurring, and I understand why Ember.run makes it go away but my question is what is the best way to solve this without resorting to Ember.run? I feel like calling Ember.run is kind of a last resort... Any help would be greatly appreciated!

Edit: Also I'm not using ember data. The find method looks like this:

App.Worker.reopenClass
    find: ->
        console.log 'loading workers'
        workers = Em.A []
        request = $.getJSON '/api/admin/workers', (data) =>
            console.log ' -> loaded workers'
            data.forEach (d) =>
                worker = App.Worker.create(d)
                worker.set 'isLoaded', true
                workers.pushObject(worker)
        request.error =>
            console.log ' -> failed to load workers'
            workers.set 'isFailed', true
        request.complete =>
            workers.set 'isLoaded', true
        workers

1条回答
趁早两清
2楼-- · 2019-08-04 09:02

I have avoided flicker in similar situations by having a fixed list who's objects I just change.

In the simplest case, lets' say you were displaying names, and knew that you knew you'd never have more than 3 elements you could make

App.names = [ 
    Ember.Object.create({name:"", active:false}),
    Ember.Object.create({name:"", active:false}),
    Ember.Object.create({name:"", active:false})
]

and have your template be

{{#each App.names}}
    {{#if active}}
        <li> {{name}} </li>
    {{/if}}
{{/each}}

you could then add names by running

  App.names[0].set("name", "Frank");
  App.names[0].set("active", true);

and update the list without any flicker. Only a single element in the list is changed at a time, so you don't have the flicker from the whole list being redrawn.

In practical terms you might need App.names to be an ArrayController so that you can handle expanding the list gracefully, but the gist of that will work.

查看更多
登录 后发表回答