新增输入框跳转功能:在原有分页器基础上,新增了一个输入框区域,允许用户直接输入目标页码进行跳转
双向页码绑定优化:实现了输入框与当前页码的双向绑定机制。当用户通过其他方式(如点击上一页、下一页、页码按钮)切换页面时,输入框会自动更新显示当前页码。同时,当用户在输入框中输入页码并确认跳转时,页面也会相应更新
类型安全和用户体验优化:对输入处理进行了严格的类型安全检查,且支持空值输入
输入框跳转区域
允许用户直接输入页码进行跳转
输入限制: 只能输入数字,最大长度根据总页数确定
< view class = "uni-pagination__jump" >
< text class = "uni-pagination__jump-text" > 前往< / text>
< input class = "uni-pagination__jump-input"
type= "number"
: value= "jumpPage"
@input= "onJumpInput"
@blur= "onJumpBlur"
@confirm= "onJumpConfirm"
: placeholder= "'1-' + maxPage"
: maxlength= "String(maxPage).length" / >
< text class = "uni-pagination__jump-text" > 页< / text>
< / view>
输入框跳转方法
onJumpInput ( e ) {
const value = e. detail. value;
this . jumpPage = value === '' ? '' : Number ( value) || 1 ;
} ,
onJumpBlur ( ) {
if ( this . jumpPage === '' ) {
return ;
}
const targetPage = Number ( this . jumpPage) ;
if ( isNaN ( targetPage) || targetPage < 1 || targetPage > this . maxPage) {
this . jumpPage = 1 ;
} else {
this . jumpPage = targetPage;
}
} ,
onJumpConfirm ( ) {
this . jumpToPage ( ) ;
} ,
jumpToPage ( ) {
if ( this . jumpPage === '' ) {
return ;
}
const targetPage = Number ( this . jumpPage) ;
if ( isNaN ( targetPage) || targetPage < 1 || targetPage > this . maxPage) {
return ;
}
this . currentIndex = targetPage;
this . change ( "current" ) ;
}
事件触发方法
change ( e ) {
this . $emit ( "input" , this . currentIndex) ;
this . $emit ( "update:modelValue" , this . currentIndex) ;
this . $emit ( "change" , {
type: e,
current: this . currentIndex
} ) ;
}
完整代码
< template>
< view class = "uni-pagination" >
< ! -- #ifndef MP -- >
< picker
v- if = "showPageSize === true || showPageSize === 'true'"
class = "select-picker"
mode= "selector"
: value= "pageSizeIndex"
: range= "pageSizeRange"
@change= "pickerChange"
@cancel= "pickerClick"
@click. native= "pickerClick"
>
< button type= "default" size= "mini" : plain= "true" >
< text> { { pageSizeRange[ pageSizeIndex] } } { { piecePerPage } } < / text>
< uni- icons
class = "select-picker-icon"
type= "arrowdown"
size= "12"
color= "#999"
> < / uni- icons>
< / button>
< / picker>
< ! -- #endif -- >
< ! -- #ifndef APP - NVUE -- >
< view class = "uni-pagination__total is-phone-hide" > 共 { { total } } 条< / view>
< ! -- #endif -- >
< view
class = "uni-pagination__btn"
: class = "
currentIndex === 1
? 'uni-pagination--disabled'
: 'uni-pagination--enabled'
"
: hover- class = "currentIndex === 1 ? '' : 'uni-pagination--hover'"
: hover- start- time= "20"
: hover- stay- time= "70"
@click= "clickLeft"
>
< template v- if = "showIcon === true || showIcon === 'true'" >
< uni- icons color= "#666" size= "16" type= "left" / >
< / template>
< template v- else >
< text class = "uni-pagination__child-btn" > { { prevPageText } } < / text>
< / template>
< / view>
< view class = "uni-pagination__num uni-pagination__num-flex-none" >
< view class = "uni-pagination__num-current" >
< text
class = "uni-pagination__num-current-text is-pc-hide current-index-text"
> { { currentIndex } } < / text
>
< text class = "uni-pagination__num-current-text is-pc-hide"
> / { { maxPage || 0 } } < / text
>
< ! -- #ifndef APP - NVUE -- >
< view
v- for = "(item, index) in paper"
: key= "index"
: class = "{ 'page--active': item === currentIndex }"
class = "uni-pagination__num-tag tag--active is-phone-hide"
@click. top= "selectPage(item, index)"
>
< text> { { item } } < / text>
< / view>
< ! -- #endif -- >
< / view>
< / view>
< view class = "uni-pagination__jump" >
< text class = "uni-pagination__jump-text" > 前往< / text>
< input
class = "uni-pagination__jump-input"
type= "number"
: value= "jumpPage"
@input= "onJumpInput"
@blur= "onJumpBlur"
@confirm= "onJumpConfirm"
: placeholder= "'1-' + maxPage"
: maxlength= "String(maxPage).length"
/ >
< text class = "uni-pagination__jump-text" > 页< / text>
< ! -- < button
class = "uni-pagination__jump-btn"
size= "mini"
type= "primary"
@click= "jumpToPage"
>
确定
< / button> -- >
< / view>
< view
class = "uni-pagination__btn"
: class = "
currentIndex >= maxPage
? 'uni-pagination--disabled'
: 'uni-pagination--enabled'
"
: hover- class = "currentIndex === maxPage ? '' : 'uni-pagination--hover'"
: hover- start- time= "20"
: hover- stay- time= "70"
@click= "clickRight"
>
< template v- if = "showIcon === true || showIcon === 'true'" >
< uni- icons color= "#666" size= "16" type= "right" / >
< / template>
< template v- else >
< text class = "uni-pagination__child-btn" > { { nextPageText } } < / text>
< / template>
< / view>
< / view>
< / template>
< script>
import { initVueI18n } from "@dcloudio/uni-i18n" ;
import messages from "./i18n/index.js" ;
const { t } = initVueI18n ( messages) ;
export default {
name: "UniPagination" ,
emits: [ "update:modelValue" , "input" , "change" , "pageSizeChange" ] ,
props: {
value: {
type: [ Number, String] ,
default : 1 ,
} ,
modelValue: {
type: [ Number, String] ,
default : 1 ,
} ,
prevText: {
type: String,
} ,
nextText: {
type: String,
} ,
piecePerPageText: {
type: String,
} ,
current: {
type: [ Number, String] ,
default : 1 ,
} ,
total: {
type: [ Number, String] ,
default : 0 ,
} ,
pageSize: {
type: [ Number, String] ,
default : 10 ,
} ,
showIcon: {
type: [ Boolean, String] ,
default : false ,
} ,
showPageSize: {
type: [ Boolean, String] ,
default : false ,
} ,
pagerCount: {
type: Number,
default : 7 ,
} ,
pageSizeRange: {
type: Array,
default : ( ) => [ 20 , 50 , 100 , 500 ] ,
} ,
} ,
data ( ) {
return {
pageSizeIndex: 0 ,
currentIndex: 1 ,
paperData: [ ] ,
pickerShow: false ,
jumpPage: 1 ,
} ;
} ,
computed: {
piecePerPage ( ) {
return this . piecePerPageText || t ( "uni-pagination.piecePerPage" ) ;
} ,
prevPageText ( ) {
return this . prevText || t ( "uni-pagination.prevText" ) ;
} ,
nextPageText ( ) {
return this . nextText || t ( "uni-pagination.nextText" ) ;
} ,
maxPage ( ) {
let maxPage = 1 ;
let total = Number ( this . total) ;
let pageSize = Number ( this . pageSize) ;
if ( total && pageSize) {
maxPage = Math. ceil ( total / pageSize) ;
}
return maxPage;
} ,
paper ( ) {
const num = this . currentIndex;
const pagerCount = this . pagerCount;
const total = this . total;
const pageSize = this . pageSize;
let totalArr = [ ] ;
let showPagerArr = [ ] ;
let pagerNum = Math. ceil ( total / pageSize) ;
for ( let i = 0 ; i < pagerNum; i++ ) {
totalArr. push ( i + 1 ) ;
}
showPagerArr. push ( 1 ) ;
const totalNum = totalArr[ totalArr. length - ( pagerCount + 1 ) / 2 ] ;
totalArr. forEach ( ( item, index ) => {
if ( ( pagerCount + 1 ) / 2 >= num) {
if ( item < pagerCount + 1 && item > 1 ) {
showPagerArr. push ( item) ;
}
} else if ( num + 2 <= totalNum) {
if (
item > num - ( pagerCount + 1 ) / 2 &&
item < num + ( pagerCount + 1 ) / 2
) {
showPagerArr. push ( item) ;
}
} else {
if (
( item > num - ( pagerCount + 1 ) / 2 ||
pagerNum - pagerCount < item) &&
item < totalArr[ totalArr. length - 1 ]
) {
showPagerArr. push ( item) ;
}
}
} ) ;
if ( pagerNum > pagerCount) {
if ( ( pagerCount + 1 ) / 2 >= num) {
showPagerArr[ showPagerArr. length - 1 ] = "..." ;
} else if ( num + 2 <= totalNum) {
showPagerArr[ 1 ] = "..." ;
showPagerArr[ showPagerArr. length - 1 ] = "..." ;
} else {
showPagerArr[ 1 ] = "..." ;
}
showPagerArr. push ( totalArr[ totalArr. length - 1 ] ) ;
} else {
if ( ( pagerCount + 1 ) / 2 >= num) {
} else if ( num + 2 <= totalNum) {
} else {
showPagerArr. shift ( ) ;
showPagerArr. push ( totalArr[ totalArr. length - 1 ] ) ;
}
}
return showPagerArr;
} ,
} ,
watch: {
current: {
immediate: true ,
handler ( val, old ) {
if ( val < 1 ) {
this . currentIndex = 1 ;
} else {
this . currentIndex = val;
}
} ,
} ,
value: {
immediate: true ,
handler ( val ) {
if ( Number ( this . current) !== 1 ) return ;
if ( val < 1 ) {
this . currentIndex = 1 ;
} else {
this . currentIndex = val;
}
} ,
} ,
pageSizeIndex ( val ) {
this . $emit ( "pageSizeChange" , this . pageSizeRange[ val] ) ;
} ,
currentIndex: {
handler ( val ) {
if ( this . jumpPage !== val && this . jumpPage !== '' ) {
this . jumpPage = val;
}
} ,
immediate: true ,
} ,
} ,
methods: {
pickerChange ( e ) {
this . pageSizeIndex = e. detail. value;
this . pickerClick ( ) ;
} ,
pickerClick ( ) {
const body = document. querySelector ( "body" ) ;
if ( ! body) return ;
const className = "uni-pagination-picker-show" ;
this . pickerShow = ! this . pickerShow;
if ( this . pickerShow) {
body. classList. add ( className) ;
} else {
setTimeout ( ( ) => body. classList. remove ( className) , 300 ) ;
}
} ,
selectPage ( e, index ) {
if ( parseInt ( e) ) {
this . currentIndex = e;
this . change ( "current" ) ;
} else {
let pagerNum = Math. ceil ( this . total / this . pageSize) ;
if ( index <= 1 ) {
if ( this . currentIndex - 5 > 1 ) {
this . currentIndex -= 5 ;
} else {
this . currentIndex = 1 ;
}
return ;
}
if ( index >= 6 ) {
if ( this . currentIndex + 5 > pagerNum) {
this . currentIndex = pagerNum;
} else {
this . currentIndex += 5 ;
}
return ;
}
}
} ,
clickLeft ( ) {
if ( Number ( this . currentIndex) === 1 ) {
return ;
}
this . currentIndex -= 1 ;
this . change ( "prev" ) ;
} ,
clickRight ( ) {
if ( Number ( this . currentIndex) >= this . maxPage) {
return ;
}
this . currentIndex += 1 ;
this . change ( "next" ) ;
} ,
change ( e ) {
this . $emit ( "input" , this . currentIndex) ;
this . $emit ( "update:modelValue" , this . currentIndex) ;
this . $emit ( "change" , {
type: e,
current: this . currentIndex,
} ) ;
} ,
onJumpInput ( e ) {
const value = e. detail. value;
this . jumpPage = value === '' ? '' : Number ( value) || 1 ;
} ,
onJumpBlur ( ) {
if ( this . jumpPage === '' ) {
return ;
}
const targetPage = Number ( this . jumpPage) ;
if ( isNaN ( targetPage) || targetPage < 1 || targetPage > this . maxPage) {
this . jumpPage = 1 ;
} else {
this . jumpPage = targetPage;
}
} ,
onJumpConfirm ( ) {
this . jumpToPage ( ) ;
} ,
jumpToPage ( ) {
if ( this . jumpPage === '' ) {
return ;
}
const targetPage = Number ( this . jumpPage) ;
if ( isNaN ( targetPage) || targetPage < 1 || targetPage > this . maxPage) {
return ;
}
this . currentIndex = targetPage;
this . change ( "current" ) ;
} ,
} ,
} ;
< / script>
< style lang= "scss" scoped>
$uni- primary: #2979 ff ! default ;
. uni- pagination {
margin: 40 rpx 0 ;
display: flex;
position: relative;
overflow: hidden;
flex- direction: row;
justify- content: center;
align- items: center;
}
. uni- pagination__total {
font- size: 14 px;
color: #999 ;
margin- right: 15 px;
}
. uni- pagination__btn {
display: flex;
cursor: pointer;
padding: 0 8 px;
line- height: 30 px;
font- size: 12 px;
position: relative;
background- color: #f0f0f0;
flex- direction: row;
justify- content: center;
align- items: center;
text- align: center;
border- radius: 5 px;
}
. uni- pagination__child- btn {
display: flex;
font- size: 12 px;
position: relative;
flex- direction: row;
justify- content: center;
align- items: center;
text- align: center;
color: #666 ;
font- size: 12 px;
}
. uni- pagination__num {
display: flex;
flex: 1 ;
flex- direction: row;
justify- content: center;
align- items: center;
height: 30 px;
line- height: 30 px;
font- size: 12 px;
color: #666 ;
margin: 0 5 px;
}
. uni- pagination__num- tag {
cursor: pointer;
min- width: 30 px;
margin: 0 5 px;
height: 30 px;
text- align: center;
line- height: 30 px;
color: #999 ;
border- radius: 4 px;
}
. uni- pagination__num- current {
display: flex;
flex- direction: row;
}
. uni- pagination__num- current- text {
font- size: 15 px;
}
. current- index- text {
color: $uni- primary;
}
. uni- pagination-- enabled {
color: #333333 ;
opacity: 1 ;
}
. uni- pagination-- disabled {
opacity: 0.5 ;
cursor: default ;
}
. uni- pagination-- hover {
color: rgba ( 0 , 0 , 0 , 0.6 ) ;
background- color: #eee;
}
. tag-- active: hover {
color: $uni- primary;
}
. page-- active {
color: #fff;
background- color: $uni- primary;
}
. page-- active: hover {
color: #fff;
}
. uni- pagination__jump {
display: flex;
flex- direction: row;
justify- content: center;
align- items: center;
margin: 0 10 px;
}
. uni- pagination__jump- text {
font- size: 12 px;
color: #666 ;
margin: 0 5 px;
}
. uni- pagination__jump- input {
width: 50 px;
height: 30 px;
min- height: fit- content;
text- align: center;
border: 1 px solid #ddd;
border- radius: 4 px;
font- size: 12 px;
color: #333 ;
background- color: #fff;
margin: 0 5 px;
}
. uni- pagination__jump- btn {
margin- left: 5 px;
height: 30 px;
line- height: 30 px;
font- size: 12 px;
padding: 0 8 px;
}
. is- pc- hide {
display: block;
}
. is- phone- hide {
display: none;
}
@media screen and ( min- width: 450 px ) {
. is- pc- hide {
display: none;
}
. is- phone- hide {
display: block;
}
. uni- pagination__num- flex- none {
flex: none;
}
}
< / style>