feat(ImagePreview): add closeable prop (#5654)

This commit is contained in:
landluck 2020-02-14 14:47:21 +08:00 committed by GitHub
parent 1d8e2654f5
commit 85a3707202
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 180 additions and 4 deletions

View File

@ -12,6 +12,7 @@ import Image from '../image';
import Swipe from '../swipe';
import Loading from '../loading';
import SwipeItem from '../swipe-item';
import Icon from '../icon';
const [createComponent, bem] = createNamespace('image-preview');
@ -71,6 +72,15 @@ export default createComponent({
type: String,
default: bem('overlay'),
},
closeable: Boolean,
closeIcon: {
type: String,
default: 'clear',
},
closeIconPosition: {
type: String,
default: 'top-right',
},
},
data() {
@ -137,6 +147,12 @@ export default createComponent({
},
methods: {
emitClose() {
if (!this.asyncClose) {
this.$emit('input', false);
}
},
onWrapperTouchStart() {
this.touchStartTime = new Date();
},
@ -151,9 +167,7 @@ export default createComponent({
if (deltaTime < 300 && offsetX < 10 && offsetY < 10) {
if (!this.doubleClickTimer) {
this.doubleClickTimer = setTimeout(() => {
if (!this.asyncClose) {
this.$emit('input', false);
}
this.emitClose();
this.doubleClickTimer = null;
}, 300);
@ -331,6 +345,19 @@ export default createComponent({
</Swipe>
);
},
genClose() {
if (this.closeable) {
return (
<Icon
role="button"
name={this.closeIcon}
class={bem('close-icon', this.closeIconPosition)}
onClick={this.emitClose}
/>
);
}
},
},
render() {
@ -341,6 +368,7 @@ export default createComponent({
return (
<transition name="van-fade">
<div vShow={this.value} class={[bem(), this.className]}>
{this.genClose()}
{this.genImages()}
{this.genIndex()}
{this.genCover()}

View File

@ -35,6 +35,20 @@ ImagePreview({
});
```
### Show Close Icon
After setting the `closeable` attribute, the close icon will be displayed in the upper right corner of the pop-up layer, and the icon can be customized through the `close-icon` attribute, and the icon location can be customized by using the `close-icon-position` attribute
```js
ImagePreview({
images: [
'https://img.yzcdn.cn/1.jpg',
'https://img.yzcdn.cn/2.jpg'
],
closeable: true
});
```
### Async Close
```js
@ -100,6 +114,9 @@ export default {
| lazyLoad | Whether to enable thumb lazy loadshould register [Lazyload](#/en-US/lazyload) component | *boolean* | `false` |
| maxZoom | Max zoom | *number \| string* | `3` |
| minZoom | Min zoom | *number \| string* | `1/3` |
| closeable | Whether to show close icon | *boolean* | `false` |
| closeIcon | Close icon name | *string* | `clear` |
| closeIconPosition | Close icon positioncan be set to `top-left` `bottom-left` `bottom-right` | *string* | `top-right` |
### Props
@ -117,6 +134,9 @@ export default {
| lazy-load | Whether to enable thumb lazy loadshould register [Lazyload](#/en-US/lazyload) component | *boolean* | `false` |
| max-zoom | Max zoom | *number \| string* | `3` |
| min-zoom | Min zoom | *number \| string* | `1/3` |
| closeable | Whether to show close icon | *boolean* | `false` |
| close-icon | Close icon name | *string* | `clear` |
| close-icon-position | Close icon positioncan be set to `top-left` `bottom-left` `bottom-right` | *string* | `top-right` |
### Events

View File

@ -41,6 +41,20 @@ ImagePreview({
});
```
### 展示关闭按钮
设置`closeable`属性后,会在弹出层的右上角显示关闭图标,并且可以通过`close-icon`属性自定义图标,使用`close-icon-position`属性可以自定义图标位置
```js
ImagePreview({
images: [
'https://img.yzcdn.cn/1.jpg',
'https://img.yzcdn.cn/2.jpg'
],
closeable: true
});
```
### 异步关闭
通过`asyncClose`属性可以开启异步关闭,开启后异步关闭后,只能通过实例上的 close 方法关闭图片预览
@ -112,6 +126,9 @@ export default {
| lazyLoad | 是否开启图片懒加载,须配合 [Lazyload](#/zh-CN/lazyload) 组件使用 | *boolean* | `false` |
| maxZoom | 手势缩放时,最大缩放比例 | *number \| string* | `3` |
| minZoom | 手势缩放时,最小缩放比例 | *number \| string* | `1/3` |
| closeable | 是否显示关闭图标 | *boolean* | `false` |
| closeIcon | 关闭图标名称或图片链接 | *string* | `clear` |
| closeIconPosition | 关闭图标位置,可选值为`top-left`<br>`bottom-left` `bottom-right` | *string* | `top-right` |
### Props
@ -131,6 +148,10 @@ export default {
| lazy-load | 是否开启图片懒加载,须配合 [Lazyload](#/zh-CN/lazyload) 组件使用 | *boolean* | `false` |
| max-zoom | 手势缩放时,最大缩放比例 | *number \| string* | `3` |
| min-zoom | 手势缩放时,最小缩放比例 | *number \| string* | `1/3` |
| closeable | 是否显示关闭图标 | *boolean* | `false` |
| close-icon | 关闭图标名称或图片链接 | *string* | `clear` |
| close-icon-position | 关闭图标位置,可选值为`top-left`<br>`bottom-left` `bottom-right` | *string* | `top-right` |
### Events

View File

@ -12,6 +12,12 @@
</van-button>
</demo-block>
<demo-block :title="$t('button4')">
<van-button type="primary" @click="showImagePreview(0, 0, true)">
{{ $t('button4') }}
</van-button>
</demo-block>
<demo-block :title="$t('button3')">
<van-button type="primary" @click="showImagePreview(0, 3000)">
{{ $t('button3') }}
@ -45,6 +51,7 @@ export default {
button1: '预览图片',
button2: '指定初始位置',
button3: '异步关闭',
button4: '展示关闭按钮',
componentCall: '组件调用',
index: index => `${index + 1}`,
},
@ -52,6 +59,7 @@ export default {
button1: 'Show Images',
button2: 'Custom Start Position',
button3: 'Async Close',
button4: 'Show Close Icon',
componentCall: 'Component Call',
index: index => `Page: ${index}`,
},
@ -74,12 +82,13 @@ export default {
this.index = index;
},
showImagePreview(position, timer) {
showImagePreview(position, timer, closeable) {
const instance = ImagePreview({
images,
lazyLoad: true,
swipeDuration: 300,
asyncClose: !!timer,
closeable,
closeOnPopstate: true,
startPosition: typeof position === 'number' ? position : 0,
});

View File

@ -20,6 +20,9 @@ const defaultConfig = {
swipeDuration: 500,
showIndicators: false,
closeOnPopstate: false,
closeable: false,
closeIcon: 'clear',
closeIconPosition: 'top-right',
};
const initInstance = () => {

View File

@ -59,4 +59,36 @@
&__overlay {
background-color: @image-preview-overlay-background-color;
}
&__close-icon {
position: absolute;
z-index: @image-preview-close-icon-z-index;
color: @image-preview-close-icon-color;
font-size: @image-preview-close-icon-size;
cursor: pointer;
&:active {
color: @image-preview-close-icon-active-color;
}
&--top-left {
top: @image-preview-close-icon-margin;
left: @image-preview-close-icon-margin;
}
&--top-right {
top: @image-preview-close-icon-margin;
right: @image-preview-close-icon-margin;
}
&--bottom-left {
bottom: @image-preview-close-icon-margin;
left: @image-preview-close-icon-margin;
}
&--bottom-right {
right: @image-preview-close-icon-margin;
bottom: @image-preview-close-icon-margin;
}
}
}

View File

@ -10,6 +10,26 @@ exports[`cover slot 1`] = `
</div>
`;
exports[`close-icon prop 1`] = `
<div class="van-image-preview" name="van-fade"><i role="button" class="van-icon van-icon-close van-image-preview__close-icon van-image-preview__close-icon--top-right">
<!----></i>
<div class="van-swipe van-image-preview__swipe">
<div class="van-swipe__track" style="width: 0px; transition-duration: 0ms; transform: translateX(0px);"></div>
</div>
<div class="van-image-preview__index">1 / 0</div>
</div>
`;
exports[`close-icon-position prop 1`] = `
<div class="van-image-preview" name="van-fade"><i role="button" class="van-icon van-icon-close van-image-preview__close-icon van-image-preview__close-icon--top-left">
<!----></i>
<div class="van-swipe van-image-preview__swipe">
<div class="van-swipe__track" style="width: 0px; transition-duration: 0ms; transform: translateX(0px);"></div>
</div>
<div class="van-image-preview__index">1 / 0</div>
</div>
`;
exports[`index slot 1`] = `
<div class="van-image-preview" name="van-fade">
<div class="van-swipe van-image-preview__swipe">

View File

@ -38,6 +38,44 @@ test('render image', async () => {
expect(wrapper.emitted('change')[0][0]).toEqual(2);
});
test('closeable prop', () => {
const wrapper = mount(ImagePreviewVue, {
propsData: {
images,
value: true,
closeable: true,
},
});
wrapper.find('.van-image-preview__close-icon').trigger('click');
expect(wrapper.emitted('input')[0][0]).toEqual(false);
});
test('close-icon prop', () => {
const wrapper = mount(ImagePreviewVue, {
propsData: {
value: true,
closeable: true,
closeIcon: 'close',
},
});
expect(wrapper).toMatchSnapshot();
});
test('close-icon-position prop', () => {
const wrapper = mount(ImagePreviewVue, {
propsData: {
value: true,
closeable: true,
closeIcon: 'close',
closeIconPosition: 'top-left',
},
});
expect(wrapper).toMatchSnapshot();
});
test('async close prop', async () => {
const wrapper = mount(ImagePreviewVue, {
propsData: {

View File

@ -411,6 +411,11 @@
@image-preview-index-font-size: @font-size-md;
@image-preview-index-text-shadow: 0 1px 1px @gray-8;
@image-preview-overlay-background-color: rgba(0, 0, 0, 0.9);
@image-preview-close-icon-size: 22px;
@image-preview-close-icon-color: @gray-5;
@image-preview-close-icon-active-color: @gray-6;
@image-preview-close-icon-margin: @padding-md;
@image-preview-close-icon-z-index: 1;
// List
@list-icon-margin-right: 5px;