Merge branch '2.x' into dev

This commit is contained in:
chenjiahan 2020-10-31 18:19:32 +08:00
commit 2d2f0d8ad4
29 changed files with 324 additions and 69 deletions

View File

@ -10,7 +10,30 @@ Vant follows [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/).
- Minor versionreleased every one to two months, including backwards compatible features. - Minor versionreleased every one to two months, including backwards compatible features.
- Major versionincluding breaking changes and new features. - Major versionincluding breaking changes and new features.
### [v2.10.11](https://github.com/youzan/vant/compare/v2.10.11-beta.0...v2.10.11) ### [v2.10.12](https://github.com/youzan/vant/compare/v2.10.11...v2.10.12)
`2020-10-31`
**Feature**
- Image: add icon-prefix prop [#7457](https://github.com/youzan/vant/issues/7457)
- Progress: add resize method [#5161](https://github.com/youzan/vant/issues/5161)
- SubmitBar: add button slot [#7458](https://github.com/youzan/vant/issues/7458)
**style**
- ActionSheet: keep the cancel button at the bottom [#7401](https://github.com/youzan/vant/issues/7401)
- Popup: adjust round border radius to 16px [#7421](https://github.com/youzan/vant/issues/7421)
- Sidebar: fix long number wrap [#7456](https://github.com/youzan/vant/issues/7456)
**Bug Fixes**
- GridItem: should not emit deprecation warning [#7433](https://github.com/youzan/vant/issues/7433)
- Picker: fix rendering failure during animation on safari [#7460](https://github.com/youzan/vant/issues/7460)
- Tabs: incorrect change event in some cases [#7461](https://github.com/youzan/vant/issues/7461)
- Tabs: should keep active value after insert item [#7445](https://github.com/youzan/vant/issues/7445)
### [v2.10.11](https://github.com/youzan/vant/compare/v2.10.11...v2.10.11)
`2020-10-24` `2020-10-24`

View File

@ -10,7 +10,30 @@ Vant 遵循 [Semver](https://semver.org/lang/zh-CN/) 语义化版本规范。
- 次版本号:每隔一至二个月发布,包含新特性和较大的功能更新,向下兼容。 - 次版本号:每隔一至二个月发布,包含新特性和较大的功能更新,向下兼容。
- 主版本号:发布时间不定,包含不兼容更新,预计下一个主版本会与 Vue 3.0 同期发布。 - 主版本号:发布时间不定,包含不兼容更新,预计下一个主版本会与 Vue 3.0 同期发布。
### [v2.10.11](https://github.com/youzan/vant/compare/v2.10.11-beta.0...v2.10.11) ### [v2.10.12](https://github.com/youzan/vant/compare/v2.10.11...v2.10.12)
`2020-10-31`
**Feature**
- Image: 新增 icon-prefix 属性 [#7457](https://github.com/youzan/vant/issues/7457)
- Progress: 新增 resize 属性 [#5161](https://github.com/youzan/vant/issues/5161)
- SubmitBar: 新增 button 插槽,用于自定义按钮 [#7458](https://github.com/youzan/vant/issues/7458)
**style**
- ActionSheet: 当选项较多时,取消按钮现在会固定在底部 [#7401](https://github.com/youzan/vant/issues/7401)
- Popup: 圆角弹窗的圆角大小从 20px 调整为 16px [#7421](https://github.com/youzan/vant/issues/7421)
- Sidebar: 修复文本为长数字时无法自动换行的问题 [#7456](https://github.com/youzan/vant/issues/7456)
**Bug Fixes**
- GridItem: 修复使用 badge 属性时会在控制台抛出 warning 的问题 [#7433](https://github.com/youzan/vant/issues/7433)
- Picker: 修复在 safari 上动画弹出过程中遮罩层闪烁的问题 [#7460](https://github.com/youzan/vant/issues/7460)
- Tabs: 修复在个别情况下错误地抛出 change 事件的问题 [#7461](https://github.com/youzan/vant/issues/7461)
- Tabs: 修复动态插入时 active 值可能错误的问题 [#7445](https://github.com/youzan/vant/issues/7445)
### [v2.10.11](https://github.com/youzan/vant/compare/v2.10.11...v2.10.11)
`2020-10-24` `2020-10-24`

View File

@ -160,7 +160,7 @@ export default {
| closed `v2.5.6` | Triggered after closed | - | | closed `v2.5.6` | Triggered after closed | - |
| change | Triggered when current image change | index: index of current image | | change | Triggered when current image change | index: index of current image |
| scale `v2.5.0` | Triggered when current image scale | { index: index of current image, scale: scale of current image} | | scale `v2.5.0` | Triggered when current image scale | { index: index of current image, scale: scale of current image} |
| swipeTo `2.9.0` | Swipe to target index | index: target index, options: Options | void | | swipeTo `2.9.0` | Swipe to target index | index: target index, options: Options | - |
### Slots ### Slots

View File

@ -201,7 +201,7 @@ export default {
| closed `v2.5.6` | 关闭且且动画结束后触发 | - | | closed `v2.5.6` | 关闭且且动画结束后触发 | - |
| change | 切换当前图片时触发 | index: 当前图片的索引 | | change | 切换当前图片时触发 | index: 当前图片的索引 |
| scale `v2.5.0` | 缩放当前图片时触发 | { index: 当前图片的索引, scale: 当前缩放的值 } | | scale `v2.5.0` | 缩放当前图片时触发 | { index: 当前图片的索引, scale: 当前缩放的值 } |
| swipeTo `2.9.0` | 切换到指定位置 | index: number, options: Options | void | | swipeTo `2.9.0` | 切换到指定位置 | index: number, options: Options | - |
### Slots ### Slots

View File

@ -79,6 +79,7 @@ app.use(Lazyload);
| show-loading | Whether to show loading placeholder | _boolean_ | `true` | | show-loading | Whether to show loading placeholder | _boolean_ | `true` |
| error-icon `v2.4.2` | Error icon | _string_ | `photo-fail` | | error-icon `v2.4.2` | Error icon | _string_ | `photo-fail` |
| loading-icon `v2.4.2` | Loading icon | _string_ | `photo` | | loading-icon `v2.4.2` | Loading icon | _string_ | `photo` |
| icon-prefix `v2.10.12` | Icon className prefix | _string_ | `van-icon` |
### fit optional value ### fit optional value

View File

@ -111,6 +111,7 @@ app.use(Lazyload);
| show-loading | 是否展示图片加载中提示 | _boolean_ | `true` | | show-loading | 是否展示图片加载中提示 | _boolean_ | `true` |
| error-icon `v2.4.2` | 失败时提示的[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `photo-fail` | | error-icon `v2.4.2` | 失败时提示的[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `photo-fail` |
| loading-icon `v2.4.2` | 加载时提示的[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `photo` | | loading-icon `v2.4.2` | 加载时提示的[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `photo` |
| icon-prefix `v2.10.12` | 图标类名前缀,同 Icon 组件的 [class-prefix 属性](#/zh-CN/icon#props) | _string_ | `van-icon` |
### 图片填充模式  ### 图片填充模式 

View File

@ -16,6 +16,7 @@ export default createComponent({
height: [Number, String], height: [Number, String],
radius: [Number, String], radius: [Number, String],
lazyLoad: Boolean, lazyLoad: Boolean,
iconPrefix: String,
showError: { showError: {
type: Boolean, type: Boolean,
default: true, default: true,
@ -84,7 +85,13 @@ export default createComponent({
return slots.loading(); return slots.loading();
} }
return <Icon name={props.loadingIcon} class={bem('loading-icon')} />; return (
<Icon
name={props.loadingIcon}
class={bem('loading-icon')}
classPrefix={props.iconPrefix}
/>
);
}; };
const renderErrorIcon = () => { const renderErrorIcon = () => {
@ -92,7 +99,13 @@ export default createComponent({
return slots.error(); return slots.error();
} }
return <Icon name={props.errorIcon} class={bem('error-icon')} />; return (
<Icon
name={props.errorIcon}
class={bem('error-icon')}
classPrefix={props.iconPrefix}
/>
);
}; };
const renderPlaceholder = () => { const renderPlaceholder = () => {

View File

@ -1,5 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`apply icon-prefix prop to error-icon 1`] = `
<div class="van-image">
<div class="van-image__error"><i class="my-icon my-icon-error van-image__error-icon">
<!----></i></div>
</div>
`;
exports[`apply icon-prefix prop to loading-icon 1`] = `
<div class="van-image"><img class="van-image__img">
<div class="van-image__loading"><i class="my-icon my-icon-success van-image__loading-icon">
<!----></i></div>
</div>
`;
exports[`default slot 1`] = ` exports[`default slot 1`] = `
<div class="van-image"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img"> <div class="van-image"><img src="https://img.yzcdn.cn/vant/cat.jpeg" class="van-image__img">
<div class="van-image__loading"><i class="van-icon van-icon-photo van-image__loading-icon"> <div class="van-image__loading"><i class="van-icon van-icon-photo van-image__loading-icon">

View File

@ -147,6 +147,31 @@ test('loading-icon prop', () => {
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
}); });
test('apply icon-prefix prop to error-icon', () => {
const wrapper = mount(VanImage, {
propsData: {
errorIcon: 'error',
iconPrefix: 'my-icon',
src: 'https://img.yzcdn.cn/vant/cat.jpeg',
},
});
wrapper.find('img').trigger('error');
expect(wrapper).toMatchSnapshot();
});
test('apply icon-prefix prop to loading-icon', () => {
const wrapper = mount(VanImage, {
propsData: {
loadingIcon: 'success',
iconPrefix: 'my-icon',
},
});
expect(wrapper).toMatchSnapshot();
});
test('radius prop', () => { test('radius prop', () => {
const wrapper = mount(VanImage, { const wrapper = mount(VanImage, {
propsData: { propsData: {

View File

@ -87,7 +87,8 @@
linear-gradient(0deg, hsla(0, 0%, 100%, 0.9), hsla(0, 0%, 100%, 0.4)); linear-gradient(0deg, hsla(0, 0%, 100%, 0.9), hsla(0, 0%, 100%, 0.4));
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: top, bottom; background-position: top, bottom;
backface-visibility: hidden; // fix rendering failure during animation on safari
transform: translateZ(0);
pointer-events: none; pointer-events: none;
} }

View File

@ -62,3 +62,11 @@ Use `pivot-text` to custom textuse `color` to custom bar color.
| text-color | Pivot text color | _string_ | `white` | | text-color | Pivot text color | _string_ | `white` |
| inactive | Whether to be gray | _boolean_ | `false` | | inactive | Whether to be gray | _boolean_ | `false` |
| show-pivot | Whether to show text | _boolean_ | `true` | | show-pivot | Whether to show text | _boolean_ | `true` |
### Methods
Use [ref](https://vuejs.org/v2/api/#ref) to get Progress instance and call instance methods.
| Name | Description | Attribute | Return value |
| --- | --- | --- | --- |
| resize | Resize Progress when container element resized or visibility changed | - | - |

View File

@ -70,3 +70,38 @@ app.use(Progress);
| text-color | 进度文字颜色 | _string_ | `white` | | text-color | 进度文字颜色 | _string_ | `white` |
| inactive | 是否置灰 | _boolean_ | `false` | | inactive | 是否置灰 | _boolean_ | `false` |
| show-pivot | 是否显示进度文字 | _boolean_ | `true` | | show-pivot | 是否显示进度文字 | _boolean_ | `true` |
### 方法
通过 ref 可以获取到 Progress 实例并调用实例方法,详见[组件实例方法](#/zh-CN/advanced-usage#zu-jian-shi-li-fang-fa)。
| 方法名 | 说明 | 参数 | 返回值 |
| ------ | -------------------------------------------- | ---- | ------ |
| resize | 外层元素大小变化后,可以调用此方法来触发重绘 | - | - |
## 常见问题
### 组件从隐藏状态切换到显示状态时,渲染不正确?
Progress 组件在挂载时,会获取自身的宽度,并计算出进度条的样式。如果组件一开始处于隐藏状态,则获取到的宽度永远为 0因此无法展示正确的进度。
#### 解决方法
方法一,如果是使用 `v-show` 来控制组件展示的,则替换为 `v-if` 即可解决此问题:
```html
<!-- Before -->
<van-progress v-show="show" />
<!-- After -->
<van-progress v-if="show" />
```
方法二,调用组件的 resize 方法来主动触发重绘:
```html
<van-progress v-show="show" ref="progress" />
```
```js
this.$refs.progress.resize();
```

View File

@ -1,5 +1,6 @@
import { ref, watch, computed, nextTick, reactive, onMounted } from 'vue'; import { ref, watch, computed, nextTick, reactive, onMounted } from 'vue';
import { createNamespace, addUnit } from '../utils'; import { createNamespace, addUnit } from '../utils';
import { useExpose } from '../composition/use-expose';
const [createComponent, bem] = createNamespace('progress'); const [createComponent, bem] = createNamespace('progress');
@ -36,7 +37,7 @@ export default createComponent({
props.inactive ? '#cacaca' : props.color props.inactive ? '#cacaca' : props.color
); );
const setWidth = () => { const resize = () => {
nextTick(() => { nextTick(() => {
state.rootWidth = root.value ? root.value.offsetWidth : 0; state.rootWidth = root.value ? root.value.offsetWidth : 0;
state.pivotWidth = pivotRef.value ? pivotRef.value.offsetWidth : 0; state.pivotWidth = pivotRef.value ? pivotRef.value.offsetWidth : 0;
@ -65,9 +66,9 @@ export default createComponent({
} }
}; };
watch([() => props.showPivot, () => props.pivotText], setWidth); watch([() => props.showPivot, () => props.pivotText], resize);
onMounted(resize);
onMounted(setWidth); useExpose({ resize });
return () => { return () => {
const { trackColor, percentage, strokeWidth } = props; const { trackColor, percentage, strokeWidth } = props;

View File

@ -9,7 +9,6 @@
color: @sidebar-text-color; color: @sidebar-text-color;
font-size: @sidebar-font-size; font-size: @sidebar-font-size;
line-height: @sidebar-line-height; line-height: @sidebar-line-height;
word-wrap: break-word;
background-color: @sidebar-background-color; background-color: @sidebar-background-color;
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
@ -22,6 +21,11 @@
border-bottom-width: 1px; border-bottom-width: 1px;
} }
&__text {
// https://github.com/youzan/vant/issues/7455
word-break: break-all;
}
&--select { &--select {
color: @sidebar-selected-text-color; color: @sidebar-selected-text-color;
font-weight: @sidebar-selected-font-weight; font-weight: @sidebar-selected-font-weight;

View File

@ -61,6 +61,7 @@ Use slot to add custom contents.
| Attribute | Description | Type | Default | | Attribute | Description | Type | Default |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| price | Price | _number_ | - | | price | Price | _number_ | - |
| decimal-length | Price dicemal length | _number \| string_ | `2` |
| label | Price left label | _string_ | `Total` | | label | Price left label | _string_ | `Total` |
| suffix-label | Price right label | _string_ | - | | suffix-label | Price right label | _string_ | - |
| text-align `v2.3.0` | Price label text align can be set to `left` | _string_ | `right` | | text-align `v2.3.0` | Price label text align can be set to `left` | _string_ | `right` |
@ -70,7 +71,6 @@ Use slot to add custom contents.
| tip | Tip | _string_ | - | | tip | Tip | _string_ | - |
| tip-icon | Icon | _string_ | - | | tip-icon | Icon | _string_ | - |
| currency | Currency symbol | _string_ | `¥` | | currency | Currency symbol | _string_ | `¥` |
| decimal-length | number of digits to appear after the decimal point | _number \| string_ | `2` |
| disabled | Whether to disable button | _boolean_ | `false` | | disabled | Whether to disable button | _boolean_ | `false` |
| loading | Whether to show loading icon | _boolean_ | `false` | | loading | Whether to show loading icon | _boolean_ | `false` |
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `true` | | safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `true` |
@ -83,8 +83,9 @@ Use slot to add custom contents.
### Slots ### Slots
| Name | Description | | Name | Description |
| ------- | ------------------- | | ----------------- | ------------------- |
| default | Custom left content | | default | Custom left content |
| top | Custom top content | | button `v2.10.12` | Custom button |
| tip | Custom tips | | top | Custom top content |
| tip | Custom tips |

View File

@ -66,18 +66,18 @@ app.use(SubmitBar);
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| price | 价格(单位分) | _number_ | - | | price | 价格(单位分) | _number_ | - |
| decimal-length | 价格小数点位数 | _number \| string_ | `2` |
| label | 价格左侧文案 | _string_ | `合计:` | | label | 价格左侧文案 | _string_ | `合计:` |
| suffix-label | 价格右侧文案 | _string_ | - | | suffix-label | 价格右侧文案 | _string_ | - |
| text-align `v2.3.0` | 价格文案对齐方向,可选值为 `left` | _string_ | `right` | | text-align `v2.3.0` | 价格文案对齐方向,可选值为 `left` | _string_ | `right` |
| button-text | 按钮文字 | _string_ | - | | button-text | 按钮文字 | _string_ | - |
| button-type | 按钮类型 | _string_ | `danger` | | button-type | 按钮类型 | _string_ | `danger` |
| button-color `v2.9.1` | 自定义按钮颜色 | _string_ | - | | button-color `v2.9.1` | 自定义按钮颜色 | _string_ | - |
| tip | 提示文案 | _string_ | - | | tip | 在订单栏上方的提示文案 | _string_ | - |
| tip-icon | 左侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | - | | tip-icon | 提示文案左侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | - |
| currency | 货币符号 | _string_ | `¥` | | currency | 货币符号 | _string_ | `¥` |
| decimal-length | 价格小数点后位数 | _number \| string_ | `2` |
| disabled | 是否禁用按钮 | _boolean_ | `false` | | disabled | 是否禁用按钮 | _boolean_ | `false` |
| loading | 是否显示加载中的按钮 | _boolean_ | `false` | | loading | 是否显示将按钮显示为加载中状态 | _boolean_ | `false` |
| safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/advanced-usage#di-bu-an-quan-qu-gua-pei) | _boolean_ | `true` | | safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/advanced-usage#di-bu-an-quan-qu-gua-pei) | _boolean_ | `true` |
### Events ### Events
@ -88,8 +88,9 @@ app.use(SubmitBar);
### Slots ### Slots
| 名称 | 说明 | | 名称 | 说明 |
| ------- | -------------------------- | | ----------------- | -------------------- |
| default | 自定义订单栏左侧内容 | | default | 自定义订单栏左侧内容 |
| top | 自定义订单栏上方内容 | | button `v2.10.12` | 自定义按钮 |
| tip | 提示文案中的额外操作和说明 | | top | 自定义订单栏上方内容 |
| tip | 提示文案中的额外内容 |

View File

@ -84,18 +84,24 @@ export default createComponent({
emit('submit'); emit('submit');
}; };
const renderButton = () => ( const renderButton = () => {
<Button if (slots.button) {
round return slots.button();
type={props.buttonType} }
text={props.buttonText}
class={bem('button', props.buttonType)} return (
color={props.buttonColor} <Button
loading={props.loading} round
disabled={props.disabled} type={props.buttonType}
onClick={onClickButton} text={props.buttonText}
/> class={bem('button', props.buttonType)}
); color={props.buttonColor}
loading={props.loading}
disabled={props.disabled}
onClick={onClickButton}
/>
);
};
return () => ( return () => (
<div class={bem({ unfit: !props.safeAreaInsetBottom })}> <div class={bem({ unfit: !props.safeAreaInsetBottom })}>

View File

@ -1,5 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`button slot 1`] = `
<div class="van-submit-bar">
<div class="van-submit-bar__bar">Custom button</div>
</div>
`;
exports[`button-color prop 1`] = ` exports[`button-color prop 1`] = `
<div class="van-submit-bar"> <div class="van-submit-bar">
<div class="van-submit-bar__bar"><button class="van-button van-button--danger van-button--normal van-button--round van-submit-bar__button van-submit-bar__button--danger" style="color: rgb(255, 255, 255); background: red; border-color: red;"> <div class="van-submit-bar__bar"><button class="van-button van-button--danger van-button--normal van-button--round van-submit-bar__button van-submit-bar__button--danger" style="color: rgb(255, 255, 255); background: red; border-color: red;">
@ -57,7 +63,7 @@ exports[`text-align prop 1`] = `
`; `;
exports[`top slot 1`] = ` exports[`top slot 1`] = `
<div class="van-submit-bar">top<div class="van-submit-bar__bar"><button class="van-button van-button--danger van-button--normal van-button--round van-submit-bar__button van-submit-bar__button--danger"> <div class="van-submit-bar">Custom Top<div class="van-submit-bar__bar"><button class="van-button van-button--danger van-button--normal van-button--round van-submit-bar__button van-submit-bar__button--danger">
<div class="van-button__content"></div> <div class="van-button__content"></div>
</button></div> </button></div>
</div> </div>

View File

@ -52,7 +52,7 @@ test('without price', () => {
test('top slot', () => { test('top slot', () => {
const wrapper = mount(SubmitBar, { const wrapper = mount(SubmitBar, {
scopedSlots: { scopedSlots: {
top: () => 'top', top: () => 'Custom Top',
}, },
}); });
@ -119,3 +119,14 @@ test('button-color prop', () => {
}); });
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
}); });
test('button slot', () => {
const wrapper = mount(SubmitBar, {
buttonText: 'text',
scopedSlots: {
button: () => 'Custom button',
},
});
expect(wrapper).toMatchSnapshot();
});

View File

@ -195,8 +195,8 @@ Use [ref](https://v3.vuejs.org/guide/component-template-refs.html) to get Swipe
| --- | --- | --- | --- | | --- | --- | --- | --- |
| prev `v2.4.2` | Swipe to prev item | - | - | | prev `v2.4.2` | Swipe to prev item | - | - |
| next `v2.4.2` | Swipe to next item | - | - | | next `v2.4.2` | Swipe to next item | - | - |
| swipeTo | Swipe to target index | index: target index, options: Options | void | | swipeTo | Swipe to target index | index: target index, options: Options | - |
| resize | Resize Swipe when container element resized | - | void | | resize | Resize Swipe when container element resized or visibility changed | - | - |
### swipeTo Options ### swipeTo Options

View File

@ -199,14 +199,14 @@ export default {
### Swipe 方法 ### Swipe 方法
通过 ref 可以获取到 Swipe 实例并调用实例方法,详见[组件实例方法](#/zh-CN/advanced-usage#zu-jian-shi-li-fang-fa)。 通过 ref 可以获取到 Swipe 实例并调用实例方法,详见[组件实例方法](#/zh-CN/advanced-usage#zu-jian-shi-li-fang-fa)。
| 方法名 | 说明 | 参数 | 返回值 | | 方法名 | 说明 | 参数 | 返回值 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| prev `v2.4.2` | 切换到上一轮播 | - | - | | prev `v2.4.2` | 切换到上一轮播 | - | - |
| next `v2.4.2` | 切换到下一轮播 | - | - | | next `v2.4.2` | 切换到下一轮播 | - | - |
| swipeTo | 切换到指定位置 | index: number, options: Options | void | | swipeTo | 切换到指定位置 | index: number, options: Options | - |
| resize | 外层元素大小变化后,可以调用此方法来触发重绘 | - | void | | resize | 外层元素大小或组件显示状态变化时,可以调用此方法来触发重绘 | - | - |
### swipeTo Options 格式 ### swipeTo Options 格式
@ -236,3 +236,28 @@ export default {
### Swipe 组件功能太少,无法实现复杂效果? ### Swipe 组件功能太少,无法实现复杂效果?
Vant 中的 Swipe 组件是比较轻量的,因此功能也比较基础。如果需要更复杂的轮播效果,推荐使用社区里一些优质的轮播库,比如 [vue-awesome-swiper](https://github.com/surmon-china/vue-awesome-swiper)。 Vant 中的 Swipe 组件是比较轻量的,因此功能也比较基础。如果需要更复杂的轮播效果,推荐使用社区里一些优质的轮播库,比如 [vue-awesome-swiper](https://github.com/surmon-china/vue-awesome-swiper)。
### 组件从隐藏状态切换到显示状态时,无法正确渲染?
Swipe 组件在挂载时,会获取自身的宽度,并计算出轮播图的位置。如果组件一开始处于隐藏状态,则获取到的宽度永远为 0因此无法正确计算位置。
#### 解决方法
方法一,如果是使用 `v-show` 来控制组件展示的,则替换为 `v-if` 即可解决此问题:
```html
<!-- Before -->
<van-swipe v-show="show" />
<!-- After -->
<van-swipe v-if="show" />
```
方法二,调用组件的 resize 方法来主动触发重绘:
```html
<van-swipe v-show="show" ref="swipe" />
```
```js
this.$refs.swipe.resize();
```

View File

@ -270,8 +270,8 @@ Use [ref](https://v3.vuejs.org/guide/component-template-refs.html) to get Tabs i
| Name | Description | Attribute | Return value | | Name | Description | Attribute | Return value |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| resize | Resize Tabs when container element resized | - | void | | resize | Resize Tabs when container element resized or visibility changed | - | - |
| scrollTo `v2.9.3` | Go to specified tab in scrollspy mode | name | void | | scrollTo `v2.9.3` | Go to specified tab in scrollspy mode | name | - |
### Tabs Slots ### Tabs Slots

View File

@ -277,8 +277,8 @@ export default {
| 方法名 | 说明 | 参数 | 返回值 | | 方法名 | 说明 | 参数 | 返回值 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| resize | 外层元素大小变化后,可以调用此方法来触发重绘 | - | void | | resize | 外层元素大小或组件显示状态变化时,可以调用此方法来触发重绘 | - | - |
| scrollTo `v2.9.3` | 滚动到指定的标签页,在滚动导航模式下可用 | name: 标识符 | void | | scrollTo `v2.9.3` | 滚动到指定的标签页,在滚动导航模式下可用 | name: 标识符 | - |
### Tabs Slots ### Tabs Slots
@ -293,3 +293,30 @@ export default {
| ------- | ---------- | | ------- | ---------- |
| default | 标签页内容 | | default | 标签页内容 |
| title | 自定义标题 | | title | 自定义标题 |
## 常见问题
### 组件从隐藏状态切换到显示状态时,底部条位置错误?
Tabs 组件在挂载时,会获取自身的宽度,并计算出底部条的位置。如果组件一开始处于隐藏状态,则获取到的宽度永远为 0因此无法展示底部条位置。
#### 解决方法
方法一,如果是使用 `v-show` 来控制组件展示的,则替换为 `v-if` 即可解决此问题:
```html
<!-- Before -->
<van-tabs v-show="show" />
<!-- After -->
<van-tabs v-if="show" />
```
方法二,调用组件的 resize 方法来主动触发重绘:
```html
<van-tabs v-show="show" ref="tabs" />
```
```js
this.$refs.tabs.resize();
```

View File

@ -331,10 +331,10 @@ exports[`swipe to switch tab 2`] = `
<div class="van-tabs van-tabs--line"> <div class="van-tabs van-tabs--line">
<div class="van-tabs__wrap"> <div class="van-tabs__wrap">
<div role="tablist" class="van-tabs__nav van-tabs__nav--line"> <div role="tablist" class="van-tabs__nav van-tabs__nav--line">
<div role="tab" aria-selected="true" class="van-tab van-tab--active"><span class="van-tab__text van-tab__text--ellipsis">title1</span></div> <div role="tab" class="van-tab"><span class="van-tab__text van-tab__text--ellipsis">title1</span></div>
<div role="tab" class="van-tab"><span class="van-tab__text van-tab__text--ellipsis">title2</span></div> <div role="tab" class="van-tab van-tab--active" aria-selected="true"><span class="van-tab__text van-tab__text--ellipsis">title2</span></div>
<div role="tab" class="van-tab van-tab--disabled"><span class="van-tab__text van-tab__text--ellipsis">title3</span></div> <div role="tab" class="van-tab van-tab--disabled"><span class="van-tab__text van-tab__text--ellipsis">title3</span></div>
<div class="van-tabs__line"></div> <div class="van-tabs__line" style="transform: translateX(0px) translateX(-50%);"></div>
</div> </div>
</div> </div>
<div class="van-tabs__content"> <div class="van-tabs__content">
@ -351,10 +351,10 @@ exports[`swipe to switch tab 3`] = `
<div class="van-tabs van-tabs--line"> <div class="van-tabs van-tabs--line">
<div class="van-tabs__wrap"> <div class="van-tabs__wrap">
<div role="tablist" class="van-tabs__nav van-tabs__nav--line"> <div role="tablist" class="van-tabs__nav van-tabs__nav--line">
<div role="tab" aria-selected="true" class="van-tab van-tab--active"><span class="van-tab__text van-tab__text--ellipsis">title1</span></div> <div role="tab" class="van-tab"><span class="van-tab__text van-tab__text--ellipsis">title1</span></div>
<div role="tab" class="van-tab"><span class="van-tab__text van-tab__text--ellipsis">title2</span></div> <div role="tab" class="van-tab van-tab--active" aria-selected="true"><span class="van-tab__text van-tab__text--ellipsis">title2</span></div>
<div role="tab" class="van-tab van-tab--disabled"><span class="van-tab__text van-tab__text--ellipsis">title3</span></div> <div role="tab" class="van-tab van-tab--disabled"><span class="van-tab__text van-tab__text--ellipsis">title3</span></div>
<div class="van-tabs__line"></div> <div class="van-tabs__line" style="transform: translateX(0px) translateX(-50%);"></div>
</div> </div>
</div> </div>
<div class="van-tabs__content"> <div class="van-tabs__content">

View File

@ -61,12 +61,17 @@ test('swipe to switch tab', async () => {
const onChange = jest.fn(); const onChange = jest.fn();
const wrapper = mount({ const wrapper = mount({
template: ` template: `
<van-tabs swipeable @change="onChange"> <van-tabs v-model="active" swipeable @change="onChange">
<van-tab title="title1">Text</van-tab> <van-tab title="title1">Text</van-tab>
<van-tab title="title2">Text</van-tab> <van-tab title="title2">Text</van-tab>
<van-tab title="title3" disabled>Text</van-tab> <van-tab title="title3" disabled>Text</van-tab>
</van-tabs> </van-tabs>
`, `,
data() {
return {
active: 0,
};
},
methods: { methods: {
onChange, onChange,
}, },
@ -174,7 +179,7 @@ test('name prop', async () => {
const wrapper = mount({ const wrapper = mount({
template: ` template: `
<van-tabs @click="onClick" @disabled="onDisabled" @change="onChange"> <van-tabs v-model="active" @click="onClick" @disabled="onDisabled" @change="onChange">
<van-tab title="title1" name="a">Text</van-tab> <van-tab title="title1" name="a">Text</van-tab>
<van-tab title="title2" name="b">Text</van-tab> <van-tab title="title2" name="b">Text</van-tab>
<van-tab title="title3" name="c" disabled>Text</van-tab> <van-tab title="title3" name="c" disabled>Text</van-tab>
@ -185,6 +190,11 @@ test('name prop', async () => {
onChange, onChange,
onDisabled, onDisabled,
}, },
data() {
return {
active: 0,
};
},
}); });
await later(); await later();

View File

@ -27,9 +27,10 @@ test('insert tab dynamically', async () => {
}); });
test('insert tab with name dynamically', async () => { test('insert tab with name dynamically', async () => {
const onChange = jest.fn();
const wrapper = mount({ const wrapper = mount({
template: ` template: `
<van-tabs v-model="active"> <van-tabs v-model="active" @change="onChange">
<van-tab v-if="insert" title="1" name="bar">2</van-tab> <van-tab v-if="insert" title="1" name="bar">2</van-tab>
<van-tab title="2" name="foo">1</van-tab> <van-tab title="2" name="foo">1</van-tab>
</van-tabs> </van-tabs>
@ -37,14 +38,18 @@ test('insert tab with name dynamically', async () => {
data() { data() {
return { return {
insert: false, insert: false,
active: [{ name: 'foo', title: 'foo' }], active: 'foo',
}; };
}, },
methods: {
onChange,
},
}); });
await later(); await later();
wrapper.setData({ insert: true }); wrapper.setData({ insert: true });
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
expect(onChange).toHaveBeenCalledTimes(0);
}); });
// this case will throw wierd error in index.spec.js // this case will throw wierd error in index.spec.js

View File

@ -218,15 +218,23 @@ export default createComponent({
}; };
const setCurrentIndex = (currentIndex) => { const setCurrentIndex = (currentIndex) => {
currentIndex = findAvailableTab(currentIndex); const newIndex = findAvailableTab(currentIndex);
if (isDef(currentIndex) && currentIndex !== state.currentIndex) { if (!isDef(newIndex)) {
const shouldEmitChange = state.currentIndex !== null; return;
state.currentIndex = currentIndex; }
emit('update:active', currentName.value);
const newTab = children[newIndex];
const newName = getTabName(newTab, newIndex);
const shouldEmitChange = state.currentIndex !== null;
state.currentIndex = newIndex;
if (newName !== props.active) {
emit('update:active', newName);
if (shouldEmitChange) { if (shouldEmitChange) {
emit('change', currentName.value, children[currentIndex].title); emit('change', newName, newTab.title);
} }
} }
}; };
@ -377,9 +385,9 @@ export default createComponent({
watch( watch(
() => children.length, () => children.length,
() => { () => {
setCurrentIndexByName(props.active || currentName.value);
setLine();
nextTick(() => { nextTick(() => {
setCurrentIndexByName(props.active || currentName.value);
setLine();
scrollIntoView(true); scrollIntoView(true);
}); });
} }

3
types/index.d.ts vendored
View File

@ -19,6 +19,7 @@ import { List } from './list';
import { Locale } from './locale'; import { Locale } from './locale';
import { Notify } from './notify'; import { Notify } from './notify';
import { Picker } from './picker'; import { Picker } from './picker';
import { Progress } from './progress';
import { Sku } from './sku'; import { Sku } from './sku';
import { Swipe } from './swipe'; import { Swipe } from './swipe';
import { SwipeCell } from './swipe-cell'; import { SwipeCell } from './swipe-cell';
@ -66,7 +67,6 @@ export class Pagination extends VanComponent {}
export class Panel extends VanComponent {} export class Panel extends VanComponent {}
export class PasswordInput extends VanComponent {} export class PasswordInput extends VanComponent {}
export class Popup extends VanComponent {} export class Popup extends VanComponent {}
export class Progress extends VanComponent {}
export class PullRefresh extends VanComponent {} export class PullRefresh extends VanComponent {}
export class Radio extends VanComponent {} export class Radio extends VanComponent {}
export class RadioGroup extends VanComponent {} export class RadioGroup extends VanComponent {}
@ -111,6 +111,7 @@ export {
Locale, Locale,
Notify, Notify,
Picker, Picker,
Progress,
Sku, Sku,
Swipe, Swipe,
SwipeCell, SwipeCell,

5
types/progress.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { VanComponent } from './component';
export class Progress extends VanComponent {
resize(): void;
}