feat(Pagination): refactor DOM to improve a11y (#9901)

This commit is contained in:
neverland 2021-11-19 10:52:16 +08:00 committed by GitHub
parent 42a5f79c2c
commit 3885fd00ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 336 additions and 232 deletions

View File

@ -1,10 +1,11 @@
import { computed, watch, defineComponent, ExtractPropTypes } from 'vue';
import { computed, watchEffect, defineComponent, ExtractPropTypes } from 'vue';
import {
BORDER,
clamp,
makeStringProp,
makeNumberProp,
makeNumericProp,
createNamespace,
BORDER_SURROUND,
} from '../utils';
const [name, bem, t] = createNamespace('pagination');
@ -57,10 +58,6 @@ export default defineComponent({
const showPageSize = +props.showPageSize;
const { modelValue, forceEllipses } = props;
if (props.mode !== 'multi') {
return items;
}
// Default page limits
let startPage = 1;
let endPage = pageCount;
@ -101,85 +98,96 @@ export default defineComponent({
return items;
});
const select = (page: number, emitChange?: boolean) => {
page = Math.min(count.value, Math.max(1, page));
const updateModelValue = (value: number, emitChange?: boolean) => {
value = clamp(value, 1, count.value);
if (props.modelValue !== page) {
emit('update:modelValue', page);
if (props.modelValue !== value) {
emit('update:modelValue', value);
if (emitChange) {
emit('change', page);
emit('change', value);
}
}
};
watch(
() => props.modelValue,
(value) => {
select(value);
},
{ immediate: true }
// format modelValue
watchEffect(() => updateModelValue(props.modelValue));
const renderDesc = () => (
<li class={bem('page-desc')}>
{slots.pageDesc
? slots.pageDesc()
: `${props.modelValue}/${count.value}`}
</li>
);
const renderDesc = () => {
if (props.mode !== 'multi') {
return (
<li class={bem('page-desc')}>
{slots.pageDesc
? slots.pageDesc()
: `${props.modelValue}/${count.value}`}
</li>
);
}
};
return () => {
const value = props.modelValue;
const simple = props.mode !== 'multi';
const onSelect = (value: number) => () => select(value, true);
const renderPrevButton = () => {
const { mode, modelValue } = props;
const slot = slots['prev-text'];
const disabled = modelValue === 1;
return (
<ul class={bem({ simple })}>
<li
class={[
bem('item', { disabled: value === 1 }),
bem('prev'),
BORDER,
]}
onClick={onSelect(value - 1)}
<li
class={[
bem('item', { disabled, border: mode === 'simple', prev: true }),
BORDER_SURROUND,
]}
>
<button
disabled={disabled}
onClick={() => updateModelValue(modelValue - 1)}
>
{slots['prev-text']
? slots['prev-text']()
: props.prevText || t('prev')}
</li>
{pages.value.map((page) => (
<li
class={[
bem('item', { active: page.active }),
bem('page'),
BORDER,
]}
onClick={onSelect(page.number)}
>
{slots.page ? slots.page(page) : page.text}
</li>
))}
{renderDesc()}
<li
class={[
bem('item', { disabled: value === count.value }),
bem('next'),
BORDER,
]}
onClick={onSelect(value + 1)}
>
{slots['next-text']
? slots['next-text']()
: props.nextText || t('next')}
</li>
</ul>
{slot ? slot() : props.prevText || t('prev')}
</button>
</li>
);
};
const renderNextButton = () => {
const { mode, modelValue } = props;
const slot = slots['next-text'];
const disabled = modelValue === count.value;
return (
<li
class={[
bem('item', { disabled, border: mode === 'simple', next: true }),
BORDER_SURROUND,
]}
>
<button
disabled={disabled}
onClick={() => updateModelValue(modelValue + 1)}
>
{slot ? slot() : props.nextText || t('next')}
</button>
</li>
);
};
const renderPages = () =>
pages.value.map((page) => (
<li
class={[
bem('item', { active: page.active, page: true }),
BORDER_SURROUND,
]}
>
<button
aria-current={page.active || undefined}
onClick={() => updateModelValue(page.number)}
>
{slots.page ? slots.page(page) : page.text}
</button>
</li>
));
return () => (
<nav role="navigation" class={bem()}>
<ul class={bem('items')}>
{renderPrevButton()}
{props.mode === 'simple' ? renderDesc() : renderPages()}
{renderNextButton()}
</ul>
</nav>
);
},
});

View File

@ -13,9 +13,12 @@
}
.van-pagination {
display: flex;
font-size: var(--van-pagination-font-size);
&__items {
display: flex;
}
&__item,
&__page-desc {
display: flex;
@ -33,58 +36,56 @@
cursor: pointer;
user-select: none;
button {
flex: 1;
height: 100%;
border: none;
padding: 0;
background: transparent;
&[disabled] {
cursor: not-allowed;
}
}
&:active {
color: var(--van-white);
background-color: var(--van-pagination-item-default-color);
}
&::after {
border-width: var(--van-border-width-base) 0 var(--van-border-width-base)
var(--van-border-width-base);
}
&:last-child::after {
border-right-width: var(--van-border-width-base);
&:not(:last-child)::after {
border-right-width: 0;
}
&--active {
color: var(--van-white);
background-color: var(--van-pagination-item-default-color);
}
}
&__prev,
&__next {
padding: 0 var(--van-padding-base);
cursor: pointer;
}
&--page {
flex-grow: 0;
}
&__item--disabled {
&,
&:active {
&--prev,
&--next {
padding: 0 var(--van-padding-base);
cursor: pointer;
}
&--border::after {
border-width: var(--van-border-width-base);
}
&--disabled {
color: var(--van-pagination-item-disabled-color);
background-color: var(--van-pagination-item-disabled-background-color);
cursor: not-allowed;
opacity: var(--van-pagination-disabled-opacity);
}
}
&__page {
flex-grow: 0;
}
&__page-desc {
flex: 1;
height: var(--van-pagination-height);
color: var(--van-pagination-desc-color);
}
&--simple {
.van-pagination__prev,
.van-pagination__next {
&::after {
border-width: var(--van-border-width-base);
}
}
}
}

View File

@ -2,92 +2,151 @@
exports[`should render demo and match snapshot 1`] = `
<div>
<ul class="van-pagination">
<li class="van-pagination__item van-pagination__item--disabled van-pagination__prev van-hairline">
Prev
</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">
Next
</li>
</ul>
</div>
<div>
<ul class="van-pagination van-pagination--simple"
size="small"
<nav role="navigation"
class="van-pagination"
>
<li class="van-pagination__item van-pagination__item--disabled van-pagination__prev van-hairline">
Prev
</li>
<li class="van-pagination__page-desc">
1/12
</li>
<li class="van-pagination__item van-pagination__next van-hairline">
Next
</li>
</ul>
<ul class="van-pagination__items">
<li class="van-pagination__item van-pagination__item--disabled van-pagination__item--prev van-hairline--surround">
<button disabled>
Prev
</button>
</li>
<li class="van-pagination__item van-pagination__item--active van-pagination__item--page van-hairline--surround">
<button aria-current="true">
1
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
2
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
3
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
4
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
5
</button>
</li>
<li class="van-pagination__item van-pagination__item--next van-hairline--surround">
<button>
Next
</button>
</li>
</ul>
</nav>
</div>
<div>
<ul class="van-pagination">
<li class="van-pagination__item van-pagination__item--disabled van-pagination__prev van-hairline">
Prev
</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">
Next
</li>
</ul>
<nav role="navigation"
class="van-pagination"
size="small"
>
<ul class="van-pagination__items">
<li class="van-pagination__item van-pagination__item--disabled van-pagination__item--border van-pagination__item--prev van-hairline--surround">
<button disabled>
Prev
</button>
</li>
<li class="van-pagination__page-desc">
1/12
</li>
<li class="van-pagination__item van-pagination__item--border van-pagination__item--next van-hairline--surround">
<button>
Next
</button>
</li>
</ul>
</nav>
</div>
<div>
<ul class="van-pagination">
<li class="van-pagination__item van-pagination__item--disabled van-pagination__prev van-hairline">
<i class="van-badge__wrapper van-icon van-icon-arrow-left">
</i>
</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">
<i class="van-badge__wrapper van-icon van-icon-arrow">
</i>
</li>
</ul>
<nav role="navigation"
class="van-pagination"
>
<ul class="van-pagination__items">
<li class="van-pagination__item van-pagination__item--disabled van-pagination__item--prev van-hairline--surround">
<button disabled>
Prev
</button>
</li>
<li class="van-pagination__item van-pagination__item--active van-pagination__item--page van-hairline--surround">
<button aria-current="true">
1
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
2
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
3
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
...
</button>
</li>
<li class="van-pagination__item van-pagination__item--next van-hairline--surround">
<button>
Next
</button>
</li>
</ul>
</nav>
</div>
<div>
<nav role="navigation"
class="van-pagination"
>
<ul class="van-pagination__items">
<li class="van-pagination__item van-pagination__item--disabled van-pagination__item--prev van-hairline--surround">
<button disabled>
<i class="van-badge__wrapper van-icon van-icon-arrow-left">
</i>
</button>
</li>
<li class="van-pagination__item van-pagination__item--active van-pagination__item--page van-hairline--surround">
<button aria-current="true">
1
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
2
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
3
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
4
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
5
</button>
</li>
<li class="van-pagination__item van-pagination__item--next van-hairline--surround">
<button>
<i class="van-badge__wrapper van-icon van-icon-arrow">
</i>
</button>
</li>
</ul>
</nav>
</div>
`;

View File

@ -1,53 +1,89 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render page slot correctly 1`] = `
<ul class="van-pagination">
<li class="van-pagination__item van-pagination__prev van-hairline">
Previous
</li>
<li class="van-pagination__item van-pagination__page van-hairline">
foo 1
</li>
<li class="van-pagination__item van-pagination__page van-hairline">
foo 2
</li>
<li class="van-pagination__item van-pagination__page van-hairline">
foo 3
</li>
<li class="van-pagination__item van-pagination__page van-hairline">
foo 4
</li>
<li class="van-pagination__item van-pagination__page van-hairline">
foo 5
</li>
<li class="van-pagination__item van-pagination__next van-hairline">
Next
</li>
</ul>
<nav role="navigation"
class="van-pagination"
>
<ul class="van-pagination__items">
<li class="van-pagination__item van-pagination__item--prev van-hairline--surround">
<button>
Previous
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
foo 1
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
foo 2
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
foo 3
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
foo 4
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
foo 5
</button>
</li>
<li class="van-pagination__item van-pagination__item--next van-hairline--surround">
<button>
Next
</button>
</li>
</ul>
</nav>
`;
exports[`should render prev-text、next-text slot correctly 1`] = `
<ul class="van-pagination">
<li class="van-pagination__item van-pagination__prev van-hairline">
Custom PrevText
</li>
<li class="van-pagination__item 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">
Custom NextText
</li>
</ul>
<nav role="navigation"
class="van-pagination"
>
<ul class="van-pagination__items">
<li class="van-pagination__item van-pagination__item--prev van-hairline--surround">
<button>
Custom PrevText
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
1
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
2
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
3
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
4
</button>
</li>
<li class="van-pagination__item van-pagination__item--page van-hairline--surround">
<button>
5
</button>
</li>
<li class="van-pagination__item van-pagination__item--next van-hairline--surround">
<button>
Custom NextText
</button>
</li>
</ul>
</nav>
`;