mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-05-26 00:09:15 +08:00
feat: Pagination component
This commit is contained in:
parent
660e535811
commit
97a6bf9d48
67
src-next/pagination/README.md
Normal file
67
src-next/pagination/README.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# Pagination
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
```js
|
||||||
|
import Vue from 'vue';
|
||||||
|
import { Pagination } from 'vant';
|
||||||
|
|
||||||
|
Vue.use(Pagination);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-pagination v-model="currentPage" :total-items="24" :items-per-page="5" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentPage: 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Simple mode
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-pagination v-model="currentPage" :page-count="12" mode="simple" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Show ellipses
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-pagination
|
||||||
|
v-model="currentPage"
|
||||||
|
:total-items="125"
|
||||||
|
:show-page-size="3"
|
||||||
|
force-ellipses
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
| Attribute | Description | Type | Default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| v-model | Current page number | _number_ | - |
|
||||||
|
| mode | Mode, can be set to `simple` `multi` | _string_ | `multi` |
|
||||||
|
| prev-text | Previous text | _string_ | `Previous` |
|
||||||
|
| next-text | Next text | _string_ | `Next` |
|
||||||
|
| total-items | Total items | _number \| string_ | `0` |
|
||||||
|
| items-per-page | Item number per page | _number \| string_ | `10` |
|
||||||
|
| page-count | The total number of pages, if not set, will be calculated based on `total-items` and `items-per-page` | _number \| string_ | `-` |
|
||||||
|
| show-page-size | Count of page size to show | _number \| string_ | `5` |
|
||||||
|
| force-ellipses | Whether to show ellipses | _boolean_ | `false` |
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
| Event | Description | Arguments |
|
||||||
|
| ------ | ------------------------ | --------- |
|
||||||
|
| change | Triggered on page change | - |
|
67
src-next/pagination/README.zh-CN.md
Normal file
67
src-next/pagination/README.zh-CN.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# Pagination 分页
|
||||||
|
|
||||||
|
### 引入
|
||||||
|
|
||||||
|
```js
|
||||||
|
import Vue from 'vue';
|
||||||
|
import { Pagination } from 'vant';
|
||||||
|
|
||||||
|
Vue.use(Pagination);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 代码演示
|
||||||
|
|
||||||
|
### 基础用法
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-pagination v-model="currentPage" :total-items="24" :items-per-page="5" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentPage: 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 简单模式
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-pagination v-model="currentPage" :page-count="12" mode="simple" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 显示省略号
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-pagination
|
||||||
|
v-model="currentPage"
|
||||||
|
:total-items="125"
|
||||||
|
:show-page-size="3"
|
||||||
|
force-ellipses
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| v-model | 当前页码 | _number_ | - |
|
||||||
|
| mode | 显示模式,可选值为 `simple` | _string_ | `multi` |
|
||||||
|
| prev-text | 上一页按钮文字 | _string_ | `上一页` |
|
||||||
|
| next-text | 下一页按钮文字 | _string_ | `下一页` |
|
||||||
|
| page-count | 总页数 | _number \| string_ | 根据页数计算 |
|
||||||
|
| total-items | 总记录数 | _number \| string_ | `0` |
|
||||||
|
| items-per-page | 每页记录数 | _number \| string_ | `10` |
|
||||||
|
| show-page-size | 显示的页码个数 | _number \| string_ | `5` |
|
||||||
|
| force-ellipses | 是否显示省略号 | _boolean_ | `false` |
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
| 事件名 | 说明 | 回调参数 |
|
||||||
|
| ------ | -------------- | -------- |
|
||||||
|
| change | 页码改变时触发 | - |
|
81
src-next/pagination/demo/index.vue
Normal file
81
src-next/pagination/demo/index.vue
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<demo-section>
|
||||||
|
<demo-block :title="t('basicUsage')">
|
||||||
|
<van-pagination
|
||||||
|
v-model="currentPage1"
|
||||||
|
:total-items="24"
|
||||||
|
:items-per-page="5"
|
||||||
|
:prev-text="t('prevText')"
|
||||||
|
:next-text="t('nextText')"
|
||||||
|
/>
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="t('title2')">
|
||||||
|
<van-pagination
|
||||||
|
v-model="currentPage2"
|
||||||
|
:page-count="12"
|
||||||
|
:prev-text="t('prevText')"
|
||||||
|
:next-text="t('nextText')"
|
||||||
|
mode="simple"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="t('title3')">
|
||||||
|
<van-pagination
|
||||||
|
v-model="currentPage3"
|
||||||
|
force-ellipses
|
||||||
|
:total-items="125"
|
||||||
|
:show-page-size="3"
|
||||||
|
:prev-text="t('prevText')"
|
||||||
|
:next-text="t('nextText')"
|
||||||
|
/>
|
||||||
|
</demo-block>
|
||||||
|
</demo-section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
i18n: {
|
||||||
|
'zh-CN': {
|
||||||
|
title2: '简单模式',
|
||||||
|
title3: '显示省略号',
|
||||||
|
prevText: '上一页',
|
||||||
|
nextText: '下一页',
|
||||||
|
},
|
||||||
|
'en-US': {
|
||||||
|
title2: 'Simple Mode',
|
||||||
|
title3: 'Show ellipses',
|
||||||
|
prevText: 'Prev',
|
||||||
|
nextText: 'Next',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentPage1: 1,
|
||||||
|
currentPage2: 1,
|
||||||
|
currentPage3: 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import '../../style/var';
|
||||||
|
|
||||||
|
.demo-pagination {
|
||||||
|
.van-pagination {
|
||||||
|
width: 100%;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-doc-demo-block {
|
||||||
|
padding: 0 @padding-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-doc-demo-block__title {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
164
src-next/pagination/index.js
Normal file
164
src-next/pagination/index.js
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
import { createNamespace } from '../utils';
|
||||||
|
import { BORDER } from '../utils/constant';
|
||||||
|
|
||||||
|
const [createComponent, bem, t] = createNamespace('pagination');
|
||||||
|
|
||||||
|
function makePage(number, text, active) {
|
||||||
|
return { number, text, active };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createComponent({
|
||||||
|
props: {
|
||||||
|
prevText: String,
|
||||||
|
nextText: String,
|
||||||
|
forceEllipses: Boolean,
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'multi',
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
pageCount: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
totalItems: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
itemsPerPage: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 10,
|
||||||
|
},
|
||||||
|
showPageSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
count() {
|
||||||
|
const count =
|
||||||
|
this.pageCount || Math.ceil(this.totalItems / this.itemsPerPage);
|
||||||
|
return Math.max(1, count);
|
||||||
|
},
|
||||||
|
|
||||||
|
pages() {
|
||||||
|
const pages = [];
|
||||||
|
const pageCount = this.count;
|
||||||
|
const showPageSize = +this.showPageSize;
|
||||||
|
|
||||||
|
if (this.mode !== 'multi') {
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default page limits
|
||||||
|
let startPage = 1;
|
||||||
|
let endPage = pageCount;
|
||||||
|
const isMaxSized = showPageSize < pageCount;
|
||||||
|
|
||||||
|
// recompute if showPageSize
|
||||||
|
if (isMaxSized) {
|
||||||
|
// Current page is displayed in the middle of the visible ones
|
||||||
|
startPage = Math.max(this.modelValue - Math.floor(showPageSize / 2), 1);
|
||||||
|
endPage = startPage + showPageSize - 1;
|
||||||
|
|
||||||
|
// Adjust if limit is exceeded
|
||||||
|
if (endPage > pageCount) {
|
||||||
|
endPage = pageCount;
|
||||||
|
startPage = endPage - showPageSize + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add page number links
|
||||||
|
for (let number = startPage; number <= endPage; number++) {
|
||||||
|
const page = makePage(number, number, number === this.modelValue);
|
||||||
|
pages.push(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add links to move between page sets
|
||||||
|
if (isMaxSized && showPageSize > 0 && this.forceEllipses) {
|
||||||
|
if (startPage > 1) {
|
||||||
|
const previousPageSet = makePage(startPage - 1, '...', false);
|
||||||
|
pages.unshift(previousPageSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endPage < pageCount) {
|
||||||
|
const nextPageSet = makePage(endPage + 1, '...', false);
|
||||||
|
pages.push(nextPageSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
modelValue: {
|
||||||
|
handler(page) {
|
||||||
|
this.select(page);
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
select(page, emitChange) {
|
||||||
|
page = Math.min(this.count, Math.max(1, page));
|
||||||
|
if (this.modelValue !== page) {
|
||||||
|
this.$emit('update:modelValue', page);
|
||||||
|
|
||||||
|
if (emitChange) {
|
||||||
|
this.$emit('change', page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const value = this.modelValue;
|
||||||
|
const simple = this.mode !== 'multi';
|
||||||
|
|
||||||
|
const onSelect = (value) => () => {
|
||||||
|
this.select(value, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul class={bem({ simple })}>
|
||||||
|
<li
|
||||||
|
class={[bem('item', { disabled: value === 1 }), bem('prev'), BORDER]}
|
||||||
|
onClick={onSelect(value - 1)}
|
||||||
|
>
|
||||||
|
{this.prevText || t('prev')}
|
||||||
|
</li>
|
||||||
|
{this.pages.map((page) => (
|
||||||
|
<li
|
||||||
|
class={[bem('item', { active: page.active }), bem('page'), BORDER]}
|
||||||
|
onClick={onSelect(page.number)}
|
||||||
|
>
|
||||||
|
{page.text}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
{simple && (
|
||||||
|
<li class={bem('page-desc')}>
|
||||||
|
{this.$slots.pageDesc
|
||||||
|
? this.$slots.pageDesc()
|
||||||
|
: `${value}/${this.count}`}
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
<li
|
||||||
|
class={[
|
||||||
|
bem('item', { disabled: value === this.count }),
|
||||||
|
bem('next'),
|
||||||
|
BORDER,
|
||||||
|
]}
|
||||||
|
onClick={onSelect(value + 1)}
|
||||||
|
>
|
||||||
|
{this.nextText || t('next')}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
77
src-next/pagination/index.less
Normal file
77
src-next/pagination/index.less
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
@import '../style/var';
|
||||||
|
|
||||||
|
.van-pagination {
|
||||||
|
display: flex;
|
||||||
|
font-size: @pagination-font-size;
|
||||||
|
|
||||||
|
&__item,
|
||||||
|
&__page-desc {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
flex: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-width: @pagination-item-width;
|
||||||
|
height: @pagination-height;
|
||||||
|
color: @pagination-item-default-color;
|
||||||
|
background-color: @pagination-background-color;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: @white;
|
||||||
|
background-color: @pagination-item-default-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-width: @border-width-base 0 @border-width-base @border-width-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child::after {
|
||||||
|
border-right-width: @border-width-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
color: @white;
|
||||||
|
background-color: @pagination-item-default-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__prev,
|
||||||
|
&__next {
|
||||||
|
padding: 0 @padding-base;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item--disabled {
|
||||||
|
&,
|
||||||
|
&:active {
|
||||||
|
color: @pagination-item-disabled-color;
|
||||||
|
background-color: @pagination-item-disabled-background-color;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: @pagination-disabled-opacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__page {
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__page-desc {
|
||||||
|
flex: 1;
|
||||||
|
height: @pagination-height;
|
||||||
|
color: @pagination-desc-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--simple {
|
||||||
|
.van-pagination__prev,
|
||||||
|
.van-pagination__next {
|
||||||
|
&::after {
|
||||||
|
border-width: @border-width-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
src-next/pagination/test/__snapshots__/demo.spec.js.snap
Normal file
34
src-next/pagination/test/__snapshots__/demo.spec.js.snap
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`renders demo correctly 1`] = `
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<ul class="van-pagination">
|
||||||
|
<li class="van-pagination__item van-pagination__item--disabled van-pagination__prev van-hairline">上一页</li>
|
||||||
|
<li class="van-pagination__item van-pagination__item--active van-pagination__page van-hairline">1</li>
|
||||||
|
<li class="van-pagination__item van-pagination__page van-hairline">2</li>
|
||||||
|
<li class="van-pagination__item van-pagination__page van-hairline">3</li>
|
||||||
|
<li class="van-pagination__item van-pagination__page van-hairline">4</li>
|
||||||
|
<li class="van-pagination__item van-pagination__page van-hairline">5</li>
|
||||||
|
<li class="van-pagination__item van-pagination__next van-hairline">下一页</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ul class="van-pagination van-pagination--simple" size="small">
|
||||||
|
<li class="van-pagination__item van-pagination__item--disabled van-pagination__prev van-hairline">上一页</li>
|
||||||
|
<li class="van-pagination__page-desc">1/12</li>
|
||||||
|
<li class="van-pagination__item van-pagination__next van-hairline">下一页</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ul class="van-pagination">
|
||||||
|
<li class="van-pagination__item van-pagination__item--disabled van-pagination__prev van-hairline">上一页</li>
|
||||||
|
<li class="van-pagination__item van-pagination__item--active van-pagination__page van-hairline">1</li>
|
||||||
|
<li class="van-pagination__item van-pagination__page van-hairline">2</li>
|
||||||
|
<li class="van-pagination__item van-pagination__page van-hairline">3</li>
|
||||||
|
<li class="van-pagination__item van-pagination__page van-hairline">...</li>
|
||||||
|
<li class="van-pagination__item van-pagination__next van-hairline">下一页</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
4
src-next/pagination/test/demo.spec.js
Normal file
4
src-next/pagination/test/demo.spec.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import Demo from '../demo';
|
||||||
|
import { snapshotDemo } from '../../../test/demo';
|
||||||
|
|
||||||
|
snapshotDemo(Demo);
|
@ -298,10 +298,10 @@ module.exports = {
|
|||||||
path: 'nav-bar',
|
path: 'nav-bar',
|
||||||
title: 'NavBar 导航栏',
|
title: 'NavBar 导航栏',
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// path: 'pagination',
|
path: 'pagination',
|
||||||
// title: 'Pagination 分页',
|
title: 'Pagination 分页',
|
||||||
// },
|
},
|
||||||
// {
|
// {
|
||||||
// path: 'sidebar',
|
// path: 'sidebar',
|
||||||
// title: 'Sidebar 侧边导航',
|
// title: 'Sidebar 侧边导航',
|
||||||
@ -632,10 +632,10 @@ module.exports = {
|
|||||||
path: 'nav-bar',
|
path: 'nav-bar',
|
||||||
title: 'NavBar',
|
title: 'NavBar',
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// path: 'pagination',
|
path: 'pagination',
|
||||||
// title: 'Pagination',
|
title: 'Pagination',
|
||||||
// },
|
},
|
||||||
// {
|
// {
|
||||||
// path: 'sidebar',
|
// path: 'sidebar',
|
||||||
// title: 'Sidebar',
|
// title: 'Sidebar',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user