feat(Picker): item-height support rem unit (#6462)

This commit is contained in:
neverland 2020-06-05 09:25:19 +08:00 committed by GitHub
parent 76c9e7ef1e
commit 2f2760aba6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 126 additions and 36 deletions

View File

@ -64,7 +64,7 @@ To have a selected valuesimply pass the `code` of target area to `value` prop
| area-list | Area list data | _object_ | - |
| columns-placeholder `v2.2.5` | Placeholder of columns | _string[]_ | `[]` |
| loading | Whether to show loading prompt | _boolean_ | `false` |
| item-height | Option height | _number \| string_ | `44` |
| item-height `v2.8.6` | Option height, supports `px` ans `rem` unit, default `px` | _number \| string_ | `44` |
| columns-num | Level of picker | _number \| string_ | `3` |
| visible-item-count | Count of visible columns | _number \| string_ | `5` |
| swipe-duration `v2.2.13` | Duration of the momentum animationunit `ms` | _number \| string_ | `1000` |

View File

@ -64,7 +64,7 @@ Vue.use(Area);
| area-list | 省市区数据,格式见下方 | _object_ | - |
| columns-placeholder `v2.2.5` | 列占位提示文字 | _string[]_ | `[]` |
| loading | 是否显示加载状态 | _boolean_ | `false` |
| item-height | 选项高度 | _number \| string_ | `44` |
| item-height `v2.8.6` | 选项高度,支持 `px``rem` 单位,默认 `px` | _number \| string_ | `44` |
| columns-num | 显示列数3-省市区2-省市1-省 | _number \| string_ | `3` |
| visible-item-count | 可见的选项个数 | _number \| string_ | `5` |
| swipe-duration `v2.2.13` | 快速滑动时惯性滚动的时长,单位`ms` | _number \| string_ | `1000` |

View File

@ -198,7 +198,7 @@ export default {
| loading | Whether to show loading prompt | _boolean_ | `false` |
| filter | Option filter | _(type, vals) => vals_ | - |
| formatter | Option text formatter | _(type, val) => val_ | - |
| item-height | Option height | _number \| string_ | `44` |
| item-height `v2.8.6` | Option height, supports `px` ans `rem` unit, default `px` | _number \| string_ | `44` |
| visible-item-count | Count of visible columns | _number \| string_ | `5` |
| swipe-duration `v2.2.13` | Duration of the momentum animationunit `ms` | _number \| string_ | `1000` |

View File

@ -205,7 +205,7 @@ export default {
| loading | 是否显示加载状态 | _boolean_ | `false` |
| filter | 选项过滤函数 | _(type, vals) => vals_ | - |
| formatter | 选项格式化函数 | _(type, val) => val_ | - |
| item-height | 选项高度 | _number \| string_ | `44` |
| item-height `v2.8.6` | 选项高度,支持 `px``rem` 单位,默认 `px` | _number \| string_ | `44` |
| visible-item-count | 可见的选项个数 | _number \| string_ | `5` |
| swipe-duration `v2.2.13` | 快速滑动时惯性滚动的时长,单位`ms` | _number \| string_ | `1000` |

View File

@ -33,7 +33,7 @@ export default createComponent({
valueKey: String,
allowHtml: Boolean,
className: String,
itemHeight: [Number, String],
itemHeight: Number,
defaultIndex: Number,
swipeDuration: [Number, String],
visibleItemCount: [Number, String],

View File

@ -252,7 +252,7 @@ export default {
| show-toolbar | Whether to show toolbar | _boolean_ | `false` |
| allow-html `v2.1.8` | Whether to allow HTML in option text | _boolean_ | `true` |
| default-index | Default value index of single column picker | _number \| string_ | `0` |
| item-height | Option height | _number \| string_ | `44` |
| item-height `v2.8.6` | Option height, supports `px` ans `rem` unit, default `px` | _number \| string_ | `44` |
| visible-item-count | Count of visible columns | _number \| string_ | `5` |
| swipe-duration `v2.2.10` | Duration of the momentum animationunit `ms` | _number \| string_ | `1000` |

View File

@ -275,9 +275,9 @@ export default {
| show-toolbar | 是否显示顶部栏 | _boolean_ | `false` |
| allow-html `v2.1.8` | 是否允许选项内容中渲染 HTML | _boolean_ | `true` |
| default-index | 单列选择时,默认选中项的索引 | _number \| string_ | `0` |
| item-height | 选项高度 | _number \| string_ | `44` |
| item-height `v2.8.6` | 选项高度,支持 `px``rem` 单位,默认 `px` | _number \| string_ | `44` |
| visible-item-count | 可见的选项个数 | _number \| string_ | `5` |
| swipe-duration `v2.2.10` | 快速滑动时惯性滚动的时长,单位`ms` | _number \| string_ | `1000` |
| swipe-duration `v2.2.10` | 快速滑动时惯性滚动的时长,单位 `ms` | _number \| string_ | `1000` |
### Events

View File

@ -3,6 +3,7 @@ import { createNamespace, isObject } from '../utils';
import { preventDefault } from '../utils/dom/event';
import { BORDER_UNSET_TOP_BOTTOM } from '../utils/constant';
import { pickerProps } from './shared';
import { unitToPx } from '../utils/format/unit';
// Components
import Loading from '../loading';
@ -39,6 +40,10 @@ export default createComponent({
},
computed: {
itemPxHeight() {
return unitToPx(this.itemHeight);
},
dataType() {
const { columns } = this;
const firstColumn = columns[0] || {};
@ -277,12 +282,38 @@ export default createComponent({
},
genColumns() {
const { itemPxHeight } = this;
const wrapHeight = itemPxHeight * this.visibleItemCount;
const frameStyle = { height: `${itemPxHeight}px` };
const columnsStyle = { height: `${wrapHeight}px` };
const maskStyle = {
backgroundSize: `100% ${(wrapHeight - itemPxHeight) / 2}px`,
};
return (
<div
class={bem('columns')}
style={columnsStyle}
onTouchmove={preventDefault}
>
{this.genColumnItems()}
<div class={bem('mask')} style={maskStyle} />
<div
class={[BORDER_UNSET_TOP_BOTTOM, bem('frame')]}
style={frameStyle}
/>
</div>
);
},
genColumnItems() {
return this.formattedColumns.map((item, columnIndex) => (
<PickerColumn
valueKey={this.valueKey}
allowHtml={this.allowHtml}
className={item.className}
itemHeight={this.itemHeight}
itemHeight={this.itemPxHeight}
defaultIndex={item.defaultIndex || +this.defaultIndex}
swipeDuration={this.swipeDuration}
visibleItemCount={this.visibleItemCount}
@ -296,38 +327,12 @@ export default createComponent({
},
render(h) {
const itemHeight = +this.itemHeight;
const wrapHeight = itemHeight * this.visibleItemCount;
const frameStyle = {
height: `${itemHeight}px`,
};
const columnsStyle = {
height: `${wrapHeight}px`,
};
const maskStyle = {
backgroundSize: `100% ${(wrapHeight - itemHeight) / 2}px`,
};
return (
<div class={bem()}>
{this.toolbarPosition === 'top' ? this.genToolbar() : h()}
{this.loading ? <Loading class={bem('loading')} /> : h()}
{this.slots('columns-top')}
<div
class={bem('columns')}
style={columnsStyle}
onTouchmove={preventDefault}
>
{this.genColumns()}
<div class={bem('mask')} style={maskStyle} />
<div
class={[BORDER_UNSET_TOP_BOTTOM, bem('frame')]}
style={frameStyle}
/>
</div>
{this.genColumns()}
{this.slots('columns-bottom')}
{this.toolbarPosition === 'bottom' ? this.genToolbar() : h()}
</div>

View File

@ -103,6 +103,27 @@ exports[`render title slot 1`] = `
</div>
`;
exports[`set rem item-height 1`] = `
<div class="van-picker">
<!---->
<div class="van-picker__columns" style="height: 800px;">
<div class="van-picker-column">
<ul class="van-picker-column__wrapper" style="transform: translate3d(0, 320px, 0); transition-duration: 0ms; transition-property: none;">
<li role="button" tabindex="0" class="van-picker-column__item van-picker-column__item--selected" style="height: 160px;">
<div class="van-ellipsis">1990</div>
</li>
<li role="button" tabindex="0" class="van-picker-column__item" style="height: 160px;">
<div class="van-ellipsis">1991</div>
</li>
</ul>
</div>
<div class="van-picker__mask" style="background-size: 100% 320px;"></div>
<div class="van-hairline-unset--top-bottom van-picker__frame" style="height: 160px;"></div>
</div>
<!---->
</div>
`;
exports[`toolbar-position prop 1`] = `
<div class="van-picker">
<!---->

View File

@ -261,3 +261,21 @@ test('should not reset index when columns unchanged', () => {
wrapper.find('.van-picker__confirm').trigger('click');
expect(wrapper.emitted('confirm')[0]).toEqual(['2', 1]);
});
test('set rem item-height', async () => {
const originGetComputedStyle = window.getComputedStyle;
window.getComputedStyle = () => ({ fontSize: '16px' });
const wrapper = mount(Picker, {
propsData: {
columns: simpleColumn.slice(0, 2),
itemHeight: '10rem',
},
});
await later();
expect(wrapper).toMatchSnapshot();
window.getComputedStyle = originGetComputedStyle;
});

View File

@ -9,3 +9,24 @@ export function addUnit(value?: string | number): string | undefined {
value = String(value);
return isNumeric(value) ? `${value}px` : value;
}
function convertRem(value: string) {
const rootStyle = window.getComputedStyle(document.documentElement);
const rootFontSize = parseFloat(rootStyle.fontSize);
value = value.replace(/rem/g, '');
return +value * rootFontSize;
}
export function unitToPx(value: string | number): number {
if (typeof value === 'number') {
return value;
}
if (value.indexOf('rem') !== -1) {
return convertRem(value);
}
return parseFloat(value);
}

View File

@ -9,6 +9,7 @@ import { isNumeric } from '../validate/number';
import { isAndroid } from '../validate/system';
import { camelize } from '../format/string';
import { formatNumber } from '../format/number';
import { addUnit, unitToPx } from '../format/unit';
test('deepClone', () => {
const a = { foo: 0 };
@ -115,3 +116,27 @@ test('formatNumber', () => {
expect(formatNumber('-1.2-', true)).toEqual('-1.2');
expect(formatNumber('123-')).toEqual('123');
});
test('addUnit', () => {
expect(addUnit(0)).toEqual('0px');
expect(addUnit(10)).toEqual('10px');
expect(addUnit('1%')).toEqual('1%');
expect(addUnit('1px')).toEqual('1px');
expect(addUnit('1vw')).toEqual('1vw');
expect(addUnit('1vh')).toEqual('1vh');
expect(addUnit('1rem')).toEqual('1rem');
});
test('unitToPx', () => {
const originGetComputedStyle = window.getComputedStyle;
window.getComputedStyle = () => ({ fontSize: '16px' });
expect(unitToPx(0)).toEqual(0);
expect(unitToPx(10)).toEqual(10);
expect(unitToPx('10px')).toEqual(10);
expect(unitToPx('0rem')).toEqual(0);
expect(unitToPx('10rem')).toEqual(160);
window.getComputedStyle = originGetComputedStyle;
});