UNPKG

element-plus

Version:

A Component Library for Vue3.0

314 lines (269 loc) 7.38 kB
import { defineComponent, h, ref, computed, watch, nextTick, provide, } from 'vue' import { IPagination } from './pagination' import Prev from './prev.vue' import Next from './next.vue' import Sizes from './sizes.vue' import Jumper from './jumper.vue' import Total from './total.vue' import Pager from './pager.vue' const getValidPageSize = (val: number) => Number.isNaN(val) ? 10 : val export default defineComponent({ name: 'ElPagination', components: { Prev, Next, Sizes, Jumper, Total, Pager, }, props: { pageSize: { type: Number, default: 10, }, small: Boolean, total: { type: Number, }, pageCount: { type: Number, }, pagerCount: { type: Number, validator: (value: number) => { return ( (value | 0) === value && value > 4 && value < 22 && value % 2 === 1 ) }, default: 7, }, currentPage: { type: Number, default: 1, }, layout: { type: String, default: 'prev, pager, next, jumper, ->, total', }, pageSizes: { type: Array, default: () => { return [10, 20, 30, 40, 50, 100] }, }, popperClass: { type: String, default: '', }, prevText: { type: String, default: '', }, nextText: { type: String, default: '', }, background: Boolean, disabled: Boolean, hideOnSinglePage: Boolean, }, emits: [ 'size-change', 'current-change', 'prev-click', 'next-click', 'update:currentPage', 'update:pageSize', ], setup(props, { emit }) { const lastEmittedPage = ref(-1) const userChangePageSize = ref(false) const internalPageSize = ref(getValidPageSize(props.pageSize)) const internalPageCount = computed<Nullable<number>>(() => { if (typeof props.total === 'number') { return Math.max(1, Math.ceil(props.total / internalPageSize.value)) } else if (typeof props.pageCount === 'number') { return Math.max(1, props.pageCount) } return null }) const internalCurrentPage = ref(getValidCurrentPage(props.currentPage)) function emitChange() { nextTick(() => { if ( internalCurrentPage.value !== lastEmittedPage.value || userChangePageSize.value ) { lastEmittedPage.value = internalCurrentPage.value userChangePageSize.value = false } }) } function handleCurrentChange(val: number) { internalCurrentPage.value = getValidCurrentPage(val) userChangePageSize.value = true } function handleSizesChange(val: number) { userChangePageSize.value = true internalPageSize.value = val emit('update:pageSize', val) emit('size-change', val) } function prev() { if (props.disabled) return const newVal = internalCurrentPage.value - 1 internalCurrentPage.value = getValidCurrentPage(newVal) emit('prev-click', internalCurrentPage) emitChange() } function next() { if (props.disabled) return const newVal = internalCurrentPage.value + 1 internalCurrentPage.value = getValidCurrentPage(newVal) emit('next-click', internalCurrentPage.value) emitChange() } function getValidCurrentPage(value: number | string) { if (typeof value === 'string') { value = parseInt(value, 10) } let resetValue: number | undefined const havePageCount = typeof internalPageCount.value === 'number' if (!havePageCount) { if (isNaN(value) || value < 1) resetValue = 1 } else { if (value < 1) { resetValue = 1 } else if (value > internalPageCount.value) { resetValue = internalPageCount.value } } if (resetValue === undefined && isNaN(value)) { resetValue = 1 } else if (resetValue === 0) { resetValue = 1 } return resetValue === undefined ? value : resetValue } watch(() => getValidCurrentPage(props.currentPage), val => { internalCurrentPage.value = val }) watch(() => props.pageSize, val => { internalPageSize.value = getValidPageSize(val) }) watch(internalCurrentPage, val => { emit('update:currentPage', val) emit('current-change', val) }) watch( () => internalPageCount.value, val => { const oldPage = internalCurrentPage.value if (val > 0 && oldPage === 0) { internalCurrentPage.value = 1 } else if (oldPage > val) { internalCurrentPage.value = val === 0 ? 1 : val userChangePageSize.value && emitChange() } userChangePageSize.value = false }, ) provide<IPagination>('pagination', { pageCount: computed(() => props.pageCount), disabled: computed(() => props.disabled), currentPage: computed(() => internalCurrentPage.value), changeEvent: handleCurrentChange, handleSizesChange, }) return { internalCurrentPage, internalPageSize, lastEmittedPage, userChangePageSize, internalPageCount, getValidCurrentPage, emitChange, handleCurrentChange, prev, next, } }, render() { const layout = this.layout if (!layout) return null if ( this.hideOnSinglePage && (!this.internalPageCount || this.internalPageCount === 1) ) return null const rootNode = h('div', { class: [ 'el-pagination', { 'is-background': this.background, 'el-pagination--small': this.small, }, ], }) const rootChildren = [] const rightWrapperRoot = h('div', { class: 'el-pagination__rightwrapper' }) const rightWrapperChildren = [] const TEMPLATE_MAP = { prev: h(Prev, { disabled: this.disabled, currentPage: this.internalCurrentPage, prevText: this.prevText, onClick: this.prev, }), jumper: h(Jumper), pager: h(Pager, { currentPage: this.internalCurrentPage, pageCount: this.internalPageCount, pagerCount: this.pagerCount, onChange: this.handleCurrentChange, disabled: this.disabled, }), next: h(Next, { disabled: this.disabled, currentPage: this.internalCurrentPage, pageCount: this.internalPageCount, nextText: this.nextText, onClick: this.next, }), sizes: h(Sizes, { pageSize: this.pageSize, pageSizes: this.pageSizes, popperClass: this.popperClass, disabled: this.disabled, }), slot: this.$slots?.default?.() ?? null, total: h(Total, { total: this.total }), } const components = layout.split(',').map((item: string) => item.trim()) let haveRightWrapper = false components.forEach((c: keyof typeof TEMPLATE_MAP | '->') => { if (c === '->') { haveRightWrapper = true return } if (!haveRightWrapper) { rootChildren.push(TEMPLATE_MAP[c]) } else { rightWrapperChildren.push(TEMPLATE_MAP[c]) } }) if (haveRightWrapper) { rootChildren.unshift(rightWrapperRoot) } return h(rootNode, {}, rootChildren) }, })