본문 바로가기
개발/script&vue&react

vue3 스크롤 페이지네이션

by 밤즈라라2 2024. 12. 29.
728x90
반응형

<
template>
  <div class="pagination">
    스크롤 페이지네이션
    <li v-for="item in dataList" :key="item.id">{{ item }}</li>
  </div>
</template>

<script>
import { onMounted, reactive } from 'vue';
import { paging } from '@/composables/paging';
import { useStore } from 'vuex';

export default {
  setup() {

    // page 10개씩 api 찌를 수 있는 상황일시,
    // pageNumb 0 ~ 숫자 올라감.

    const pageNationData = [{
      id: 0,
      data: '제목1',
      contents: '내용',
    }, {
      id: 1,
      data: '제목2',
      contents: '내용',
    },{
      id: 2,
      data: '제목3',
      contents: '내용',
    },{
      id: 3,
      data: '제목4',
      contents: '내용',
    }
    ,{
      id: 4,
      data: '제목5',
      contents: '내용',
    }
    ,{
      id: 5,
      data: '제목6',
      contents: '내용',
    }
    ,{
      id: 6,
      data: '제목7',
      contents: '내용',
    }
    ,{
      id: 7,
      data: '제목8',
      contents: '내용',
    }
    ,{
      id: 8,
      data: '제목9',
      contents: '내용',
    }
    ,{
      id: 9,
      data: '제목10',
      contents: '내용',
    }]

     const pageNationData2 = [
    {
      id: 10,
      data: '제목11',
      contents: '내용',
    },
    {
      id: 11,
      data: '제목12',
      contents: '내용',
    },
    {
      id: 12,
      data: '제목13',
      contents: '내용',
    }
  ]


    const total = 13;
    const store = useStore();
    const tabMenuStatus = store.state.tabMenuStatus;
    let pageNo = reactive(0);
    let pageSize = reactive(10);
    let dataList = reactive([]);
    // 스크롤
    const moreSearch = () => {
      pageNo = pageNo + 1;
      if (pageNo > 0) {
        tabMenuStatus.moreSearchYn = true;
        test();
      }
      console.log(pageNo, 'pageNo');
    };

    const { handleScroll } = paging(moreSearch);

    const test = () => {
       console.log(pageNationData.length);

      if (pageNo == 0) {
        for(let i = 0; i < pageSize; i ++) {
          dataList.push(pageNationData[i]);
        }
        // pageNo 0보다 크고 총 개수 범위에만 걸리게.
      } else if (pageNo > 0 && dataList.length < total + 1) {
        for(let i = 0; i < pageNationData2.length; i ++) {
          dataList.push(pageNationData2[i]);
        }
         tabMenuStatus.moreSearchYn = false;
         return;
      } else {
        tabMenuStatus.moreSearchYn = false;
        return;
      }
    }

    try {
      document.querySelector('.pagination').removeEventListener('scroll', handleScroll);

      // eslint-disable-next-line no-empty
    } catch (ignore) {}

    onMounted(()=>{
      test();
      document.querySelector('.pagination').addEventListener('scroll', handleScroll);
     
    })

    return {total, pageNationData, pageNationData2, tabMenuStatus, pageNo, pageSize, handleScroll, dataList }
  }
}
</script>
<style scoped>
.pagination {    
  height: 75px;
  overflow: auto;

}
</style>

 

 

폴더 구조 

 

 

src> composables > paging.js

import { useStore } from 'vuex';
export const paging = callback => {
    const store = useStore();
    const handleScroll = event => {
        let scrollTop = Math.ceil(event.target.scrollTop);
        let innerHeight = Math.ceil(event.target.clientHeight);
        let scrollHeight = Math.ceil(event.target.scrollHeight);

        if (scrollTop + innerHeight >= scrollHeight && store.state.tabMenuStatus.moreSearchYn) {
            store.state.tabMenuStatus.moreSearchYn = false;
            callback();
        }
    };

    return {
        handleScroll,
    };
};

 

src > store > index.js

/*****************************************************************************
 * PROJECT NAME   : SKT 모바일지갑
 * SUBSYSTEM NAME : 모바일지갑 웹뷰
 * FILE NAME      : index.js
 * DESCRIPTION    : VUEX 스토어 파일
 *
 * VERSION NO     author           date        content  -> info
 * ----------------------------------------------------------------------------
 *    1.0       InJae Yeo      2021-09-27      init
 *****************************************************************************/

import { createStore } from 'vuex';
const files = require.context('@/store/modules/', true, /\.js$/);

const modules = {};
files.keys().forEach(key => {
    if (key === './index.js') return;
    modules[
        key
            .replace(/^.*[\\/]/, '') // filename only
            .replace(/(\.\/|\.js)/g, '') // .js only
            .replace(/(-)/g, '_') // change - to _
    ] = files(key).default;
});


export default createStore({
    state() {
        return {
        };
    },
    mutations: {
    },

    actions: {},

    modules: {
        ...modules,
    },
});

 

src > store > modules > tabMenuStatus.js

const state = {
    moreSearchYn: true,
};

export default {
    state,
};

 

 

 
728x90
반응형

'개발 > script&vue&react' 카테고리의 다른 글

null vs undefined 차이  (0) 2024.12.31
데이터 타입의 종류  (0) 2024.12.30
[vue.js] v-if, v-show 차이점, 사용해야 할 타이밍  (0) 2024.12.28