diff --git a/src-next/pagination/README.md b/src-next/pagination/README.md new file mode 100644 index 000000000..42ca945df --- /dev/null +++ b/src-next/pagination/README.md @@ -0,0 +1,67 @@ +# Pagination + +### Install + +```js +import Vue from 'vue'; +import { Pagination } from 'vant'; + +Vue.use(Pagination); +``` + +## Usage + +### Basic Usage + +```html + +``` + +```js +export default { + data() { + return { + currentPage: 1, + }; + }, +}; +``` + +### Simple mode + +```html + +``` + +### Show ellipses + +```html + +``` + +## 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 | - | diff --git a/src-next/pagination/README.zh-CN.md b/src-next/pagination/README.zh-CN.md new file mode 100644 index 000000000..89a5dcb44 --- /dev/null +++ b/src-next/pagination/README.zh-CN.md @@ -0,0 +1,67 @@ +# Pagination 分页 + +### 引入 + +```js +import Vue from 'vue'; +import { Pagination } from 'vant'; + +Vue.use(Pagination); +``` + +## 代码演示 + +### 基础用法 + +```html + +``` + +```js +export default { + data() { + return { + currentPage: 1, + }; + }, +}; +``` + +### 简单模式 + +```html + +``` + +### 显示省略号 + +```html + +``` + +## 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 | 页码改变时触发 | - | diff --git a/src-next/pagination/demo/index.vue b/src-next/pagination/demo/index.vue new file mode 100644 index 000000000..d579d6819 --- /dev/null +++ b/src-next/pagination/demo/index.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/src-next/pagination/index.js b/src-next/pagination/index.js new file mode 100644 index 000000000..0aef4e5f1 --- /dev/null +++ b/src-next/pagination/index.js @@ -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 ( +
    +
  • + {this.prevText || t('prev')} +
  • + {this.pages.map((page) => ( +
  • + {page.text} +
  • + ))} + {simple && ( +
  • + {this.$slots.pageDesc + ? this.$slots.pageDesc() + : `${value}/${this.count}`} +
  • + )} +
  • + {this.nextText || t('next')} +
  • +
+ ); + }, +}); diff --git a/src-next/pagination/index.less b/src-next/pagination/index.less new file mode 100644 index 000000000..862b1677c --- /dev/null +++ b/src-next/pagination/index.less @@ -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; + } + } + } +} diff --git a/src-next/pagination/test/__snapshots__/demo.spec.js.snap b/src-next/pagination/test/__snapshots__/demo.spec.js.snap new file mode 100644 index 000000000..c4e54ef49 --- /dev/null +++ b/src-next/pagination/test/__snapshots__/demo.spec.js.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders demo correctly 1`] = ` +
+
+
    +
  • 上一页
  • +
  • 1
  • +
  • 2
  • +
  • 3
  • +
  • 4
  • +
  • 5
  • +
  • 下一页
  • +
+
+
+
    +
  • 上一页
  • +
  • 1/12
  • +
  • 下一页
  • +
+
+
+
    +
  • 上一页
  • +
  • 1
  • +
  • 2
  • +
  • 3
  • +
  • ...
  • +
  • 下一页
  • +
+
+
+`; diff --git a/src-next/pagination/test/demo.spec.js b/src-next/pagination/test/demo.spec.js new file mode 100644 index 000000000..5c70922b5 --- /dev/null +++ b/src-next/pagination/test/demo.spec.js @@ -0,0 +1,4 @@ +import Demo from '../demo'; +import { snapshotDemo } from '../../../test/demo'; + +snapshotDemo(Demo); diff --git a/vant.config.js b/vant.config.js index d5eaad36d..8bc31a38e 100644 --- a/vant.config.js +++ b/vant.config.js @@ -298,10 +298,10 @@ module.exports = { path: 'nav-bar', title: 'NavBar 导航栏', }, - // { - // path: 'pagination', - // title: 'Pagination 分页', - // }, + { + path: 'pagination', + title: 'Pagination 分页', + }, // { // path: 'sidebar', // title: 'Sidebar 侧边导航', @@ -632,10 +632,10 @@ module.exports = { path: 'nav-bar', title: 'NavBar', }, - // { - // path: 'pagination', - // title: 'Pagination', - // }, + { + path: 'pagination', + title: 'Pagination', + }, // { // path: 'sidebar', // title: 'Sidebar',