반응형
Vue.js에서 infinite scroll 구현하기
Vue.js에서 무한스크롤(infinite scroll)을 구현하는 방법에 대한 포스팅입니다.
chrome extension을 만들던 도중에 여러 글 목록을 나열해야될 일이 있어
pagination과 infinite scroll중에 어떤 걸 사용할까 고민하던 중
작은 화면에는 infinite scroll이 더 어울린다고 생각하여서 이걸로 진행하게 되었습니다.
vue-infinite-loading
intersection observer 객체를 사용해 구현하는 방법도 있지만 이미 만들어져있는 플러그인인 vue-infinite-loading을 사용하면 더 빠르게 구현할 수 있습니다.
https://www.npmjs.com/package/vue-infinite-loading
설치
npm으로 설치해주었습니다.
npm install vue-infinite-loading -S
예제
가이드에 나와있는 Hacker News 예제 입니다.
infinite-loading 컴포넌트를 삽입해주고 @infinite에 대한 핸들러를 작성해줍니다.
<header>
<!-- Hacker News header -->
</header>
<div v-for="(item, $index) in list" :key="$index">
<!-- Hacker News item loop -->
</div>
<infinite-loading @infinite="infiniteHandler"></infinite-loading>
import axios from 'axios';
const api = '//hn.algolia.com/api/v1/search_by_date?tags=story';
export default {
data() {
return {
page: 1,
list: [],
};
},
methods: {
infiniteHandler($state) {
axios.get(api, {
params: {
page: this.page,
},
}).then(({ data }) => {
if (data.hits.length) {
this.page += 1;
this.list.push(...data.hits);
$state.loaded();
} else {
$state.complete();
}
});
},
},
};
적용
위 예제를 프로젝트에 적용해보았습니다.
똑같이 컴포넌트를 삽입해주었고 핸들러를 async-await 문법으로 작성해주었습니다.
<template>
<div>
<v-list two-line height="470" style="overflow: scroll">
<v-list-item-group active-class="pink--text">
<template v-for="(item, index) in items">
<v-list-item :key="item.subject">
<v-list-item-content @click.stop="showContent(index)">
<v-list-item-title v-text="item.subject"></v-list-item-title>
<v-list-item-subtitle
class="text--primary"
v-text="item.auther"
></v-list-item-subtitle>
<v-list-item-subtitle
v-text="`조회 ${item.hits}`"
></v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-list-item-action-text
v-text="item.date"
></v-list-item-action-text>
</v-list-item-action>
</v-list-item>
<v-divider v-if="index < items.length - 1" :key="index"></v-divider>
</template>
<infinite-loading @infinite="infiniteHandler"></infinite-loading>
</v-list-item-group>
</v-list>
<!-- 다이얼로그 -->
<v-dialog v-model="dialog" max-width="500">
<v-card>
<v-card-title class="headline">
{{ contents.subject }}
</v-card-title>
<v-card-text v-html="contents.content"></v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="error" text @click="dialog = false"> 닫기 </v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
import InfiniteLoading from "vue-infinite-loading";
import { daelimNotice } from "@/api/daelim.js";
export default {
components: {
InfiniteLoading,
},
data() {
return {
dialog: false,
page: 0,
items: [],
contents: {
subject: "",
content: "",
},
};
},
methods: {
showContent(idx) {
this.dialog = true;
this.contents.subject = this.items[idx].subject;
this.contents.content = this.items[idx].contents;
},
async infiniteHandler($state) {
try {
const { data } = await daelimNotice(this.page);
if (data.data.list) {
await setTimeout(() => {
this.page += 1;
for (const bulletin of data.data.list) {
const data = {
subject: bulletin.SUBJECT,
auther: bulletin.WRITER_NM,
hits: bulletin.HITS,
date: bulletin.WRITE_DATE,
contents: bulletin.CONTENTS,
};
this.items.push(data);
}
$state.loaded();
}, 1000);
} else {
$state.complete();
}
} catch (error) {
console.log(error);
}
},
},
};
</script>
반응형
'Framwork > Vue.js' 카테고리의 다른 글
Nuxt.js 에 폰트 적용 방법 (0) | 2021.08.14 |
---|---|
확장 프로그램 vue로 만들기 - 프로젝트 세팅하기 (0) | 2021.03.25 |