Ember.js - jQuery-masonry + infinite scroll

2019-05-10 05:53发布

问题:

I'm trying to get infinite scrolling and masonry working in my ember project. The masonry 'bricks' are posts with text and an image. Currently I can get the first page to show on the initial load of the page and apply masonry (I still have to do a setTimeout though, trying to figure out how to get rid of that as well).

I also have the basic infinite scroll code in. For now I'm simply grabbing the second page from the back end. When scrolled to the bottom of the page the second page of posts are loaded. What I'm trying to figure out is how to apply masonry to the new page upon insertion.

Putting $('#masonry-container').masonry('refresh') in didInsertElement doesn't work since the view element is already rendered and I'm simply appending new elements to the existing view.

Is there an event I can put the refresh in?

The code below applies masonry on the initial load and then loads the second page when scrolled to the bottom, but does not currently refresh masonry.

Thanks

Routing:

App.Router.map ->
  @route 'posts', path: '/'

App.PostsRoute = Ember.Route.extend
  model: -> 
    App.Post.find()

    events:
      more: ->
        App.Post.query(page: 2) # hard code for now, next page will come from back end

View:

App.PostsView = Ember.View.extend
layoutName: 'appLayout'
templateName: 'posts'
controller: 'posts'

didInsertElement: ->
  @scheduleMasony()
  $(window).bind('scroll', =>
    @.didScroll()
  )

scheduleMasony: -> 
  Ember.run.schedule('afterRender', @, @applyMasonry)

applyMasonry: ->
  setTimeout(-> 
    $('#masonry-container').masonry(
      itemSelector: '.box',
      columnWidth: 220,
      gutterWidth: 10,
      isFitWidth: true,
      isAnimated: true
    )
  2000)

didScroll: -> 
  if @isScrolledToBottom()
    @get('controller').send('more')

isScrolledToBottom: -> 
  distanceToTop = $(document).height() - $(window).height()
  top = $(document).scrollTop()
  top == distanceToTop

Templates:

app_layout.handlebars

...layout mark up...
<div id="container">
  {{yield}}
</div>
...more layout mark up...

posts.handlebars:

<div id="masonry-container" class="transitions-enabed infinite-scroll clearfix centered">
{{#each controller.content}}
  <div class="col2 box">
    <h3>{{title}}
    <img {{bindAttr src="imageUrl"}} >
    <p class="text">
      {{text}}
    </p>
  </div>
{{/each}}
</div>

application.handlebars

{{outlet}}

回答1:

When scrolled to the bottom of the page the second page of posts are loaded. What I'm trying to figure out is how to apply masonry to the new page upon insertion.

I guess you are better of on observing the controller's content length to re-invoke masonry since the appending to the DOM relates with the number of posts you are showing.

So try something like this:

App.PostsView = Ember.View.extend({
  layoutName: 'appLayout'
  templateName: 'posts'
  controller: 'posts'
  ...
  contentDidChange: function() {
    // check for 'inDOM' just to be sure
    // we don't run this unnecessarily 
    // when the view is not yet rendered
    if(this.get('state') === "inDOM") {
      applyMasonry();
    }
  }.observes('controller.content.length')
  ...
});

Hope it helps.



回答2:

This article shows how to do it. http://coryforsyth.com/2013/07/28/infinite-scrolling-with-ember-js/