<div id="app"> <p class="debug">{{ debug }}</p> <div class="item-container" @scroll="infiniteScroll"> <div v-for="item in items" class="item-card"> <div class="thumbnail"></div> <h3 class="title">{{ item.title }}</h3> </div> <div class="loader"><p>Now loading......</p></div> </div> </div>
body { background-color: white; font-size: 62.5%; padding: 10px; } .item-container { width: 100%; height: 100vh; padding: 0 20px; overflow-y: auto; } .item-card { width: 80%; height: 80px; } .item-card { display: flex; margin-bottom: 20px; > .thumbnail { background-color: #C7E7EF; width: 80px; height: 80px; } > .title { margin-left: 10px; font-size: 2rem; color: #00BADD; } } .loader { width: 100%; height: 50px; text-align: center; position: relative; overflow: hidden; &::after { content: ''; display: block; width: 100%; height: 100%; background-color: white; position: absolute; top: 0; transform: translateX(30%); animation: loading 1.5s infinite; } > p { font-size: 2rem; color: #AAAAAA; } } @keyframes loading { 100% { transform: translateX(70%); } } .debug { position: fixed; top: 0; right: 0; background-color: rgba(170,170,170,.25); z-index: 1; }
// mock function api (page, limit) { const items = [...Array(limit)].map((a, i) => { return { title: `page: ${page}, limit: ${limit}, ${i.toString().repeat(10)}` }; }); return new Promise((resolve, reject) => { setTimeout(() => { resolve(items); }, 2000); }); } const app = new Vue({ el: '#app', data () { return { page: 0, limit: 10, items: [], debug: 'debug' } }, async created () { this.fetch(); }, methods: { async fetch () { const items = await api(this.page, this.limit); this.items.push(...items); this.page++; }, infiniteScroll (event) { this.debug = [ `scrollTop: ${event.target.scrollTop}`, `offsetHeight: ${event.target.offsetHeight}`, `scrollHeight: ${event.target.scrollHeight}`, `content: ${this.items.length}` ].join(' | '); // スクロールの現在位置 + 親(.item-container)の高さ >= スクロール内のコンテンツの高さ if ((event.target.scrollTop + event.target.offsetHeight) >= event.target.scrollHeight) { this.fetch(); } } } })