2018-03-19 10:16:27 +08:00
2018-03-05 19:06:44 +08:00
import PropTypes from '../_util/vue-types'
import BaseMixin from '../_util/BaseMixin'
import { hasProp } from '../_util/props-util'
import Pager from './Pager'
import Options from './Options'
import LOCALE from './locale/zh_CN'
import KEYCODE from './KeyCode'
function noop ( ) {
}
// 是否是正整数
function isInteger ( value ) {
return typeof value === 'number' &&
isFinite ( value ) &&
Math . floor ( value ) === value
}
function defaultItemRender ( page , type , element ) {
return element
}
export default {
name : 'Pagination' ,
mixins : [ BaseMixin ] ,
props : {
prefixCls : PropTypes . string . def ( 'rc-pagination' ) ,
selectPrefixCls : PropTypes . string . def ( 'rc-select' ) ,
current : PropTypes . number ,
defaultCurrent : PropTypes . number . def ( 1 ) ,
total : PropTypes . number . def ( 0 ) ,
pageSize : PropTypes . number ,
defaultPageSize : PropTypes . number . def ( 10 ) ,
change : PropTypes . func . def ( noop ) ,
hideOnSinglePage : PropTypes . bool . def ( false ) ,
showSizeChanger : PropTypes . bool . def ( false ) ,
showLessItems : PropTypes . bool . def ( false ) ,
// showSizeChange: PropTypes.func.def(noop),
selectComponentClass : PropTypes . any ,
2018-03-22 17:23:51 +08:00
showPrevNextJumpers : PropTypes . bool . def ( true ) ,
2018-03-05 19:06:44 +08:00
showQuickJumper : PropTypes . oneOfType ( [ PropTypes . bool , PropTypes . object ] ) . def ( false ) ,
showTitle : PropTypes . bool . def ( true ) ,
pageSizeOptions : PropTypes . arrayOf ( PropTypes . string ) ,
2018-03-06 15:40:42 +08:00
buildOptionText : PropTypes . func ,
2018-03-05 19:06:44 +08:00
showTotal : PropTypes . func ,
simple : PropTypes . bool ,
locale : PropTypes . object . def ( LOCALE ) ,
itemRender : PropTypes . func . def ( defaultItemRender ) ,
} ,
model : {
prop : 'current' ,
2018-03-09 18:52:31 +08:00
event : 'change' ,
2018-03-05 19:06:44 +08:00
} ,
data ( ) {
const hasOnChange = this . onChange !== noop
const hasCurrent = hasProp ( this , 'current' )
if ( hasCurrent && ! hasOnChange ) {
console . warn ( 'Warning: You provided a `current` prop to a Pagination component without an `onChange` handler. This will render a read-only component.' ) ; // eslint-disable-line
}
let current = this . defaultCurrent
if ( hasCurrent ) {
current = this . current
}
let pageSize = this . defaultPageSize
if ( hasProp ( this , 'pageSize' ) ) {
pageSize = this . pageSize
}
return {
stateCurrent : current ,
stateCurrentInputValue : current ,
statePageSize : pageSize ,
}
} ,
watch : {
current ( val ) {
this . setState ( {
stateCurrent : val ,
stateCurrentInputValue : val ,
} )
} ,
pageSize ( val ) {
const newState = { }
2018-03-11 13:47:42 +08:00
let current = this . stateCurrent
2018-03-05 19:06:44 +08:00
const newCurrent = this . calculatePage ( val )
current = current > newCurrent ? newCurrent : current
2018-03-07 10:48:33 +08:00
if ( ! hasProp ( this , 'current' ) ) {
2018-03-05 19:06:44 +08:00
newState . stateCurrent = current
newState . stateCurrentInputValue = current
}
newState . statePageSize = val
this . setState ( newState )
} ,
2018-04-21 12:51:56 +08:00
stateCurrent ( val , oldValue ) {
2018-04-07 18:52:02 +08:00
// When current page change, fix focused style of prev item
// A hacky solution of https://github.com/ant-design/ant-design/issues/8948
2018-04-21 12:51:56 +08:00
this . $nextTick ( ( ) => {
if ( this . $refs . paginationNode ) {
2018-04-07 18:52:02 +08:00
const lastCurrentNode = this . $refs . paginationNode . querySelector (
` . ${ this . prefixCls } -item- ${ oldValue } `
2018-04-21 12:51:56 +08:00
)
2018-04-07 18:52:02 +08:00
if ( lastCurrentNode && document . activeElement === lastCurrentNode ) {
2018-04-21 12:51:56 +08:00
lastCurrentNode . blur ( )
2018-04-07 18:52:02 +08:00
}
}
} )
} ,
2018-03-05 19:06:44 +08:00
} ,
methods : {
isValid ( page ) {
return isInteger ( page ) && page >= 1 && page !== this . stateCurrent
} ,
calculatePage ( p ) {
let pageSize = p
if ( typeof pageSize === 'undefined' ) {
pageSize = this . statePageSize
}
return Math . floor ( ( this . total - 1 ) / pageSize ) + 1
} ,
handleGoTO ( event ) {
if ( event . keyCode === KEYCODE . ENTER || event . type === 'click' ) {
this . handleChange ( this . stateCurrentInputValue )
}
} ,
prev ( ) {
if ( this . hasPrev ( ) ) {
this . handleChange ( this . stateCurrent - 1 )
}
} ,
next ( ) {
if ( this . hasNext ( ) ) {
this . handleChange ( this . stateCurrent + 1 )
}
} ,
hasPrev ( ) {
return this . stateCurrent > 1
} ,
hasNext ( ) {
return this . stateCurrent < this . calculatePage ( )
} ,
handleKeyDown ( event ) {
if ( event . keyCode === KEYCODE . ARROW _UP || event . keyCode === KEYCODE . ARROW _DOWN ) {
event . preventDefault ( )
}
} ,
handleKeyUp ( event ) {
const inputValue = event . target . value
const stateCurrentInputValue = this . stateCurrentInputValue
let value
if ( inputValue === '' ) {
value = inputValue
} else if ( isNaN ( Number ( inputValue ) ) ) {
value = stateCurrentInputValue
} else {
value = Number ( inputValue )
}
if ( value !== stateCurrentInputValue ) {
this . setState ( {
stateCurrentInputValue : value ,
} )
}
if ( event . keyCode === KEYCODE . ENTER ) {
this . handleChange ( value )
} else if ( event . keyCode === KEYCODE . ARROW _UP ) {
this . handleChange ( value - 1 )
} else if ( event . keyCode === KEYCODE . ARROW _DOWN ) {
this . handleChange ( value + 1 )
}
} ,
changePageSize ( size ) {
let current = this . stateCurrent
const newCurrent = this . calculatePage ( size )
current = current > newCurrent ? newCurrent : current
2018-09-05 21:28:54 +08:00
// fix the issue:
// Once 'total' is 0, 'current' in 'onShowSizeChange' is 0, which is not correct.
if ( newCurrent === 0 ) {
current = this . stateCurrent
}
2018-03-05 19:06:44 +08:00
if ( typeof size === 'number' ) {
if ( ! hasProp ( this , 'pageSize' ) ) {
this . setState ( {
statePageSize : size ,
} )
}
if ( ! hasProp ( this , 'current' ) ) {
this . setState ( {
stateCurrent : current ,
stateCurrentInputValue : current ,
} )
}
}
2018-03-11 13:47:42 +08:00
this . $emit ( 'update:pageSize' , size )
2018-03-05 19:06:44 +08:00
this . $emit ( 'showSizeChange' , current , size )
2018-03-11 13:47:42 +08:00
this . $emit ( 'change' , current , size )
2018-03-05 19:06:44 +08:00
} ,
handleChange ( p ) {
let page = p
if ( this . isValid ( page ) ) {
const allTotal = this . calculatePage ( )
if ( page > allTotal ) {
page = allTotal
}
if ( ! hasProp ( this , 'current' ) ) {
this . setState ( {
stateCurrent : page ,
stateCurrentInputValue : page ,
} )
}
2018-03-07 10:48:33 +08:00
// this.$emit('input', page)
2018-03-05 19:06:44 +08:00
this . $emit ( 'change' , page , this . statePageSize )
return page
}
return this . stateCurrent
} ,
runIfEnter ( event , callback , ... restParams ) {
if ( event . key === 'Enter' || event . charCode === 13 ) {
callback ( ... restParams )
}
} ,
runIfEnterPrev ( event ) {
this . runIfEnter ( event , this . prev )
} ,
runIfEnterNext ( event ) {
this . runIfEnter ( event , this . next )
} ,
runIfEnterJumpPrev ( event ) {
this . runIfEnter ( event , this . jumpPrev )
} ,
runIfEnterJumpNext ( event ) {
this . runIfEnter ( event , this . jumpNext )
} ,
getJumpPrevPage ( ) {
return Math . max ( 1 , this . stateCurrent - ( this . showLessItems ? 3 : 5 ) )
} ,
getJumpNextPage ( ) {
return Math . min ( this . calculatePage ( ) , this . stateCurrent + ( this . showLessItems ? 3 : 5 ) )
} ,
jumpPrev ( ) {
this . handleChange ( this . getJumpPrevPage ( ) )
} ,
jumpNext ( ) {
this . handleChange ( this . getJumpNextPage ( ) )
} ,
} ,
render ( ) {
// When hideOnSinglePage is true and there is only 1 page, hide the pager
if ( this . hideOnSinglePage === true && this . total <= this . statePageSize ) {
return null
}
const locale = this . locale
const prefixCls = this . prefixCls
const allPages = this . calculatePage ( )
const pagerList = [ ]
let jumpPrev = null
let jumpNext = null
let firstPager = null
let lastPager = null
let gotoButton = null
const goButton = ( this . showQuickJumper && this . showQuickJumper . goButton )
const pageBufferSize = this . showLessItems ? 1 : 2
const { stateCurrent , statePageSize } = this
const prevPage = stateCurrent - 1 > 0 ? stateCurrent - 1 : 0
const nextPage = stateCurrent + 1 < allPages ? stateCurrent + 1 : allPages
if ( this . simple ) {
if ( goButton ) {
if ( typeof goButton === 'boolean' ) {
gotoButton = (
< button
type = 'button'
onClick = { this . handleGoTO }
2018-03-07 10:48:33 +08:00
onKeyup = { this . handleGoTO }
2018-03-05 19:06:44 +08:00
>
{ locale . jump _to _confirm }
< / button >
)
} else {
gotoButton = (
< span
onClick = { this . handleGoTO }
2018-03-07 10:48:33 +08:00
onKeyup = { this . handleGoTO }
2018-03-05 19:06:44 +08:00
> { goButton } < / span >
)
}
gotoButton = (
< li
title = { this . showTitle ? ` ${ locale . jump _to } ${ this . stateCurrent } / ${ allPages } ` : null }
class = { ` ${ prefixCls } -simple-pager ` }
>
{ gotoButton }
< / li >
)
}
2018-03-09 12:20:21 +08:00
const hasPrev = this . hasPrev ( )
const hasNext = this . hasNext ( )
2018-03-05 19:06:44 +08:00
return (
< ul class = { ` ${ prefixCls } ${ prefixCls } -simple ` } >
< li
title = { this . showTitle ? locale . prev _page : null }
onClick = { this . prev }
2018-03-09 12:20:21 +08:00
tabIndex = { hasPrev ? 0 : null }
2018-03-05 19:06:44 +08:00
onKeypress = { this . runIfEnterPrev }
2018-03-09 12:20:21 +08:00
class = { ` ${ hasPrev ? '' : ` ${ prefixCls } -disabled ` } ${ prefixCls } -prev ` }
2018-03-05 19:06:44 +08:00
aria - disabled = { ! this . hasPrev ( ) }
>
{ this . itemRender ( prevPage , 'prev' , < a class = { ` ${ prefixCls } -item-link ` } / > ) }
< / li >
< li
title = { this . showTitle ? ` ${ stateCurrent } / ${ allPages } ` : null }
class = { ` ${ prefixCls } -simple-pager ` }
>
< input
type = 'text'
value = { this . stateCurrentInputValue }
onKeydown = { this . handleKeyDown }
onKeyup = { this . handleKeyUp }
2018-03-12 22:13:59 +08:00
onInput = { this . handleKeyUp }
2018-03-05 19:06:44 +08:00
size = '3'
/ >
< span class = { ` ${ prefixCls } -slash ` } > / < / span >
{ allPages }
< / li >
< li
title = { this . showTitle ? locale . next _page : null }
onClick = { this . next }
2018-03-22 17:23:51 +08:00
tabIndex = { this . hasNext ? 0 : null }
2018-03-05 19:06:44 +08:00
onKeypress = { this . runIfEnterNext }
2018-03-09 12:20:21 +08:00
class = { ` ${ hasNext ? '' : ` ${ prefixCls } -disabled ` } ${ prefixCls } -next ` }
2018-03-05 19:06:44 +08:00
aria - disabled = { ! this . hasNext ( ) }
>
{ this . itemRender ( nextPage , 'next' , < a class = { ` ${ prefixCls } -item-link ` } / > ) }
< / li >
{ gotoButton }
< / ul >
)
}
if ( allPages <= 5 + pageBufferSize * 2 ) {
for ( let i = 1 ; i <= allPages ; i ++ ) {
const active = stateCurrent === i
pagerList . push (
< Pager
locale = { locale }
rootPrefixCls = { prefixCls }
onClick = { this . handleChange }
onKeypress = { this . runIfEnter }
key = { i }
page = { i }
active = { active }
showTitle = { this . showTitle }
itemRender = { this . itemRender }
/ >
)
}
} else {
const prevItemTitle = this . showLessItems ? locale . prev _3 : locale . prev _5
const nextItemTitle = this . showLessItems ? locale . next _3 : locale . next _5
2018-03-22 17:23:51 +08:00
if ( this . showPrevNextJumpers ) {
jumpPrev = (
< li
title = { this . showTitle ? prevItemTitle : null }
key = 'prev'
onClick = { this . jumpPrev }
tabIndex = '0'
onKeypress = { this . runIfEnterJumpPrev }
class = { ` ${ prefixCls } -jump-prev ` }
>
{ this . itemRender (
this . getJumpPrevPage ( ) , 'jump-prev' , < a class = { ` ${ prefixCls } -item-link ` } / >
) }
< / li >
)
jumpNext = (
< li
title = { this . showTitle ? nextItemTitle : null }
key = 'next'
tabIndex = '0'
onClick = { this . jumpNext }
onKeypress = { this . runIfEnterJumpNext }
class = { ` ${ prefixCls } -jump-next ` }
>
{ this . itemRender (
this . getJumpNextPage ( ) , 'jump-next' , < a class = { ` ${ prefixCls } -item-link ` } / >
) }
< / li >
)
}
2018-03-05 19:06:44 +08:00
lastPager = (
< Pager
locale = { locale }
last
rootPrefixCls = { prefixCls }
onClick = { this . handleChange }
onKeypress = { this . runIfEnter }
key = { allPages }
page = { allPages }
active = { false }
showTitle = { this . showTitle }
itemRender = { this . itemRender }
/ >
)
firstPager = (
< Pager
locale = { locale }
rootPrefixCls = { prefixCls }
onClick = { this . handleChange }
onKeypress = { this . runIfEnter }
key = { 1 }
page = { 1 }
active = { false }
showTitle = { this . showTitle }
itemRender = { this . itemRender }
/ >
)
let left = Math . max ( 1 , stateCurrent - pageBufferSize )
let right = Math . min ( stateCurrent + pageBufferSize , allPages )
if ( stateCurrent - 1 <= pageBufferSize ) {
right = 1 + pageBufferSize * 2
}
if ( allPages - stateCurrent <= pageBufferSize ) {
left = allPages - pageBufferSize * 2
}
for ( let i = left ; i <= right ; i ++ ) {
const active = stateCurrent === i
pagerList . push (
< Pager
locale = { locale }
rootPrefixCls = { prefixCls }
onClick = { this . handleChange }
onKeypress = { this . runIfEnter }
key = { i }
page = { i }
active = { active }
showTitle = { this . showTitle }
itemRender = { this . itemRender }
/ >
)
}
if ( stateCurrent - 1 >= pageBufferSize * 2 && stateCurrent !== 1 + 2 ) {
pagerList [ 0 ] = (
< Pager
locale = { locale }
rootPrefixCls = { prefixCls }
onClick = { this . handleChange }
onKeypress = { this . runIfEnter }
key = { left }
page = { left }
class = { ` ${ prefixCls } -item-after-jump-prev ` }
active = { false }
showTitle = { this . showTitle }
itemRender = { this . itemRender }
/ >
)
pagerList . unshift ( jumpPrev )
}
if ( allPages - stateCurrent >= pageBufferSize * 2 && stateCurrent !== allPages - 2 ) {
pagerList [ pagerList . length - 1 ] = (
< Pager
locale = { locale }
rootPrefixCls = { prefixCls }
onClick = { this . handleChange }
onKeypress = { this . runIfEnter }
key = { right }
page = { right }
class = { ` ${ prefixCls } -item-before-jump-next ` }
active = { false }
showTitle = { this . showTitle }
itemRender = { this . itemRender }
/ >
)
pagerList . push ( jumpNext )
}
if ( left !== 1 ) {
pagerList . unshift ( firstPager )
}
if ( right !== allPages ) {
pagerList . push ( lastPager )
}
}
let totalText = null
if ( this . showTotal ) {
totalText = (
< li class = { ` ${ prefixCls } -total-text ` } >
{ this . showTotal (
this . total ,
[
( stateCurrent - 1 ) * statePageSize + 1 ,
stateCurrent * statePageSize > this . total ? this . total : stateCurrent * statePageSize ,
]
) }
< / li >
)
}
const prevDisabled = ! this . hasPrev ( )
const nextDisabled = ! this . hasNext ( )
2018-03-06 15:40:42 +08:00
const buildOptionText = this . buildOptionText || this . $scopedSlots . buildOptionText
2018-03-05 19:06:44 +08:00
return (
< ul
class = { ` ${ prefixCls } ` }
unselectable = 'unselectable'
2018-04-07 18:52:02 +08:00
ref = 'paginationNode'
2018-03-05 19:06:44 +08:00
>
{ totalText }
< li
title = { this . showTitle ? locale . prev _page : null }
onClick = { this . prev }
2018-03-09 12:20:21 +08:00
tabIndex = { prevDisabled ? null : 0 }
2018-03-05 19:06:44 +08:00
onKeypress = { this . runIfEnterPrev }
class = { ` ${ ! prevDisabled ? '' : ` ${ prefixCls } -disabled ` } ${ prefixCls } -prev ` }
aria - disabled = { prevDisabled }
>
{ this . itemRender ( prevPage , 'prev' , < a class = { ` ${ prefixCls } -item-link ` } / > ) }
< / li >
{ pagerList }
< li
title = { this . showTitle ? locale . next _page : null }
onClick = { this . next }
2018-03-09 12:20:21 +08:00
tabIndex = { nextDisabled ? null : 0 }
2018-03-05 19:06:44 +08:00
onKeypress = { this . runIfEnterNext }
class = { ` ${ ! nextDisabled ? '' : ` ${ prefixCls } -disabled ` } ${ prefixCls } -next ` }
aria - disabled = { nextDisabled }
>
{ this . itemRender ( nextPage , 'next' , < a class = { ` ${ prefixCls } -item-link ` } / > ) }
< / li >
< Options
locale = { locale }
rootPrefixCls = { prefixCls }
selectComponentClass = { this . selectComponentClass }
selectPrefixCls = { this . selectPrefixCls }
changeSize = { this . showSizeChanger ? this . changePageSize : null }
current = { stateCurrent }
pageSize = { statePageSize }
pageSizeOptions = { this . pageSizeOptions }
2018-03-06 15:40:42 +08:00
buildOptionText = { buildOptionText || null }
2018-03-05 19:06:44 +08:00
quickGo = { this . showQuickJumper ? this . handleChange : null }
goButton = { goButton }
/ >
< / ul >
)
} ,
}
2018-03-19 10:16:27 +08:00