tjz
7 years ago
2 changed files with 652 additions and 0 deletions
@ -0,0 +1,465 @@
|
||||
<script> |
||||
import Button from '../button/index' |
||||
import Pager from './Pager' |
||||
import Options from './Options' |
||||
import locale from './locale/zh_CN' |
||||
import KEYCODE from './KeyCode' |
||||
|
||||
// 是否是正整数 |
||||
function isInteger (value) { |
||||
return typeof value === 'number' && |
||||
isFinite(value) && |
||||
Math.floor(value) === value |
||||
} |
||||
|
||||
function defaultItemRender (page, type, element) { |
||||
return element |
||||
} |
||||
|
||||
export default { |
||||
name: 'Pagination', |
||||
props: { |
||||
prefixCls: { |
||||
type: String, |
||||
default: 'ant-pagination', |
||||
}, |
||||
current: { |
||||
type: [Number, String], |
||||
default: 1, |
||||
}, |
||||
total: { |
||||
type: [Number, String], |
||||
default: 0, |
||||
}, |
||||
pageSize: { |
||||
type: [Number, String], |
||||
default: 10, |
||||
}, |
||||
showSizeChanger: { |
||||
type: Boolean, |
||||
default: false, |
||||
}, |
||||
pageSizeOptions: { |
||||
type: Array, |
||||
default: () => ['10', '20', '30', '40'], |
||||
}, |
||||
showQuickJumper: { |
||||
type: Boolean, |
||||
default: false, |
||||
}, |
||||
size: { |
||||
type: String, |
||||
default: '', |
||||
}, |
||||
simple: Boolean, |
||||
showTitle: { |
||||
type: Boolean, |
||||
default: true, |
||||
}, |
||||
showTotal: Function, |
||||
itemRender: { |
||||
type: Function, |
||||
default: defaultItemRender, |
||||
}, |
||||
}, |
||||
model: { |
||||
prop: 'current', |
||||
}, |
||||
data () { |
||||
const { current } = this |
||||
return { |
||||
stateCurrent: +current, |
||||
} |
||||
}, |
||||
methods: { |
||||
isValid (page) { |
||||
return isInteger(page) && page >= 1 && page !== this.stateCurrent |
||||
}, |
||||
calculatePage (p) { |
||||
let pageSize = p |
||||
if (typeof pageSize === 'undefined') { |
||||
pageSize = this.pageSize |
||||
} |
||||
return Math.floor((this.total - 1) / pageSize) + 1 |
||||
}, |
||||
handleGoTO (event) { |
||||
if (event.keyCode === KEYCODE.ENTER || event.type === 'click') { |
||||
this.handleChange(this.stateCurrent) |
||||
} |
||||
}, |
||||
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 stateCurrent = this.stateCurrent |
||||
let value |
||||
|
||||
if (inputValue === '') { |
||||
value = inputValue |
||||
} else if (isNaN(Number(inputValue))) { |
||||
value = stateCurrent |
||||
} else { |
||||
value = Number(inputValue) |
||||
} |
||||
event.target.value = 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) |
||||
} |
||||
}, |
||||
handleChange (p) { |
||||
let page = p |
||||
if (this.isValid(page)) { |
||||
const allTotal = this.calculatePage() |
||||
if (page > allTotal) { |
||||
page = allTotal |
||||
} |
||||
this.stateCurrent = page |
||||
this.$emit('input', page) |
||||
this.$emit('change', page, this.pageSize) |
||||
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()) |
||||
}, |
||||
}, |
||||
watch: { |
||||
current (val) { |
||||
this.stateCurrent = +val |
||||
}, |
||||
}, |
||||
components: { |
||||
vcButton: Button, |
||||
Pager, |
||||
}, |
||||
render () { |
||||
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 |
||||
const pageBufferSize = this.showLessItems ? 1 : 2 |
||||
const { stateCurrent, pageSize } = this |
||||
const smallClass = this.size === 'small' ? 'mini' : '' |
||||
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 = ( |
||||
<li |
||||
title={this.showTitle ? `${locale.jump_to}${stateCurrent}/${allPages}` : null} |
||||
class={`${prefixCls}-simple-pager`} |
||||
> |
||||
<vc-button |
||||
onClick={this.handleGoTO} |
||||
onKeyup={this.handleGoTO} |
||||
> |
||||
{locale.jump_to_confirm} |
||||
</vc-button> |
||||
</li> |
||||
) |
||||
} else { |
||||
gotoButton = goButton |
||||
} |
||||
} |
||||
return ( |
||||
<ul class={`${prefixCls} ${prefixCls}-simple ${smallClass}`}> |
||||
<li |
||||
title={this.showTitle ? locale.prev_page : null} |
||||
onClick={this.prev} |
||||
tabIndex='0' |
||||
onKeypress={this.runIfEnterPrev} |
||||
class={`${this.hasPrev() ? '' : `${prefixCls}-disabled`} ${prefixCls}-prev`} |
||||
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.stateCurrent} |
||||
onKeydown={this.handleKeyDown} |
||||
onKeyup={this.handleKeyUp} |
||||
onChange={this.handleKeyUp} |
||||
size='3' |
||||
/> |
||||
<span class={`${prefixCls}-slash`}>/</span> |
||||
{allPages} |
||||
</li> |
||||
<li |
||||
title={this.showTitle ? locale.next_page : null} |
||||
onClick={this.next} |
||||
tabIndex='0' |
||||
onKeypress={this.runIfEnterNext} |
||||
class={`${this.hasNext() ? '' : `${prefixCls}-disabled`} ${prefixCls}-next`} |
||||
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 |
||||
rootPrefixCls={this.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 |
||||
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> |
||||
) |
||||
lastPager = ( |
||||
<Pager |
||||
rootPrefixCls={prefixCls} |
||||
onClick={this.handleChange} |
||||
onKeypress={this.runIfEnter} |
||||
key={allPages} |
||||
page={allPages} |
||||
active={false} |
||||
showTitle={this.showTitle} |
||||
itemRender={this.itemRender} |
||||
/> |
||||
) |
||||
firstPager = ( |
||||
<Pager |
||||
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 |
||||
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 |
||||
rootPrefixCls={prefixCls} |
||||
onClick={this.handleChange} |
||||
onKeypress={this.runIfEnter} |
||||
key={left} |
||||
page={left} |
||||
className={`${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 |
||||
rootPrefixCls={prefixCls} |
||||
onClick={this.handleChange} |
||||
onKeypress={this.runIfEnter} |
||||
key={right} |
||||
page={right} |
||||
className={`${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) * pageSize + 1, |
||||
stateCurrent * pageSize > this.total ? this.total : stateCurrent * pageSize, |
||||
] |
||||
)} |
||||
</li> |
||||
) |
||||
} |
||||
const prevDisabled = !this.hasPrev() |
||||
const nextDisabled = !this.hasNext() |
||||
return ( |
||||
<ul |
||||
class={`${prefixCls} ${smallClass}`} |
||||
unselectable='unselectable' |
||||
> |
||||
{totalText} |
||||
<li |
||||
title={this.showTitle ? locale.prev_page : null} |
||||
onClick={this.prev} |
||||
tabIndex='0' |
||||
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} |
||||
tabIndex='0' |
||||
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={pageSize} |
||||
pageSizeOptions={this.pageSizeOptions} |
||||
quickGo={this.showQuickJumper ? this.handleChange : null} |
||||
goButton={goButton} |
||||
/> |
||||
</ul> |
||||
) |
||||
}, |
||||
} |
||||
</script> |
@ -0,0 +1,187 @@
|
||||
<script> |
||||
import { cloneElement, isValidElement, getClass, getStyle } from '../_util/vnode' |
||||
import RcTooltip from './src/Tooltip' |
||||
import getPlacements from './placements' |
||||
import PropTypes from '../_util/vue-types' |
||||
import { hasProp, getComponentFromProp } from '../_util/props-util' |
||||
import abstractTooltipProps from './abstractTooltipProps' |
||||
|
||||
const splitObject = (obj, keys) => { |
||||
const picked = {} |
||||
const omited = { ...obj } |
||||
keys.forEach(key => { |
||||
if (obj && key in obj) { |
||||
picked[key] = obj[key] |
||||
delete omited[key] |
||||
} |
||||
}) |
||||
return { picked, omited } |
||||
} |
||||
const props = abstractTooltipProps() |
||||
export default { |
||||
name: 'Tooltip', |
||||
props: { |
||||
...props, |
||||
title: PropTypes.any, |
||||
}, |
||||
model: { |
||||
prop: 'visible', |
||||
event: 'change', |
||||
}, |
||||
data () { |
||||
return { |
||||
sVisible: !!this.$props.visible, |
||||
} |
||||
}, |
||||
watch: { |
||||
visible (val) { |
||||
this.sVisible = val |
||||
}, |
||||
}, |
||||
methods: { |
||||
onVisibleChange (visible) { |
||||
if (!hasProp(this, 'visible')) { |
||||
this.sVisible = this.isNoTitle() ? false : visible |
||||
} |
||||
if (!this.isNoTitle()) { |
||||
this.$emit('change', visible) |
||||
} |
||||
}, |
||||
|
||||
getPopupDomNode () { |
||||
return this.$refs.tooltip.getPopupDomNode() |
||||
}, |
||||
|
||||
getPlacements () { |
||||
const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = this.$props |
||||
return builtinPlacements || getPlacements({ |
||||
arrowPointAtCenter, |
||||
verticalArrowShift: 8, |
||||
autoAdjustOverflow, |
||||
}) |
||||
}, |
||||
|
||||
isHoverTrigger () { |
||||
const { trigger } = this.$props |
||||
if (!trigger || trigger === 'hover') { |
||||
return true |
||||
} |
||||
if (Array.isArray(trigger)) { |
||||
return trigger.indexOf('hover') >= 0 |
||||
} |
||||
return false |
||||
}, |
||||
|
||||
// Fix Tooltip won't hide at disabled button |
||||
// mouse events don't trigger at disabled button in Chrome |
||||
// https://github.com/react-component/tooltip/issues/18 |
||||
getDisabledCompatibleChildren (ele) { |
||||
const isAntBtn = ele.componentOptions && ele.componentOptions.Ctor.options.__ANT_BUTTON |
||||
if (((isAntBtn && ele.componentOptions.propsData.disabled) || (ele.tag === 'button' && ele.data && ele.data.attrs.disabled !== false)) && this.isHoverTrigger()) { |
||||
// Pick some layout related style properties up to span |
||||
// Prevent layout bugs like https://github.com/ant-design/ant-design/issues/5254 |
||||
const { picked, omited } = splitObject( |
||||
getStyle(ele), |
||||
['position', 'left', 'right', 'top', 'bottom', 'float', 'display', 'zIndex'], |
||||
) |
||||
const spanStyle = { |
||||
display: 'inline-block', // default inline-block is important |
||||
...picked, |
||||
cursor: 'not-allowed', |
||||
} |
||||
const buttonStyle = { |
||||
...omited, |
||||
pointerEvents: 'none', |
||||
} |
||||
const spanCls = getClass(ele) |
||||
const child = cloneElement(ele, { |
||||
style: buttonStyle, |
||||
class: null, |
||||
}) |
||||
return ( |
||||
<span style={spanStyle} class={spanCls}> |
||||
{child} |
||||
</span> |
||||
) |
||||
} |
||||
return ele |
||||
}, |
||||
|
||||
isNoTitle () { |
||||
const { $slots, title } = this |
||||
return !$slots.title && !title |
||||
}, |
||||
|
||||
// 动态设置动画点 |
||||
onPopupAlign (domNode, align) { |
||||
const placements = this.getPlacements() |
||||
// 当前返回的位置 |
||||
const placement = Object.keys(placements).filter( |
||||
key => ( |
||||
placements[key].points[0] === align.points[0] && |
||||
placements[key].points[1] === align.points[1] |
||||
), |
||||
)[0] |
||||
if (!placement) { |
||||
return |
||||
} |
||||
// 根据当前坐标设置动画点 |
||||
const rect = domNode.getBoundingClientRect() |
||||
const transformOrigin = { |
||||
top: '50%', |
||||
left: '50%', |
||||
} |
||||
if (placement.indexOf('top') >= 0 || placement.indexOf('Bottom') >= 0) { |
||||
transformOrigin.top = `${rect.height - align.offset[1]}px` |
||||
} else if (placement.indexOf('Top') >= 0 || placement.indexOf('bottom') >= 0) { |
||||
transformOrigin.top = `${-align.offset[1]}px` |
||||
} |
||||
if (placement.indexOf('left') >= 0 || placement.indexOf('Right') >= 0) { |
||||
transformOrigin.left = `${rect.width - align.offset[0]}px` |
||||
} else if (placement.indexOf('right') >= 0 || placement.indexOf('Left') >= 0) { |
||||
transformOrigin.left = `${-align.offset[0]}px` |
||||
} |
||||
domNode.style.transformOrigin = `${transformOrigin.left} ${transformOrigin.top}` |
||||
}, |
||||
}, |
||||
|
||||
render (h) { |
||||
const { $props, $data, $slots } = this |
||||
const { prefixCls, openClassName, getPopupContainer, getTooltipContainer } = $props |
||||
const children = ($slots.default || []).filter(c => c.tag || c.text.trim() !== '')[0] |
||||
let sVisible = $data.sVisible |
||||
// Hide tooltip when there is no title |
||||
if (!hasProp(this, 'visible') && this.isNoTitle()) { |
||||
sVisible = false |
||||
} |
||||
if (!children) { |
||||
return null |
||||
} |
||||
const child = this.getDisabledCompatibleChildren(isValidElement(children) ? children : <span>{children}</span>) |
||||
const childCls = { |
||||
[openClassName || `${prefixCls}-open`]: true, |
||||
} |
||||
const tooltipProps = { |
||||
props: { |
||||
...$props, |
||||
getTooltipContainer: getPopupContainer || getTooltipContainer, |
||||
builtinPlacements: this.getPlacements(), |
||||
visible: sVisible, |
||||
}, |
||||
ref: 'tooltip', |
||||
on: { |
||||
visibleChange: this.onVisibleChange, |
||||
popupAlign: this.onPopupAlign, |
||||
}, |
||||
} |
||||
return ( |
||||
<RcTooltip {...tooltipProps}> |
||||
<template slot='overlay'> |
||||
{getComponentFromProp(this, 'title')} |
||||
</template> |
||||
{sVisible ? cloneElement(child, { class: childCls }) : child} |
||||
</RcTooltip> |
||||
) |
||||
}, |
||||
} |
||||
</script> |
Loading…
Reference in new issue