2

I have list of 100+ items and rendering takes too much time. I want to show just the once that are visible, and rest on scroll.

What's the best approach?

I have this snippet below, but the vue.set() isn't working.

var dbItems = [{name: 'New item'}, {name:'Another'}, {name:'Third'}];

var app = new Vue({
  el: '#app',
  data: {
    // if I put items : dbItems, then for some reason the Vue.set() doesn't work!!
   items : [],
  },
  methods: {
    init: function () {
      this.items = dbItems; // we add all items
    },
    makeItemVisible : function(id) {
      console.log("Making visible #"+id);
      this.items[id].show = 1;
      Vue.set(this.items, id, this.items[id]);
    }
   }
});

app.init();
app.makeItemVisible(1); // this works

$(document).on('scroll', function(){
  // function to show elements when visible
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>

<div id="app" v-cloak>

<button v-on:click="makeItemVisible(0)">MAKE VISIBLE - This button doesn't work</button>

  <div class="items" v-show="items.length">
    <!-- I dont know why, but (key, item) had to be switched compared to VUE documentation! -->
	  <div v-for="(key, item) in items">
         <div v-if="item.show" style="border:2px solid green;height:700px">
            You can see me: {{ item.name }} | ID: {{ key }}
        </div>
        <div class="item-blank" data-id="{{ key }}" v-else style="border:2px solid red;height:700px">
         {{ item.name }}  invisible {{ key }}
        </div>
		</div>
  </div>

</div>

1
  • 3
    Maybe look at libraries that already do this, for example this one. In general, this functionality is called virtual scrolling. Commented Sep 3, 2017 at 19:10

1 Answer 1

0

Solved.

Edit: This Vue.js is only useable in Chrome... otherwise it is incredibly slow (Firefox is slowest), it works better when loading the whole document in HTML at once.

var dbItems = [{name: 'New item'}, {name:'Another'}, {name:'Third'}];

var app = new Vue({
  el: '#app',
  data: {
   items : dbItems
  },
  methods: {
    makeItemVisible : function(id) {
      console.log("Making visible #"+id);
      Vue.set(this.items[id], 'show', 1);
    }
  }
});

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();
    return (elemTop <= docViewBottom && elemTop >= docViewTop) || (elemBottom >= docViewTop && elemBottom <= docViewBottom);
}

var fn = function(){
  $('.item-blank').each(function(){
    if(isScrolledIntoView(this)) {
      app.makeItemVisible($(this).attr('data-id'));
    }
  });
};
$(window).scroll(fn);
fn(); // because trigger() doesn't work
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>

<div id="app" v-cloak>
  <div class="items" v-show="items.length">
	  <div v-for="(item, index) in items">
         <div v-if="item.show" style="border:2px solid green;height:700px">
            You can see me: {{ item.name }} | ID: {{ index }}
        </div>
        <div class="item-blank" :data-id="index" v-else style="border:2px solid red;height:700px;position:relative;">
         {{ item.name }}  invisible {{ index }}
        </div>
		</div>
  </div>

</div>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.