영화리스트가 있는 프로젝트를 만드는데
한번에 다 받아오기 말고 10개씩 끊어서 받아오고 싶은 것이다.
https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API
1. Observer.vue 만들기
이 컴포넌트는 무한 스크롤을 구현하고 싶은 컴포넌트 맨 하단에 붙여서
이 컴포넌트가 보이면 리스트를 더 불러오는 메소드를 실행하기 위해 만든다.
//Observer.vue
<template>
<div ref="trigger">-</div>
</template>
<script>
import {
defineComponent, onMounted, onUnmounted, ref
} from 'vue';
export default defineComponent({
setup(props, { emit }) {
const trigger = ref();
const options = {
root: null,
threshold: 1
};
let observer = null;
const handleIntersect = (entry) => {
if (entry.isIntersecting) emit('triggerIntersected', trigger.value);
};
onMounted(() => {
try {
observer = new IntersectionObserver((entries) => {
handleIntersect(entries[0]);
}, options);
observer.observe(trigger.value);
} catch (err) {
console.error(err);
}
});
onUnmounted(() => {
observer.value.disconnect();
});
return {
trigger
};
}
});
</script>
코드 위에서 부터
1. 보여주는 div를 trigger이라는 ref로 설정해준다.
2. intersection observer에 넣을 옵션을 설정해준다.
threshold는 해당 컴포넌트가 화면에 얼마나 보였을 때를 감지할 것인지를 말하는 것인데
1은 100%이고 0.1은 10%이다.
3. onMounted에서 observer을 등록한다.
옵저버가 감지되면 handleIntersect이라는 함수를 실행하고
그 함수는 부모로 triggerIntersected 이벤트를 emit으로 보낸다.
4. 그리고 onMounted에서 observer를 연결 해제 시켜준다.
2. 사용하고 싶은 컴포넌트에서 사용
//Main.vue
<template>
<div class="filters">
<Filter
v-for="(genre) in genres"
:key="genre.id"
:genre="genre"
@click="getGenreMovies(genre.id , genre.name)"
></Filter>
</div>
<MovieList :movieList="filteredMoviesByGenre"/>
<Observe @triggerIntersected="loadMore"/>
</template>
나는 Main컴포넌트에서 MovieList가 끝나고 맨 밑에 Observe 컴포넌트를 붙였다.
MovieList가 10개가 다 보이면 Observe 컴포넌트가 보이고
Observe가 보이면 또 영화를 10개 더 가져와서 MovieList에 추가되어 밑으로 밀리는 형태이다.
옵저버가 감지됐을때 실행되는 함수는 loadMore함수이다.
<template>
<div class="filters">
<Filter
v-for="(genre) in genres"
:key="genre.id"
:genre="genre"
@click="getGenreMovies(genre.id , genre.name)"
></Filter>
</div>
<MovieList :movieList="filteredMoviesByGenre"/>
<Observe @triggerIntersected="loadMore"/>
</template>
<script lang="ts">
import ...
export default defineComponent({
...
setup() {
...
const page = ref(1);
const loadMore = async () => {
const fetchData = await getAllMoviesAPI(page.value + 1);
if (fetchData) {
await store.dispatch("movie/setMoreMovies", fetchData);
}
page.value += 1;
};
...
return {
...
loadMore
};
},
});
</script>
<style lang="scss" scoped>
...
</style>
loadMore함수는 page를 1씩 올려서 다음페이지를 가지고 온다.
그리고 store에 저장한다.
3. 결과
'WEB > VUE.js' 카테고리의 다른 글
[VUE.js] vue-draggable-next로 drag and drop 구현 (0) | 2021.11.30 |
---|---|
[VUE.js] vue3 selectbox mutiple dropdown구현하기 (0) | 2021.11.27 |
[VUE.js] vue3 scss media query 전역으로 쓰는 법 (0) | 2021.11.17 |
[Vue.js] computed와 method/ watch 의 차이 (0) | 2021.11.07 |
[Vue.js] 한글 바인딩 시 v-model 대신에 v-on:input 사용 (0) | 2021.11.07 |