|
|
@@ -0,0 +1,217 @@
|
|
|
+<template>
|
|
|
+ <div class="pagination-wrapper">
|
|
|
+ <div class="pagination">
|
|
|
+ <span class="pagination__arrow icon" @click="handleChange({ page: page - 1 })">
|
|
|
+ <eva-icon-arrow-ios-back-outline />
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ :class="{ 'pagination__page': true, '--active': page === 1 }"
|
|
|
+ @click="handleChange({ page: 1 })"
|
|
|
+ >1</span>
|
|
|
+ <span
|
|
|
+ v-if="hasLeftDot"
|
|
|
+ class="pagination__hidden-arrow"
|
|
|
+ @click="handleChange({ page: page - SHOW_PAGE_NUM })"
|
|
|
+ >
|
|
|
+ <span class="icon">
|
|
|
+ <eva-icon-arrowhead-left-outline />
|
|
|
+ </span>
|
|
|
+ <span class="pagination__hidden-ellipsis">•••</span>
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ v-for="item in centerPages"
|
|
|
+ :key="item"
|
|
|
+ :class="{ 'pagination__page': true, '--active': page === item }"
|
|
|
+ @click="handleChange({ page: item })"
|
|
|
+ >{{ item }}</span>
|
|
|
+ <span
|
|
|
+ v-if="hasRightDot"
|
|
|
+ class="pagination__hidden-arrow --right"
|
|
|
+ @click="handleChange({ page: page + SHOW_PAGE_NUM })"
|
|
|
+ >
|
|
|
+ <span class="icon">
|
|
|
+ <eva-icon-arrowhead-left-outline />
|
|
|
+ </span>
|
|
|
+ <span class="pagination__hidden-ellipsis">•••</span>
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ v-if="totalPage > 1"
|
|
|
+ :class="{ 'pagination__page': true, '--active': page === totalPage }"
|
|
|
+ @click="handleChange({ page: totalPage })"
|
|
|
+ >{{ totalPage }}</span>
|
|
|
+ <span
|
|
|
+ class="pagination__arrow --right icon"
|
|
|
+ @click="handleChange({ page: page + 1 })"
|
|
|
+ >
|
|
|
+ <eva-icon-arrow-ios-back-outline />
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="pagination-input">
|
|
|
+ <c-input
|
|
|
+ v-model="inputPage"
|
|
|
+ class="search-input"
|
|
|
+ style="width: 50px; margin-right: 5px"
|
|
|
+ @keypress="handlePageInputEvent"
|
|
|
+ />
|
|
|
+ <span>of {{ totalPage }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import iconMap from '@/utils/icon-map'
|
|
|
+import CInput from '@/components/CInput'
|
|
|
+import EvaIconArrowIosBackOutline from '@/components/EvaIcon/EvaIconArrowIosBackOutline'
|
|
|
+import EvaIconArrowheadLeftOutline from '@/components/EvaIcon/EvaIconArrowheadLeftOutline'
|
|
|
+
|
|
|
+const SHOW_PAGE_NUM = 3
|
|
|
+
|
|
|
+export default {
|
|
|
+ components: { EvaIconArrowheadLeftOutline, EvaIconArrowIosBackOutline, CInput },
|
|
|
+ props: {
|
|
|
+ page: {
|
|
|
+ default: 1,
|
|
|
+ type: Number
|
|
|
+ },
|
|
|
+ size: {
|
|
|
+ type: Number,
|
|
|
+ default: 0
|
|
|
+ },
|
|
|
+ totalElements: {
|
|
|
+ type: Number,
|
|
|
+ default: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ inputPage: String(this.page),
|
|
|
+ iconMap,
|
|
|
+ SHOW_PAGE_NUM
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ totalPage() {
|
|
|
+ return Math.ceil(this.totalElements / this.size)
|
|
|
+ },
|
|
|
+ hasLeftDot() {
|
|
|
+ return this.page >= SHOW_PAGE_NUM && this.totalPage >= SHOW_PAGE_NUM + 2
|
|
|
+ },
|
|
|
+ hasRightDot() {
|
|
|
+ return (
|
|
|
+ this.page <= this.totalPage - (SHOW_PAGE_NUM - 1) &&
|
|
|
+ this.totalPage >= SHOW_PAGE_NUM + 2
|
|
|
+ )
|
|
|
+ },
|
|
|
+ centerPages() {
|
|
|
+ const theCenter =
|
|
|
+ this.page < ((SHOW_PAGE_NUM + 1) / 2)
|
|
|
+ ? ((SHOW_PAGE_NUM + 1) / 2)
|
|
|
+ : this.page > this.totalPage - 2
|
|
|
+ ? this.totalPage - 2
|
|
|
+ : this.page
|
|
|
+
|
|
|
+ return Array(SHOW_PAGE_NUM)
|
|
|
+ .fill(0)
|
|
|
+ .map((_, index) => theCenter + (index - Math.floor(SHOW_PAGE_NUM / 2)))
|
|
|
+ .filter(item => item > 1 && item < this.totalPage)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleChange({ page = this.page, size = this.size }) {
|
|
|
+ const thePage =
|
|
|
+ page < 1 ? 1 : page > this.totalPage ? this.totalPage : page
|
|
|
+ this.$emit('change', { page: thePage, size })
|
|
|
+ },
|
|
|
+ handlePageInputEvent(event) {
|
|
|
+ if (event.key === 'Enter') {
|
|
|
+ event.preventDefault()
|
|
|
+ this.handleChange({ page: this.inputPage })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+@import "~@/style/theme.scss";
|
|
|
+
|
|
|
+$pagination-font-color: inherit;
|
|
|
+$pagination-font-color--hover: inherit;
|
|
|
+$pagination-page-background--hover: $theme-blue-transparent;
|
|
|
+$pagination-page-background--active: $theme-blue;
|
|
|
+
|
|
|
+.icon{
|
|
|
+ font-family: 'iconfont', sans-serif;
|
|
|
+}
|
|
|
+
|
|
|
+.pagination-wrapper {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: $pagination-font-color;
|
|
|
+}
|
|
|
+
|
|
|
+.pagination-input{
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.pagination {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ &__arrow,
|
|
|
+ &__page,
|
|
|
+ &__hidden-arrow {
|
|
|
+ line-height: 1em;
|
|
|
+ display: block;
|
|
|
+ transition: background-color 0.3s;
|
|
|
+ padding: 8px 10px;
|
|
|
+ margin: 0 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 2px;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: $pagination-font-color--hover;
|
|
|
+ background: $pagination-page-background--hover;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &__page.--active {
|
|
|
+ color: white;
|
|
|
+ background-color: $pagination-page-background--active;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__arrow {
|
|
|
+ &.--right {
|
|
|
+ transform: rotate(180deg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &__hidden-arrow {
|
|
|
+ position: relative;
|
|
|
+ .icon {
|
|
|
+ position: absolute;
|
|
|
+ left: 50%;
|
|
|
+ top: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ opacity: 0;
|
|
|
+ }
|
|
|
+ &:hover {
|
|
|
+ .icon {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ .pagination__hidden-ellipsis {
|
|
|
+ opacity: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &.--right {
|
|
|
+ .icon {
|
|
|
+ transform: translate(-50%, -50%) rotate(180deg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|