refactor(components): refactor pagination (#3526)

* refactor(components): refactor pagination

* fix: tests

* fix: emits

* refactor: improve props
This commit is contained in:
三咲智子
2021-09-22 01:19:04 +08:00
committed by GitHub
parent bb5ec2c487
commit 6256189100
15 changed files with 474 additions and 487 deletions

View File

@@ -1,6 +1,6 @@
import { nextTick, ref, h } from 'vue'
import { mount } from '@vue/test-utils'
import Pagination from '../src/index'
import Pagination from '../src/pagination'
import type { VueWrapper } from '@vue/test-utils'
const assertElementsExistence = (

View File

@@ -1,15 +1,8 @@
import Pagination from './src'
import { withInstall } from '@element-plus/utils/with-install'
import type { App } from 'vue'
import type { SFCWithInstall } from '@element-plus/utils/types'
import Pagination from './src/pagination'
const _Pagination = Pagination as SFCWithInstall<typeof Pagination>
_Pagination.install = (app: App) => {
app.component(_Pagination.name, _Pagination)
}
export default _Pagination
export const ElPagination = _Pagination
export const ElPagination = withInstall(Pagination)
export default ElPagination
export * from './src/pagination'

View File

@@ -20,37 +20,37 @@
import { computed, defineComponent, ref } from 'vue'
import { useLocaleInject } from '@element-plus/hooks'
import ElInput from '@element-plus/components/input'
import { usePagination } from './usePagination'
import type { Nullable } from '@element-plus/utils/types'
import { usePagination } from '../usePagination'
export default defineComponent({
name: 'ElPaginationJumper',
components: {
ElInput,
},
setup() {
const { t } = useLocaleInject()
const { pagination, pageCount, disabled, currentPage } = usePagination()
const userInput = ref<Nullable<number>>(null)
const innerValue = computed(() => userInput.value ?? currentPage.value)
const { pageCount, disabled, currentPage, changeEvent } = usePagination()
const userInput = ref<number>()
const innerValue = computed(() => userInput.value ?? currentPage?.value)
function handleInput(val: number | string) {
userInput.value = Number(val)
userInput.value = +val
}
function handleChange(val: number | string) {
pagination?.changeEvent(Number(val))
userInput.value = null
changeEvent?.(+val)
userInput.value = undefined
}
return {
t,
userInput,
pageCount,
disabled,
innerValue,
t,
handleInput,
handleChange,
innerValue,
}
},
})

View File

@@ -4,7 +4,7 @@
class="btn-next"
:disabled="internalDisabled"
:aria-disabled="internalDisabled"
@click.self.prevent
@click="$emit('click', $event)"
>
<span v-if="nextText">{{ nextText }}</span>
<i v-else class="el-icon el-icon-arrow-right"></i>
@@ -13,23 +13,29 @@
<script lang="ts">
import { defineComponent, computed } from 'vue'
export default defineComponent({
name: 'Next',
props: {
disabled: Boolean,
currentPage: {
type: Number,
default: 1,
},
pageCount: {
type: Number,
default: 50,
},
nextText: {
type: String,
default: '',
},
const paginationNextProps = {
disabled: Boolean,
currentPage: {
type: Number,
default: 1,
},
pageCount: {
type: Number,
default: 50,
},
nextText: {
type: String,
default: '',
},
} as const
export default defineComponent({
name: 'ElPaginationNext',
props: paginationNextProps,
emits: ['click'],
setup(props) {
const internalDisabled = computed(
() =>

View File

@@ -47,28 +47,34 @@
<script lang="ts">
import { defineComponent, ref, computed, watchEffect } from 'vue'
export default defineComponent({
name: 'ElPager',
props: {
currentPage: {
type: Number,
default: 1,
},
pageCount: {
type: Number,
},
pagerCount: {
type: Number,
default: 7,
},
disabled: Boolean,
const paginationPagerProps = {
currentPage: {
type: Number,
default: 1,
},
pageCount: {
type: Number,
required: true,
},
pagerCount: {
type: Number,
default: 7,
},
disabled: Boolean,
} as const
export default defineComponent({
name: 'ElPaginationPager',
props: paginationPagerProps,
emits: ['change'],
setup(props, { emit }) {
const showPrevMore = ref(false)
const showNextMore = ref(false)
const quicknextIconClass = ref('el-icon-more')
const quickprevIconClass = ref('el-icon-more')
const pagers = computed(() => {
const pagerCount = props.pagerCount
const halfPagerCount = (pagerCount - 1) / 2
@@ -85,7 +91,7 @@ export default defineComponent({
showNextMore = true
}
}
const array = []
const array: number[] = []
if (showPrevMore && !showNextMore) {
const startPage = pageCount - (pagerCount - 2)
for (let i = startPage; i < pageCount; i++) {
@@ -190,6 +196,7 @@ export default defineComponent({
quicknextIconClass,
quickprevIconClass,
pagers,
onMouseenter,
onPagerClick,
onEnter,

View File

@@ -4,7 +4,7 @@
class="btn-prev"
:disabled="internalDisabled"
:aria-disabled="internalDisabled"
@click.self.prevent
@click="$emit('click', $event)"
>
<span v-if="prevText">{{ prevText }}</span>
<i v-else class="el-icon el-icon-arrow-left"></i>
@@ -14,19 +14,24 @@
<script lang="ts">
import { defineComponent, computed } from 'vue'
export default defineComponent({
name: 'Prev',
props: {
disabled: Boolean,
currentPage: {
type: Number,
default: 1,
},
prevText: {
type: String,
default: '',
},
const paginationPrevProps = {
disabled: Boolean,
currentPage: {
type: Number,
default: 1,
},
prevText: {
type: String,
default: '',
},
} as const
export default defineComponent({
name: 'ElPaginationPrev',
props: paginationPrevProps,
emits: ['click'],
setup(props) {
const internalDisabled = computed(
() => props.disabled || props.currentPage <= 1

View File

@@ -20,39 +20,44 @@
<script lang="ts">
import { defineComponent, watch, computed, ref } from 'vue'
import isEqual from 'lodash/isEqual'
import ElSelect from '@element-plus/components/select'
import { ElSelect, ElOption } from '@element-plus/components/select'
import { useLocaleInject } from '@element-plus/hooks'
import { usePagination } from './usePagination'
import { buildProp, mutable } from '@element-plus/utils/props'
import { usePagination } from '../usePagination'
import type { PropType } from 'vue'
import type { Nullable } from '@element-plus/utils/types'
const { Option: ElOption } = ElSelect
const defaultPageSizes = mutable([10, 20, 30, 40, 50, 100] as const)
const paginationSizesProps = {
pageSize: {
type: Number,
required: true,
},
pageSizes: buildProp<number[], false, typeof defaultPageSizes>({
type: Array,
default: () => defaultPageSizes,
} as const),
popperClass: {
type: String,
default: '',
},
disabled: Boolean,
} as const
export default defineComponent({
name: 'Sizes',
name: 'ElPaginationSizes',
components: {
ElSelect,
ElOption,
},
props: {
pageSize: Number,
pageSizes: {
type: Array as PropType<Array<number>>,
default: () => {
return [10, 20, 30, 40, 50, 100]
},
},
popperClass: {
type: String,
default: '',
},
disabled: Boolean,
},
props: paginationSizesProps,
emits: ['page-size-change'],
setup(props, { emit }) {
const { t } = useLocaleInject()
const { pagination } = usePagination()
const pagination = usePagination()
const innerPageSize = ref<Nullable<number>>(props.pageSize)
watch(
@@ -81,14 +86,15 @@ export default defineComponent({
function handleChange(val: number) {
if (val !== innerPageSize.value) {
innerPageSize.value = val
pagination?.handleSizeChange(Number(val))
pagination.handleSizeChange?.(Number(val))
}
}
return {
t,
innerPagesizes,
innerPageSize,
t,
handleChange,
}
},

View File

@@ -12,14 +12,21 @@
import { defineComponent } from 'vue'
import { useLocaleInject } from '@element-plus/hooks'
export default defineComponent({
name: 'Total',
props: {
total: {
type: Number,
default: 1000,
},
import type { ExtractPropTypes } from 'vue'
const paginationTotalProps = {
total: {
type: Number,
default: 1000,
},
} as const
export type PaginationTotalProps = ExtractPropTypes<typeof paginationTotalProps>
export default defineComponent({
name: 'ElPaginationTotal',
props: paginationTotalProps,
setup() {
const { t } = useLocaleInject()
return {

View File

@@ -1,346 +0,0 @@
import {
h,
ref,
provide,
computed,
defineComponent,
getCurrentInstance,
watch,
} from 'vue'
import { debugWarn } from '@element-plus/utils/error'
import { useLocaleInject } from '@element-plus/hooks'
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'
import type { IPagination } from './pagination'
/**
* It it user's responsibility to guarantee that the value of props.total... is number
* (same as pageSize, defaultPageSize, currentPage, defaultCurrentPage, pageCount)
* Otherwise we can reasonable infer that the corresponding field is absent
*/
const isAbsent = (v: unknown) => typeof v !== 'number'
const componentName = 'ElPagination'
export default defineComponent({
name: componentName,
components: {
Prev,
Next,
Sizes,
Jumper,
Total,
Pager,
},
props: {
total: {
type: Number,
},
pageSize: {
type: Number,
},
defaultPageSize: {
type: Number,
},
currentPage: {
type: Number,
},
defaultCurrentPage: {
type: Number,
},
pageCount: {
type: Number,
},
pagerCount: {
type: Number,
validator: (value: number) => {
return (
(value | 0) === value && value > 4 && value < 22 && value % 2 === 1
)
},
default: 7,
},
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: '',
},
small: Boolean,
background: Boolean,
disabled: Boolean,
hideOnSinglePage: Boolean,
},
emits: [
'update:current-page',
'update:page-size',
// events below are depracated
// v-model:current-page and v-model:page-size are better choices
'size-change',
'current-change',
'prev-click',
'next-click',
],
setup(props, { emit, slots }) {
const { t } = useLocaleInject()
const vnodeProps = getCurrentInstance().vnode.props || {}
// we can find @xxx="xxx" props on `vnodeProps` to check if user bind corresponding events
const hasCurrentPageListener =
'onUpdate:currentPage' in vnodeProps ||
'onUpdate:current-page' in vnodeProps ||
'onCurrentChange' in vnodeProps
const hasPageSizeListener =
'onUpdate:pageSize' in vnodeProps ||
'onUpdate:page-size' in vnodeProps ||
'onSizeChange' in vnodeProps
const assertValidUsage = computed(() => {
// Users have to set either one, otherwise count of pages cannot be determined
if (isAbsent(props.total) && isAbsent(props.pageCount)) return false
// <el-pagination ...otherProps :current-page="xxx" /> without corresponding listener is forbidden now
// Users have to use two way binding of `currentPage`
// If users just want to provide a default value, `defaultCurrentPage` is here for you
if (!isAbsent(props.currentPage) && !hasCurrentPageListener) return false
// When you want to change sizes, things get more complex, detailed below
// Basically the most important value we need is page count
// either directly from props.pageCount
// or calculated from props.total
// we will take props.pageCount precedence over props.total
if (props.layout.includes('sizes')) {
if (!isAbsent(props.pageCount)) {
// if props.pageCount is assign by user, then user have to watch pageSize change
// and recalculate pageCount
if (!hasPageSizeListener) return false
} else if (!isAbsent(props.total)) {
// Otherwise, we will see if user have props.pageSize defined
// If so, meaning user want to have pageSize controlled himself/herself from component
// Thus page size listener is required
// users are account for page size change
if (!isAbsent(props.pageSize)) {
if (!hasPageSizeListener) {
return false
}
} else {
// (else block just for explaination)
// else page size is controlled by el-pagination internally
}
}
}
return true
})
const innerPageSize = ref(
isAbsent(props.defaultPageSize) ? 10 : props.defaultPageSize
)
const innerCurrentPage = ref(
isAbsent(props.defaultCurrentPage) ? 1 : props.defaultCurrentPage
)
const pageSizeBridge = computed({
get() {
return isAbsent(props.pageSize) ? innerPageSize.value : props.pageSize
},
set(v: number) {
if (isAbsent(props.pageSize)) {
innerPageSize.value = v
}
if (hasPageSizeListener) {
emit('update:page-size', v)
emit('size-change', v)
}
},
})
const pageCountBridge = computed<number>(() => {
let pageCount = 0
if (!isAbsent(props.pageCount)) {
pageCount = props.pageCount
} else if (!isAbsent(props.total)) {
pageCount = Math.max(1, Math.ceil(props.total / pageSizeBridge.value))
}
return pageCount
})
const currentPageBridge = computed<number>({
get() {
return isAbsent(props.currentPage)
? innerCurrentPage.value
: props.currentPage
},
set(v) {
let newCurrentPage = v
if (v < 1) {
newCurrentPage = 1
} else if (v > pageCountBridge.value) {
newCurrentPage = pageCountBridge.value
}
if (isAbsent(props.currentPage)) {
innerCurrentPage.value = newCurrentPage
}
if (hasCurrentPageListener) {
emit('update:current-page', newCurrentPage)
emit('current-change', newCurrentPage)
}
},
})
watch(pageCountBridge, (val) => {
if (currentPageBridge.value > val) currentPageBridge.value = val
})
function handleCurrentChange(val: number) {
currentPageBridge.value = val
}
function handleSizeChange(val: number) {
pageSizeBridge.value = val
const newPageCount = pageCountBridge.value
if (currentPageBridge.value > newPageCount) {
currentPageBridge.value = newPageCount
}
}
function prev() {
if (props.disabled) return
currentPageBridge.value -= 1
emit('prev-click', currentPageBridge.value)
}
function next() {
if (props.disabled) return
currentPageBridge.value += 1
emit('next-click', currentPageBridge.value)
}
provide<IPagination>('pagination', {
pageCount: pageCountBridge,
disabled: computed(() => props.disabled),
currentPage: currentPageBridge,
changeEvent: handleCurrentChange,
handleSizeChange,
})
return () => {
if (!assertValidUsage.value) {
debugWarn(componentName, t('el.pagination.deprecationWarning'))
return null
}
if (!props.layout) return null
if (props.hideOnSinglePage && pageCountBridge.value <= 1) return null
const rootChildren = []
const rightWrapperChildren = []
const rightWrapperRoot = h(
'div',
{ class: 'el-pagination__rightwrapper' },
rightWrapperChildren
)
const TEMPLATE_MAP = {
prev: h(Prev, {
disabled: props.disabled,
currentPage: currentPageBridge.value,
prevText: props.prevText,
onClick: prev,
}),
jumper: h(Jumper as any),
pager: h(Pager as any, {
currentPage: currentPageBridge.value,
pageCount: pageCountBridge.value,
pagerCount: props.pagerCount,
onChange: handleCurrentChange,
disabled: props.disabled,
}),
next: h(Next as any, {
disabled: props.disabled,
currentPage: currentPageBridge.value,
pageCount: pageCountBridge.value,
nextText: props.nextText,
onClick: next,
}),
sizes: h(Sizes as any, {
pageSize: pageSizeBridge.value,
pageSizes: props.pageSizes,
popperClass: props.popperClass,
disabled: props.disabled,
}),
slot: slots?.default?.() ?? null,
total: h(Total, { total: isAbsent(props.total) ? 0 : props.total }),
}
const components = props.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 && rightWrapperChildren.length > 0) {
rootChildren.unshift(rightWrapperRoot)
}
return h(
'div',
{
role: 'pagination',
'aria-label': 'pagination',
class: [
'el-pagination',
{
'is-background': props.background,
'el-pagination--small': props.small,
},
],
},
rootChildren
)
}
},
})

View File

@@ -1,35 +1,335 @@
import type { ComputedRef } from 'vue'
import type { AnyFunction } from '@element-plus/utils/types'
import {
h,
ref,
provide,
computed,
defineComponent,
getCurrentInstance,
watch,
} from 'vue'
import { useLocaleInject } from '@element-plus/hooks'
import { debugWarn } from '@element-plus/utils/error'
import { buildProp, mutable } from '@element-plus/utils/props'
import { elPaginationKey } from '@element-plus/tokens'
export interface IPagination {
currentPage?: ComputedRef<number>
pageCount?: ComputedRef<number>
disabled?: ComputedRef<boolean>
changeEvent?: AnyFunction<any>
handleSizeChange?: AnyFunction<any>
}
import Prev from './components/prev.vue'
import Next from './components/next.vue'
import Sizes from './components/sizes.vue'
import Jumper from './components/jumper.vue'
import Total from './components/total.vue'
import Pager from './components/pager.vue'
export interface IPaginationProps {
pageSize: number
small: boolean
total: number
pageCount: number
pagerCount: number
currentPage: number
layout: Record<string, string | undefined>
pageSizes: Array<number>
popperClass: string
prevText: string
nextText: string
background: boolean
disabled: boolean
hideOnSinglePage: boolean
}
import type { VNode, ExtractPropTypes } from 'vue'
export interface IPaginationSetups {
currentPage: number
pageCount: number
pagerCount: number
disabled: boolean
pageSizes: Array<number>
/**
* It it user's responsibility to guarantee that the value of props.total... is number
* (same as pageSize, defaultPageSize, currentPage, defaultCurrentPage, pageCount)
* Otherwise we can reasonable infer that the corresponding field is absent
*/
const isAbsent = (v: unknown): v is undefined => typeof v !== 'number'
type LayoutKey =
| 'prev'
| 'pager'
| 'next'
| 'jumper'
| '->'
| 'total'
| 'sizes'
| 'slot'
const defaultPageSizes = mutable([10, 20, 30, 40, 50, 100] as const)
export const paginationProps = {
total: Number,
pageSize: Number,
defaultPageSize: Number,
currentPage: Number,
defaultCurrentPage: Number,
pageCount: Number,
pagerCount: {
type: Number,
validator: (value: unknown) => {
return (
typeof value === 'number' &&
(value | 0) === value &&
value > 4 &&
value < 22 &&
value % 2 === 1
)
},
default: 7,
},
layout: {
type: String,
default: (
['prev', 'pager', 'next', 'jumper', '->', 'total'] as LayoutKey[]
).join(', '),
},
pageSizes: buildProp<number[], false, typeof defaultPageSizes>({
type: Array,
default: () => defaultPageSizes,
}),
popperClass: {
type: String,
default: '',
},
prevText: {
type: String,
default: '',
},
nextText: {
type: String,
default: '',
},
small: Boolean,
background: Boolean,
disabled: Boolean,
hideOnSinglePage: Boolean,
} as const
export type PaginationProps = ExtractPropTypes<typeof paginationProps>
export const paginationEmits = {
'update:current-page': (val: number) => typeof val === 'number',
'update:page-size': (val: number) => typeof val === 'number',
'size-change': (val: number) => typeof val === 'number',
'current-change': (val: number) => typeof val === 'number',
'prev-click': (val: number) => typeof val === 'number',
'next-click': (val: number) => typeof val === 'number',
}
export type PaginationEmits = typeof paginationEmits
const componentName = 'ElPagination'
export default defineComponent({
name: componentName,
props: paginationProps,
emits: paginationEmits,
setup(props, { emit, slots }) {
const { t } = useLocaleInject()
const vnodeProps = getCurrentInstance()!.vnode.props || {}
// we can find @xxx="xxx" props on `vnodeProps` to check if user bind corresponding events
const hasCurrentPageListener =
'onUpdate:currentPage' in vnodeProps ||
'onUpdate:current-page' in vnodeProps ||
'onCurrentChange' in vnodeProps
const hasPageSizeListener =
'onUpdate:pageSize' in vnodeProps ||
'onUpdate:page-size' in vnodeProps ||
'onSizeChange' in vnodeProps
const assertValidUsage = computed(() => {
// Users have to set either one, otherwise count of pages cannot be determined
if (isAbsent(props.total) && isAbsent(props.pageCount)) return false
// <el-pagination ...otherProps :current-page="xxx" /> without corresponding listener is forbidden now
// Users have to use two way binding of `currentPage`
// If users just want to provide a default value, `defaultCurrentPage` is here for you
if (!isAbsent(props.currentPage) && !hasCurrentPageListener) return false
// When you want to change sizes, things get more complex, detailed below
// Basically the most important value we need is page count
// either directly from props.pageCount
// or calculated from props.total
// we will take props.pageCount precedence over props.total
if (props.layout.includes('sizes')) {
if (!isAbsent(props.pageCount)) {
// if props.pageCount is assign by user, then user have to watch pageSize change
// and recalculate pageCount
if (!hasPageSizeListener) return false
} else if (!isAbsent(props.total)) {
// Otherwise, we will see if user have props.pageSize defined
// If so, meaning user want to have pageSize controlled himself/herself from component
// Thus page size listener is required
// users are account for page size change
if (!isAbsent(props.pageSize)) {
if (!hasPageSizeListener) {
return false
}
} else {
// (else block just for explaination)
// else page size is controlled by el-pagination internally
}
}
}
return true
})
const innerPageSize = ref(
isAbsent(props.defaultPageSize) ? 10 : props.defaultPageSize
)
const innerCurrentPage = ref(
isAbsent(props.defaultCurrentPage) ? 1 : props.defaultCurrentPage
)
const pageSizeBridge = computed({
get() {
return isAbsent(props.pageSize) ? innerPageSize.value : props.pageSize
},
set(v: number) {
if (isAbsent(props.pageSize)) {
innerPageSize.value = v
}
if (hasPageSizeListener) {
emit('update:page-size', v)
emit('size-change', v)
}
},
})
const pageCountBridge = computed<number>(() => {
let pageCount = 0
if (!isAbsent(props.pageCount)) {
pageCount = props.pageCount
} else if (!isAbsent(props.total)) {
pageCount = Math.max(1, Math.ceil(props.total / pageSizeBridge.value))
}
return pageCount
})
const currentPageBridge = computed<number>({
get() {
return isAbsent(props.currentPage)
? innerCurrentPage.value
: props.currentPage
},
set(v) {
let newCurrentPage = v
if (v < 1) {
newCurrentPage = 1
} else if (v > pageCountBridge.value) {
newCurrentPage = pageCountBridge.value
}
if (isAbsent(props.currentPage)) {
innerCurrentPage.value = newCurrentPage
}
if (hasCurrentPageListener) {
emit('update:current-page', newCurrentPage)
emit('current-change', newCurrentPage)
}
},
})
watch(pageCountBridge, (val) => {
if (currentPageBridge.value > val) currentPageBridge.value = val
})
function handleCurrentChange(val: number) {
currentPageBridge.value = val
}
function handleSizeChange(val: number) {
pageSizeBridge.value = val
const newPageCount = pageCountBridge.value
if (currentPageBridge.value > newPageCount) {
currentPageBridge.value = newPageCount
}
}
function prev() {
if (props.disabled) return
currentPageBridge.value -= 1
emit('prev-click', currentPageBridge.value)
}
function next() {
if (props.disabled) return
currentPageBridge.value += 1
emit('next-click', currentPageBridge.value)
}
provide(elPaginationKey, {
pageCount: pageCountBridge,
disabled: computed(() => props.disabled),
currentPage: currentPageBridge,
changeEvent: handleCurrentChange,
handleSizeChange,
})
return () => {
if (!assertValidUsage.value) {
debugWarn(componentName, t('el.pagination.deprecationWarning'))
return null
}
if (!props.layout) return null
if (props.hideOnSinglePage && pageCountBridge.value <= 1) return null
const rootChildren: Array<VNode | VNode[] | null> = []
const rightWrapperChildren: Array<VNode | VNode[] | null> = []
const rightWrapperRoot = h(
'div',
{ class: 'el-pagination__rightwrapper' },
rightWrapperChildren
)
const TEMPLATE_MAP: Record<
Exclude<LayoutKey, '->'>,
VNode | VNode[] | null
> = {
prev: h(Prev, {
disabled: props.disabled,
currentPage: currentPageBridge.value,
prevText: props.prevText,
onClick: prev,
}),
jumper: h(Jumper),
pager: h(Pager, {
currentPage: currentPageBridge.value,
pageCount: pageCountBridge.value,
pagerCount: props.pagerCount,
onChange: handleCurrentChange,
disabled: props.disabled,
}),
next: h(Next, {
disabled: props.disabled,
currentPage: currentPageBridge.value,
pageCount: pageCountBridge.value,
nextText: props.nextText,
onClick: next,
}),
sizes: h(Sizes, {
pageSize: pageSizeBridge.value,
pageSizes: props.pageSizes,
popperClass: props.popperClass,
disabled: props.disabled,
}),
slot: slots?.default?.() ?? null,
total: h(Total, { total: isAbsent(props.total) ? 0 : props.total }),
}
const components = props.layout
.split(',')
.map((item: string) => item.trim()) as LayoutKey[]
let haveRightWrapper = false
components.forEach((c) => {
if (c === '->') {
haveRightWrapper = true
return
}
if (!haveRightWrapper) {
rootChildren.push(TEMPLATE_MAP[c])
} else {
rightWrapperChildren.push(TEMPLATE_MAP[c])
}
})
if (haveRightWrapper && rightWrapperChildren.length > 0) {
rootChildren.unshift(rightWrapperRoot)
}
return h(
'div',
{
role: 'pagination',
'aria-label': 'pagination',
class: [
'el-pagination',
{
'is-background': props.background,
'el-pagination--small': props.small,
},
],
},
rootChildren
)
}
},
})

View File

@@ -1,13 +1,4 @@
import { inject } from 'vue'
import type { IPagination } from './pagination'
import { elPaginationKey } from '@element-plus/tokens'
export const usePagination = () => {
const pagination = inject<IPagination>('pagination', {})
return {
pagination,
pageCount: pagination.pageCount,
disabled: pagination.disabled,
currentPage: pagination.currentPage,
}
}
export const usePagination = () => inject(elPaginationKey, {})

View File

@@ -1,3 +1,4 @@
export * from './form'
export * from './button'
export * from './breadcrumb'
export * from './pagination'

View File

@@ -0,0 +1,12 @@
import type { InjectionKey, ComputedRef } from 'vue'
export interface ElPaginationContext {
currentPage?: ComputedRef<number>
pageCount?: ComputedRef<number>
disabled?: ComputedRef<boolean>
changeEvent?: (val: number) => void
handleSizeChange?: (val: number) => void
}
export const elPaginationKey: InjectionKey<ElPaginationContext> =
Symbol('elPaginationKey')

View File

@@ -1,3 +1,4 @@
import type { Mutable } from './types'
import type { PropType } from 'vue'
/**
@@ -69,5 +70,7 @@ export function buildProp<
}
export const keyOf = <T>(arr: T) => Object.keys(arr) as Array<keyof T>
export const mutable = <T extends readonly any[]>(val: T) =>
val as Mutable<typeof val>
export const componentSize = ['large', 'medium', 'small', 'mini'] as const

View File

@@ -49,3 +49,5 @@ export type TimeoutHandle = ReturnType<typeof global.setTimeout>
export type ComponentSize = 'large' | 'medium' | 'small' | 'mini'
export type StyleValue = string | CSSProperties | Array<StyleValue>
export type Mutable<T> = { -readonly [P in keyof T]: T[P] }