diff --git a/components/pagination/PropsType.tsx b/components/pagination/PropsType.tsx index bce5d9b1..2f45f076 100644 --- a/components/pagination/PropsType.tsx +++ b/components/pagination/PropsType.tsx @@ -1,22 +1,36 @@ export default interface PropsType { + // 样式前缀 prefixCls?: string; + // 样式名 + className?: string; + // 内联样式 + style?: React.CSSProperties; + // 当前页 value?: number; + // 默认页 defaultValue?: number; + // 禁用 + disabled?: boolean; + // 本地化 + locale?: { [propName: string]: any }; + // 每页条数 pageSize: number; - pageSizeSource?: Array; + // 每页条数下拉框的选项 + pageSizeOptions?: Array; + // 数据总数 total: number; + // 是否展示总数 showTotal?: boolean; - showJumper?: boolean; - showPageSizeSelector?: boolean; - className?: string; - style?: object; - shape: 'rect' | 'radius'; - bordered?: boolean; - isBordered?: boolean; - addonBefore?: React.ReactNode; - addonAfter?: React.ReactNode; - onPageChange: (value: number) => void; - onPageSizeChange: (value: number) => void; - locale?: { [propName: string]: any }; - onChange: (pageInfo: { currentPage: number; pageSize: number }) => void; + // 是否展示跳转 + showQuickJumper?: boolean; + // 是否展示每页条数选择器 + showPageSizeChanger?: boolean; + // 是否简洁分页 + simple?: boolean; + // 分页器尺寸 + size?: 'md' | 'sm'; + // 每页展示条数变更触发的事件 + onPageSizeChange: (pageSize?: number) => void; + // 页面切换和跳转时触发的事件 + onChange: (page?: number) => void; } diff --git a/components/pagination/__tests__/__snapshots__/index.test.jsx.snap b/components/pagination/__tests__/__snapshots__/index.test.jsx.snap index 14aa7886..e0d36dc4 100644 --- a/components/pagination/__tests__/__snapshots__/index.test.jsx.snap +++ b/components/pagination/__tests__/__snapshots__/index.test.jsx.snap @@ -1,420 +1,2191 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Pagination renders Pagination with customized props correctly 1`] = ` -
-
+ -
-
    -
    - addonBefore -
    +
    • - - - - - + + + + + + + + +
    • 1
    • 2
    • 3
    • 4
    • 5
    • 10
    • - - - - - + + + + + + + + +
    • -
      - addonAfter -
      +
      + 跳至 + + 页 +
      +
    -
-
-
+ + + `; -exports[`Pagination renders Pagination with jumper correctly 1`] = ` -
-
+ -
-
    +
    • - - - - - + + + + + + + + +
    • 1
    • 2
    • 3
    • 4
    • 5
    • 10
    • - - - - - + + + + + + + + +
    -
    + + +`; + +exports[`Pagination renders Pagination with pageSize info correctly 1`] = ` + + + +
      - 跳至 -
      - -
      - 页 -
    -
-
-
+ + + + + + + + + + + + +
  • + 1 +
  • +
  • + 2 +
  • +
  • + 3 +
  • +
  • + 4 +
  • +
  • + 5 +
  • +
  • +
  • + 10 +
  • +
  • + + + + + + + + + + + +
  • + + + + `; -exports[`Pagination renders Pagination with total info correctly 1`] = ` -
    -
    + -
    - 共有 100 条记录 第 1 / 10 页 -
    -
    +
  • + + + + + + + + + + + +
  • +
  • + 1 +
  • +
  • + 2 +
  • +
  • + 3 +
  • +
  • + 4 +
  • +
  • + 5 +
  • +
  • +
  • + 10 +
  • +
  • + + + + + + + + + + + +
  • + + + + +`; + +exports[`Pagination renders Pagination with showPageSizeChanger info correctly 1`] = ` + + + -
      +
      • - - - - - + + + + + + + + +
      • 1
      • 2
      • 3
      • 4
      • 5
      • 10
      • - - - - - + + + + + + + + + +
      • +
      • + + + + +
      -
    -
    -
    + + + `; -exports[`Pagination renders normal Pagination correctly 1`] = ` -
    -
    + -
    -
      +
      • + 共有 100 条记录 + 第 1 / 10 页 +
      • +
      • - - - - - + + + + + + + + +
      • 1
      • 2
      • 3
      • 4
      • 5
      • 10
      • + + + + + + + + + + + +
      • +
      + + + +`; + +exports[`Pagination renders Pagination with simple info correctly 1`] = ` + + + +
        +
      • + + + + + + + + + + + +
      • +
      • + + + / + + 10 +
      • +
      • + + + + + + + + + + + +
      • +
      +
      +
      +
      +`; + +exports[`Pagination renders size correctly 1`] = ` + + + +
        + + + +`; + +exports[`Pagination should render page total number 1`] = ` + + + +
          +
        • + + + + + + + + + + + +
        • +
        • + 1 +
        • +
        • + 2 +
        • +
        • + 3 +
        • +
        • + 4 +
        • +
        • + 5 +
        • +
        • +
        • + 50 +
        • +
        • - - - - - + + + + + + + + +
        -
    -
    -
    + + + `; diff --git a/components/pagination/__tests__/index.test.jsx b/components/pagination/__tests__/index.test.jsx index a704e22e..abdbace3 100644 --- a/components/pagination/__tests__/index.test.jsx +++ b/components/pagination/__tests__/index.test.jsx @@ -4,126 +4,131 @@ import toJson from 'enzyme-to-json'; import Pagination from '../index'; describe('Pagination', () => { - it('renders normal Pagination correctly', () => { - const wrapper = render( -
    - -
    , - ); + let wrapper; - expect(toJson(wrapper)).toMatchSnapshot(); + beforeEach(() => { + wrapper = mount(); }); - it('renders Pagination with total info correctly', () => { - const wrapper = render( -
    - -
    , - ); + afterEach(() => { + wrapper && wrapper.unmount(); + wrapper = null; + }); - expect(toJson(wrapper)).toMatchSnapshot(); + it('should receive className prop', () => { + wrapper.setProps({ + className: 'custom', + }); + expect(wrapper.find('.zw-pagination').hasClass('custom')); }); - it('renders Pagination with jumper correctly', () => { - const wrapper = render( -
    - -
    , - ); + it('should receive style prop', () => { + wrapper.setProps({ + style: { + color: 'red', + }, + }); + expect(wrapper.find('.zw-pagination').prop('style').color === 'red'); + }); + + it('renders size correctly', () => { + wrapper.setProps({ + size: 'sm', + }); + expect(wrapper.find('.zw-pagination--sm').length).toEqual(1); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('renders Pagination with customized props correctly', () => { - const wrapper = render( -
    - -
    , - ); - + it('should render page total number', () => { + wrapper.setProps({ + total: 500, + }); expect(toJson(wrapper)).toMatchSnapshot(); }); - it('behaves correctly when changing page', () => { - const onChange = jest.fn(); - const wrapper = mount( -
    - -
    , - ); + it('should render by total', () => { + wrapper.setProps({ + total: 0, + }); + expect(wrapper.find('.zw-pagination__item').hostNodes().length === 0); - wrapper.find('.ui-pagination-item').at(2).simulate('click'); + wrapper.setProps({ + total: 10, + }); + expect(wrapper.find('.zw-pagination__item zw-pagination__item--prev').hostNodes().length === 0); + expect(wrapper.find('.zw-pagination__item zw-pagination__item--next').hostNodes().length === 0); - expect(onChange).toHaveBeenCalledWith(2); + wrapper.setProps({ + total: 100, + }); + expect(wrapper.find('.zw-pagination__item').hostNodes().length === 9); }); - it('behaves correctly when click prev button', () => { - const onChange = jest.fn(); - const wrapper = mount( -
    - -
    , - ); - - wrapper.find('.ui-pagination-item-prev').simulate('click'); - - expect(onChange).toHaveBeenCalledWith(5); + it('should disable the previous button when current is the first page ', () => { + wrapper.setProps({ + current: 1, + }); + expect(wrapper.find('.zw-pagination__item zw-pagination__item--prev zw-pagination__item--disabled')); }); - it('behaves correctly when click next button', () => { - const onChange = jest.fn(); - const wrapper = mount( -
    - -
    , + it('should disable the next button when current is the last page', () => { + wrapper.setProps({ + current: 10, + total: 100, + }); + expect( + wrapper.find('.zw-pagination__item zw-pagination__item--next zw-pagination__item--disabled'), ); - - wrapper.find('.ui-pagination-item-next').simulate('click'); - - expect(onChange).toHaveBeenCalledWith(6); }); - it('behaves correctly when click prev 5 button', () => { + it('should not trigger onChange callback when input some text that can not conver to positive integer or current page', () => { const onChange = jest.fn(); - const wrapper = mount( -
    - -
    , - ); + wrapper.setProps({ + total: 100, + onChange, + }); - wrapper.find('.ui-pagination-item-jump-prev').simulate('click'); + wrapper.find('.zw-pagination__item--prev').simulate('click'); + }); - expect(onChange).toHaveBeenCalledWith(1); + it('should disable the previous button when current is the first page ', () => { + wrapper.setProps({ current: 1 }); + expect(wrapper.find('.zw-pagination__item--prev')); }); - it('behaves correctly when click next 5 button', () => { + it('should not trigger onChange callback when click current page button', () => { const onChange = jest.fn(); - const wrapper = mount( -
    - -
    , - ); + wrapper.setProps({ + total: 100, + onChange, + }); - wrapper.find('.ui-pagination-item-jump-next').simulate('click'); + wrapper + .find('.zw-pagination__item') + .hostNodes() + .at(0) + .simulate('click'); + }); - expect(onChange).toHaveBeenCalledWith(6); + it('renders Pagination with jumper correctly', () => { + wrapper.setProps({ + total: 100, + showQuickJumper: true, + }); + + expect(toJson(wrapper)).toMatchSnapshot(); }); it('behaves correctly when change page with jumper', () => { const onChange = jest.fn(); - const wrapper = mount( -
    - -
    , - ); + wrapper.setProps({ + total: 100, + showQuickJumper: true, + onChange, + }); - wrapper.find('.ui-pagination-jumper input').simulate('keydown', { + wrapper.find('.zw-pagination__options--jumper input').simulate('keydown', { keyCode: 13, target: { value: 6, @@ -132,12 +137,58 @@ describe('Pagination', () => { expect(onChange).toHaveBeenCalledWith(6); }); - it('behaves correctly when receiving new value', () => { - const wrapper = mount( - , - ); + it('renders Pagination with pageSize info correctly', () => { + wrapper.setProps({ + total: 100, + pageSize: 10, + }); + + expect(toJson(wrapper)).toMatchSnapshot(); + }); + + it('renders Pagination with simple info correctly', () => { + wrapper.setProps({ + total: 100, + simple: true, + }); + + expect(toJson(wrapper)).toMatchSnapshot(); + }); + + it('renders Pagination with pageSizeOptions info correctly', () => { + wrapper.setProps({ + total: 100, + pageSizeOptions: [10, 20, 30, 40, 50], + }); + + expect(toJson(wrapper)).toMatchSnapshot(); + }); + + it('renders Pagination with showTotal info correctly', () => { + wrapper.setProps({ + total: 100, + showTotal: true, + }); + + expect(toJson(wrapper)).toMatchSnapshot(); + }); - wrapper.setProps({ value: 1 }); - expect(wrapper.find('.ui-pagination-item').at(1).hasClass('ui-pagination-item-active')).toBeTruthy(); + it('renders Pagination with showPageSizeChanger info correctly', () => { + wrapper.setProps({ + total: 100, + showPageSizeChanger: true, + }); + + expect(toJson(wrapper)).toMatchSnapshot(); }); + + it('renders Pagination with onPageSizeChange info correctly', () => { + wrapper.setProps({ + total: 100, + onPageSizeChange: jest.fn(), + }); + + expect(toJson(wrapper)).toMatchSnapshot(); + }); + }); diff --git a/components/pagination/index.tsx b/components/pagination/index.tsx index e797a46e..9185651c 100644 --- a/components/pagination/index.tsx +++ b/components/pagination/index.tsx @@ -1,27 +1,34 @@ import React, { Component } from 'react'; import classnames from 'classnames'; import Select from '../select'; -import Input from '../input'; import Icon from '../icon'; import PropsType from './PropsType'; import format from '../locale-provider/format'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; -const noop = () => { }; +const noop = () => {}; + class Pagination extends Component { static defaultProps = { - prefixCls: 'ui-pagination', + // 样式前缀 + prefixCls: 'zw-pagination', + // 默认页 defaultValue: 1, - isBordered: false, - isRadius: false, + // 数据总数 total: 0, + // 每页条数 pageSize: 10, - pageSizeSource: [10, 20, 30, 40, 50], + // 每页条数下拉框的选项 + pageSizeOptions: [10, 20, 30, 40, 50], + // 是否展示总数 showTotal: false, - showJumper: false, - showPageSizeSelector: false, - onPageChange: noop, + // 是否展示跳转 + showQuickJumper: false, + // 是否展示每页条数选择器 + showPageSizeChanger: false, + // 每页展示条数变更触发的事件 onPageSizeChange: noop, + // 页面切换和跳转时触发的事件 onChange: noop, }; @@ -29,26 +36,30 @@ class Pagination extends Component { super(props); this.state = { value: props.value || props.defaultValue, + currentInputValue: props.value || props.defaultValue, }; } - componentWillReceiveProps(nextProps) { + static getDerivedStateFromProps(nextProps) { if ('value' in nextProps) { - this.setState({ + return { value: nextProps.value, - }); + }; } + return null; } - getPagerList = () => { - const { - total, - addonBefore, - addonAfter, - pageSize, - } = this.props; + /** + * 根据总数计算分页数 + * @return {number} 返回分页数 + */ + getPageSize = () => { + const { total, pageSize } = this.props; + return Math.ceil(total / pageSize); + }; - const pageCount = Math.ceil(total / pageSize); + getPagerList = () => { + const pageCount = this.getPageSize(); const pagerList: JSX.Element[] = []; let { value } = this.state; value = value < 1 ? 1 : value; @@ -87,13 +98,39 @@ class Pagination extends Component { pagerList.push(this.nextPager(value, pageCount)); } - if (addonBefore) { - pagerList.unshift(this.renderAddonBefore(addonBefore)); - } - if (addonAfter) { - pagerList.push(this.renderAddonAfter(addonAfter)); - } + return pagerList; + }; + + renderSimple = () => { + const { prefixCls, disabled } = this.props; + const pagerList: JSX.Element[] = []; + const pageCount = this.getPageSize(); + const { currentInputValue } = this.state; + let { value } = this.state; + value = value > pageCount ? pageCount : value; + + pagerList.push( +
  • + + + {pageCount} +
  • , + ); + pagerList.unshift(this.prevPager(value)); + pagerList.push(this.nextPager(value, pageCount)); return pagerList; }; @@ -103,7 +140,7 @@ class Pagination extends Component {
  • this._onPagerClick(1)} > 1 @@ -111,109 +148,156 @@ class Pagination extends Component { ); }; - lastPager = (pageCount) => { + lastPager = (pageSize: number) => { const { prefixCls, locale } = this.props; return (
  • this._onPagerClick(pageCount)} + className={`${prefixCls}__item`} + onClick={() => this._onPagerClick(pageSize)} > - {pageCount} + {pageSize}
  • ); }; - prevPager = (current) => { + prevPager = (page: number) => { const { prefixCls, locale } = this.props; + const cls = classnames({ + [`${prefixCls}__item`]: true, + [`${prefixCls}__item--prev`]: true, + [`${prefixCls}__item--disabled`]: Number(page) === 1, + }); + return (
  • current > 1 && this._onPagerClick(current - 1)} + className={classnames(cls)} + onClick={() => page > 1 && this._onPagerClick(page - 1)} > - +
  • ); }; - nextPager = (current, pageCount) => { + nextPager = (page: number, pageSize: number) => { const { prefixCls, locale } = this.props; + const cls = classnames({ + [`${prefixCls}__item`]: true, + [`${prefixCls}__item--next`]: true, + [`${prefixCls}__item--disabled`]: Number(page) === pageSize, + }); + return (
  • current < pageCount && this._onPagerClick(current + 1)} + className={cls} + onClick={() => page < pageSize && this._onPagerClick(page + 1)} > - +
  • ); }; - jumpPrev = (current) => { + jumpPrev = (page: number) => { const { prefixCls, locale } = this.props; + const cls = classnames({ + [`${prefixCls}__item`]: true, + [`${prefixCls}__item--ellipsis`]: true, + }); + return (
  • this._onPagerClick(current - 5)} + className={cls} + onClick={() => this._onPagerClick(page - 5)} /> ); }; - jumpNext = (current) => { + jumpNext = (page: number) => { const { prefixCls, locale } = this.props; + const cls = classnames({ + [`${prefixCls}__item`]: true, + [`${prefixCls}__item--ellipsis`]: true, + }); + return (
  • this._onPagerClick(current + 5)} + className={cls} + onClick={() => this._onPagerClick(page + 5)} /> ); }; - _onPagerClick(value) { - const { onPageChange, onChange, pageSize } = this.props; + /** + * 指定跳转页码 + */ + handleJumpChange = ({ target: { value } }) => { + const sValue = parseInt(value, 10); + if (typeof sValue !== 'number') { + this.setState({ currentInputValue: '' }); + return; + } + + this.setState({ currentInputValue: value }); + }; + + /** + * 按下回车键,改变分页 + */ + handleJumpKeyDown = ({ keyCode, target: { value } }: any) => { + if (keyCode === 13) { + let sValue = parseInt(value, 10); + if (typeof sValue !== 'number') { + return; + } + + const pageCount = this.getPageSize(); + if (sValue < 1) { + sValue = 1; + } + + if (sValue > pageCount) { + sValue = pageCount; + } + + this._onPagerClick(sValue); + } + }; + + _onPagerClick(value: number) { + const { onChange, disabled } = this.props; + if (disabled) { + return false; + } this.setState({ value, + currentInputValue: value, }); - if (onPageChange !== noop) { - onPageChange(value); - return; - } - onChange({ - pageSize, - currentPage: value, - }); + + onChange(value); } - renderPager = (i, current) => { - const { prefixCls } = this.props; + renderPager = (i: number, page: number) => { + const { prefixCls, disabled } = this.props; + const cls = classnames({ + [`${prefixCls}__item`]: true, + [`${prefixCls}__item--active`]: page === i && !disabled, + }); + return (
  • this._onPagerClick(i)} > {i} @@ -221,144 +305,113 @@ class Pagination extends Component { ); }; - renderAddonBefore = (addonBefore) => { - const { prefixCls } = this.props; - return ( -
    - {addonBefore} -
    - ); - }; - - renderAddonAfter = (addonAfter) => { - const { prefixCls } = this.props; - return ( -
    - {addonAfter} -
    - ); - }; - renderTotal = () => { const { total, prefixCls, locale, pageSize } = this.props; + const cls = classnames({ + [`${prefixCls}__total`]: true, + }); const { value } = this.state; return ( -
    +
  • {format(locale!.total, { total, })} {format(locale!.current, { current: `${value} / ${Math.ceil(total / pageSize)}`, })} - +
  • ); }; renderPageSizeSelector = () => { - const { prefixCls, onPageSizeChange, onChange, locale, pageSize } = this.props; - let { pageSizeSource } = this.props; - let defaultPageSize = pageSizeSource && pageSizeSource.length > 0 && pageSizeSource[0]; + const { + prefixCls, + onPageSizeChange, + onChange, + locale, + pageSize, + disabled, + } = this.props; + let { pageSizeOptions } = this.props; + let defaultPageSize = pageSizeOptions && pageSizeOptions.length > 0 && pageSizeOptions[0]; - if (!pageSizeSource) { - pageSizeSource = [10, 20, 30, 40, 50]; + if (!pageSizeOptions) { + pageSizeOptions = [10, 20, 30, 40, 50]; defaultPageSize = 10; } return ( -
    +
  • -
  • + ); }; renderJumper = () => { - const { shape, total, prefixCls, locale, pageSize } = this.props; + const { prefixCls, locale } = this.props; return ( -
    - {locale!.goto} - ) => { - const { value } = e.target as HTMLInputElement; - if (e.keyCode === 13) { - let sValue = parseInt(value, 10); - // eslint-disable-next-line - if (!sValue || isNaN(sValue)) { return; } - - if (sValue < 1) { sValue = 1; } - const pageCount = Math.ceil(total / pageSize); - if (sValue > pageCount) { sValue = pageCount; } - - this._onPagerClick(sValue); - } - }} - /> - {locale!.pageClassifier} -
    +
  • +
    + {locale!.goto} + + {locale!.pageClassifier} +
    +
  • ); }; render() { const { prefixCls, - isBordered, - shape, className, showTotal, - showJumper, - showPageSizeSelector, + showQuickJumper, + showPageSizeChanger, + simple, + size, + disabled, style, } = this.props; const cls = classnames({ [prefixCls!]: true, - bordered: 'bordered' in this.props || isBordered, - [`shape-${shape}`]: !!shape, + [`${prefixCls}--disabled`]: !!disabled, + [`${prefixCls}--${size}`]: !!size, + [`${prefixCls}--simple`]: simple, [className!]: !!className, }); return ( -
    +
      {showTotal && this.renderTotal()} -
      -
        - {this.getPagerList()} -
      - {showPageSizeSelector && this.renderPageSizeSelector()} - {showJumper && this.renderJumper()} -
      -
    + {simple ? this.renderSimple() : this.getPagerList()} + {showPageSizeChanger && this.renderPageSizeSelector()} + {showQuickJumper && this.renderJumper()} + ); } } diff --git a/components/pagination/pagination.md b/components/pagination/pagination.md index e144028a..2ab41bf9 100644 --- a/components/pagination/pagination.md +++ b/components/pagination/pagination.md @@ -1,209 +1,174 @@ -## Pagination 分页 -一般配合Table组件做分页展示。 +# Pagination 分页 -### 基础用法 +采用分页的形式分隔长列表,每次只加载一个页面。 + +## 基础用法 最简单的分页。 -:::demo 只需要设置`total`,`pageSize`默认为10。 +```jsx +import { Pagination } from 'zarm-web'; -```js +class Demo extends React.Component { render() { - return ( -
    - -
    - ) + return ; } +} + +ReactDOM.render(, mountNode); ``` -::: -### 显示总数 +## 显示总数 -添加`showToal`属性即可。 +通过设置 showTotal 展示总共有多少数据。 -:::demo +```jsx +import { Pagination } from 'zarm-web'; -```js +class Demo extends React.Component { render() { - return ( -
    - -
    - ) + return ; } +} + +ReactDOM.render(, mountNode); ``` -::: -### 显示跳转 +## 显示跳转 -添加`showJumper`属性即可。 +添加`showQuickJumper`属性即可。 -:::demo +```jsx +import { Pagination } from 'zarm-web'; -```js +class Demo extends React.Component { render() { - return ( -
    - -
    - ) + return ; } +} + +ReactDOM.render(, mountNode); ``` -::: -### 显示每页条数选择器 +## 显示每页条数选择器 -添加`showPageSizeSelector`属性即可。 +添加`showPageSizeChanger`属性即可。 -:::demo +```jsx +import { Pagination } from 'zarm-web'; -```js +class Demo extends React.Component { render() { - return ( -
    - -
    - ) + return ; } +} + +ReactDOM.render(, mountNode); ``` -::: -### 设置页面下拉框的数据源 +## 指定每页可以显示多少条 -添加`pageSizeSource`属性即可。 +添加`pageSizeOptions`属性即可。 -:::demo +```jsx +import { Pagination } from 'zarm-web'; -```js +class Demo extends React.Component { render() { return ( -
    - -
    - ) + + ); } +} + +ReactDOM.render(, mountNode); ``` -::: -### 事件回调 +## 小型分页 -通过`onPageChange`监听翻页和跳转,通过`onPageSizeChange`监听每页条数变更事件。 +占用更小位置的分页 -:::demo +```jsx +import { Pagination } from 'zarm-web'; -```js - constructor(props) { - super(props); - this.state = { - pageSize: 10 - } - } +class Demo extends React.Component { render() { - const { pageSize } = this.state; - return ( -
    - { - alert('翻页到:' + page); - }} - onPageSizeChange={(pageSize) => { - alert('每页展示:' + pageSize); - this.setState({ - pageSize - }); - }} - /> -
    - ) + return ; } -``` -::: - -### 事件回调 +} -通过`onChange`兼容`onPageSizeChange`与`onPageChange`,监听翻页和跳转以及每页条数变更事件。 +ReactDOM.render(, mountNode); +``` +## 迷你 -:::demo +```jsx +import { Pagination } from 'zarm-web'; -```js - constructor(props) { - super(props); - this.state = { - pageSize: 10, - currentPage: 1, - } - } +class Demo extends React.Component { render() { - const { pageSize, currentPage } = this.state; - return ( -
    - { - alert('每页展示:' + pageSize + ',且当前页是' + currentPage); - this.setState({ - pageSize, - currentPage, - }); - }} - /> -
    - ) + return ; } +} + +ReactDOM.render(, mountNode); ``` -::: -### 更多设置 +## 事件回调 -通过`radius`,`bordered`设置样式。 +通过`onChange`监听翻页和跳转,通过`onPageSizeChange`监听每页条数变更事件。 -:::demo +```jsx +import { Pagination } from 'zarm-web'; -```js +class Demo extends React.Component { + constructor(props) { + super(props); + this.state = { + pageSize: 10 + }; + } render() { + const { pageSize } = this.state; return ( -
    - -
    - ) + { + alert('翻页到:' + page); + }} + onPageSizeChange={pageSize => { + alert('每页展示:' + pageSize); + this.setState({ + pageSize + }); + }} + /> + ); } +} + +ReactDOM.render(, mountNode); ``` -::: - -### Attributes -| 参数 | 说明 | 类型 | 可选值 | 默认值 | -|---------- |-------- |---------- |------------- |-------- | -| value | 当前页 | number | - | - | -| defaultValue | 默认页 | number | - | 1 | -| total | 总数 | number | — | 0 | -| pageSize | 每页条数 | number | — | 10 | -| pageSizeSource |页数下拉框的数据源 | number[] | - | [10,20,30,40,50] -| showTotal | 是否展示总数 | boolean | — | false | -| showJumper | 是否展示跳转 | boolean | — | false | -| showPageSizeSelector | 是否展示每页条数选择器 | boolean | — | false | -| radius | 是否圆角 | boolean | — | false | -| bordered | 是否有边框 | boolean | — | false | - - -### Events -| 事件名称 | 说明 | 回调参数 | -|---------- |-------- |---------- | -| onPageChange | 翻页或跳转触发的事件 | page | -| onPageSizeChange | 每页展示条数变更触发的事件 | pageSize | -| onChange |监听翻页和跳转以及每页条数变更事件。 | {pageSize, currentPage} | + +## API + +| 属性 | 类型 | 默认值 | 说明 | +| ------------------- | --------------------------- | ---------------- | -------------------------- | +| value | number | - | 当前页 | +| defaultValue | number | 1 | 默认页 | +| simple | boolean | false | 是否简洁分页 | +| size | 'md' or 'sm' | md | 分页器尺寸 | +| total | number | 0 | 数据总数 | +| pageSize | number | 10 | 每页条数 | +| pageSizeOptions | number[] | [10,20,30,40,50] | 每页条数下拉框的选项 | +| showTotal | boolean | false | 是否展示总数 | +| showQuickJumper | boolean | false | 是否展示跳转 | +| showPageSizeChanger | boolean | false | 是否展示每页条数选择器 | +| onPageSizeChange | (pageSize?: number) => void | - | 每页展示条数变更触发的事件 | +| onChange | (page?: number) => void | - | 页面切换和跳转时触发的事件 | diff --git a/components/pagination/style/component.scss b/components/pagination/style/component.scss deleted file mode 100644 index c06db2ee..00000000 --- a/components/pagination/style/component.scss +++ /dev/null @@ -1,141 +0,0 @@ -.ui-pagination { - &:after { - content: " "; - display: block; - height: 0; - clear: both; - overflow: hidden; - visibility: hidden; - } - - &.bordered { - .ui-pagination-item { - border: 1px solid #d9d9d9; - margin-right: 8px; - - &:hover { - border-color: #2db7f5; - } - - &.ui-pagination-item-jump-prev, - &.ui-pagination-item-jump-next { - border-width: 0; - } - - &.ui-pagination-item-active { - border-color: #2db7f5; - } - - &.ui-pagination-item-disabled { - &:hover { - border-color: #d9d9d9; - } - } - } - } - - &.shape-radius { - .ui-pagination-item { - border-radius: $base-radius; - } - } - - &-total { - float: left; - line-height: 28px; - padding-right: 4px; - color: #999; - } - - &-pagers { - float: right; - - & > ul { - float: left; - margin: 0; - padding: 0; - } - } - - &-size, - &-jumper { - float: left; - margin-left: 6px; - line-height: 28px; - - .ui-selectm, - .ui-dropdown-trigger-box { - vertical-align: inherit; - } - } -} - -.ui-pagination-item { - float: left; - // display: inline-block; - border: 1px solid transparent; - min-width: 28px; - padding: 0 6px; - height: 28px; - line-height: 26px; - text-align: center; - list-style: none; - background-color: #fff; - margin-right: 4px; - font-family: Arial; - user-select: none; - cursor: pointer; - - &.ui-pagination-item-prev, - &.ui-pagination-item-next { - color: #ccc; - } - - &.ui-pagination-item-jump-prev, - &.ui-pagination-item-jump-next { - &:after { - content: "\2022\2022\2022"; - display: block; - letter-spacing: 2px; - color: #ccc; - text-align: center; - } - } - - &:hover { - color: #2db7f5; - - &.ui-pagination-jump-prev, - &.ui-pagination-jump-next { - &:after { - color: #2db7f5; - } - } - } - - &.ui-pagination-item-disabled { - cursor: not-allowed; - opacity: 0.7; - - &:hover { - color: #ccc; - } - } - - &.ui-pagination-item-active { - background-color: #2db7f5; - color: #fff; - } -} - -.ui-pagination-addon-before { - float: left; - margin-right: 15px; - line-height: 28px; -} - -.ui-pagination-addon-after { - float: left; - margin-left: 15px; - line-height: 28px; -} diff --git a/components/pagination/style/index.scss b/components/pagination/style/index.scss index 87ed5f3d..36cb60e0 100644 --- a/components/pagination/style/index.scss +++ b/components/pagination/style/index.scss @@ -1,2 +1,76 @@ -@import '../../style/themes/default'; -@import './component'; +@import "../../style/core/index"; +@import "mixins"; + +@include b(pagination) { + margin: 0; + padding: 0; + @include clearfix(); + + @include e(item) { + @include pagination-item( + var(--pagination-color), + var(--pagination-default-bg-color), + var(--pagination-default-hover-color), + var(--pagination-default-active-background), + var(--pagination-font-size-md), + var(--pagination-opacity), + var(--pagination-height-md), + var(--radius-md) + ); + } + + @include e(input) { + @include pagination-input( + var(--pagination-height-md), + var(--pagination-height-md), + var(--radius-md), + var(--pagination-default-bg-color) + ); + } + + @include e(total) { + @include pagination-total(); + } + + @include e(options) { + @include pagination-options( + var(--pagination-default-bg-color), + var(--radius-md), + var(--pagination-height-md) + ); + } + + @include m(sm) { + @include pagination-size( + var(--pagination-default-active-background), + var(--pagination-font-size-sm), + var(--pagination-height-sm) + ); + } + + @include m(simple) { + @include pagination-simple(var(--pagination-height-sm)); + } + + @include m(disabled) { + background-color: var(--opacity-disabled); + color: var(--color-text); + opacity: var(--opacity-disabled); + cursor: not-allowed; + + &:active, + &:focus, + &:hover, + &:visited { + background-color: var(--opacity-disabled); + color: var(--color-text); + } + + @include e(item) { + cursor: not-allowed; + &:hover { + color: inherit; + } + } + } +} diff --git a/components/pagination/style/index.tsx b/components/pagination/style/index.tsx index 6054c0b4..8a3ccd84 100644 --- a/components/pagination/style/index.tsx +++ b/components/pagination/style/index.tsx @@ -1,5 +1,4 @@ import '../../style'; -import '../../input/style'; import '../../select/style'; -import '../../button/style'; +import '../../icon/style'; import './index.scss'; diff --git a/components/pagination/style/mixins.scss b/components/pagination/style/mixins.scss new file mode 100644 index 00000000..42733a30 --- /dev/null +++ b/components/pagination/style/mixins.scss @@ -0,0 +1,156 @@ +@mixin pagination-item( + $color, + $background, + $hover-color, + $active-background, + $font-size, + $disabled-opacity, + $height, + $radius +) { + min-width: $height; + height: $height; + line-height: $height; + padding: 0 6px; + margin-right: 8px; + display: inline-block; + text-align: center; + list-style: none; + user-select: none; + cursor: pointer; + vertical-align: middle; + border: 1px solid transparent; + background-color: $background; + border-radius: $radius; + font-size: $font-size; + + &:hover { + color: $hover-color; + } + + @include m(disabled) { + &, + &:active, + &:hover, + &:focus, + &:visited { + color: var(--color-text-disabled); + cursor: not-allowed; + } + } + + @include m(active) { + background-color: var(--pagination-default-active-background); + + &, + &:hover { + color: #fff; + } + } + + @include m(ellipsis) { + background-color: transparent; + + &:after { + content: "\2022\2022\2022"; + display: block; + letter-spacing: 2px; + color: #ccc; + text-align: center; + font-size: 12px; + } + } + + @include m(icon) { + font-size: 14px; + } +} + +@mixin pagination-total() { + display: inline-block; + vertical-align: middle; + padding-right: 8px; +} + +@mixin pagination-options($background, $radius, $height) { + display: inline-block; + margin-left: 8px; + vertical-align: middle; + + // select + // @include m(changer) { + // } + + @include m(jumper) { + display: inline-block; + } + + @include m(slash) { + margin: 0 16px 0 16px; + } +} + +@mixin pagination-size($active-background, $font-size, $height) { + @include e(item) { + background-color: transparent; + min-width: $height; + height: $height; + line-height: $height; + margin-right: 6px; + display: inline-flex; + align-items: center; + } + + @include e(item--icon) { + font-size: $font-size; + } + + @include e(item--active) { + background-color: var(--pagination-default-active-background); + + &, + &:hover { + color: #fff; + } + } + + @include e(total) { + height: $height; + line-height: $height; + } + + @include e(input) { + height: $height; + } +} + +@mixin pagination-simple($height) { + @include e(item) { + margin: 0; + background-color: transparent; + } + + @include e(pager) { + &:hover { + color: inherit; + cursor: inherit; + } + } + + @include e(input) { + height: $height; + margin: 0; + } +} + +@mixin pagination-input($width, $height, $radius, $background) { + position: relative; + display: inline-block; + width: 48px; + height: $height; + margin: 0 8px; + text-align: center; + border-radius: $radius; + border: 1px solid $background; + background-color: $background; +} diff --git a/components/style/themes/variable.scss b/components/style/themes/variable.scss index b9ac1cbb..091a143d 100644 --- a/components/style/themes/variable.scss +++ b/components/style/themes/variable.scss @@ -252,4 +252,30 @@ --steps-status-error: var(--theme-danger); --steps-icon-size: 28px; --steps-content-width: 140px; + // Avatar + --avatar-border-radius: 50%; + --avatar-fontSize: 14px; + --avatar-width-md: 40px; + --avatar-height-md: 40px; + --avatar-width-xl: 72px; + --avatar-height-xl: 72px; + --avatar-width-lg: 48px; + --avatar-height-lg: 48px; + --avatar-width-sm: 32px; + --avatar-height-sm: 32px; + --avatar-width-xs: 24px; + --avatar-height-xs: 24px; + --avatar-default-color: #fff; + --avatar-default-bg-color: #ccc; + + // pagination + --pagination-color: #343434; + --pagination-default-hover-color: var(--theme-primary); + --pagination-default-bg-color: #fafafa; + --pagination-default-active-background: var(--theme-primary); + --pagination-font-size-md: 14px; + --pagination-font-size-sm: 12px; + --pagination-height-md: 32px; + --pagination-height-sm: 24px; + --pagination-opacity: var(--opacity-disabled); }