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 Swipe from '../swipe';
import Loading from '../loading'; import Loading from '../loading';
import SwipeItem from '../swipe-item'; import SwipeItem from '../swipe-item';
import Icon from '../icon';
const [createComponent, bem] = createNamespace('image-preview'); const [createComponent, bem] = createNamespace('image-preview');
@ -71,6 +72,15 @@ export default createComponent({
type: String, type: String,
default: bem('overlay'), default: bem('overlay'),
}, },
closeable: Boolean,
closeIcon: {
type: String,
default: 'clear',
},
closeIconPosition: {
type: String,
default: 'top-right',
},
}, },
data() { data() {
@ -137,6 +147,12 @@ export default createComponent({
}, },
methods: { methods: {
emitClose() {
if (!this.asyncClose) {
this.$emit('input', false);
}
},
onWrapperTouchStart() { onWrapperTouchStart() {
this.touchStartTime = new Date(); this.touchStartTime = new Date();
}, },
@ -151,9 +167,7 @@ export default createComponent({
if (deltaTime < 300 && offsetX < 10 && offsetY < 10) { if (deltaTime < 300 && offsetX < 10 && offsetY < 10) {
if (!this.doubleClickTimer) { if (!this.doubleClickTimer) {
this.doubleClickTimer = setTimeout(() => { this.doubleClickTimer = setTimeout(() => {
if (!this.asyncClose) { this.emitClose();
this.$emit('input', false);
}
this.doubleClickTimer = null; this.doubleClickTimer = null;
}, 300); }, 300);
@ -331,6 +345,19 @@ export default createComponent({
</Swipe> </Swipe>
); );
}, },
genClose() {
if (this.closeable) {
return (
<Icon
role="button"
name={this.closeIcon}
class={bem('close-icon', this.closeIconPosition)}
onClick={this.emitClose}
/>
);
}
},
}, },
render() { render() {
@ -341,6 +368,7 @@ export default createComponent({
return ( return (
<transition name="van-fade"> <transition name="van-fade">
<div vShow={this.value} class={[bem(), this.className]}> <div vShow={this.value} class={[bem(), this.className]}>
{this.genClose()}
{this.genImages()} {this.genImages()}
{this.genIndex()} {this.genIndex()}
{this.genCover()} {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 ### Async Close
```js ```js
@ -100,6 +114,9 @@ export default {
| lazyLoad | Whether to enable thumb lazy loadshould register [Lazyload](#/en-US/lazyload) component | *boolean* | `false` | | lazyLoad | Whether to enable thumb lazy loadshould register [Lazyload](#/en-US/lazyload) component | *boolean* | `false` |
| maxZoom | Max zoom | *number \| string* | `3` | | maxZoom | Max zoom | *number \| string* | `3` |
| minZoom | Min zoom | *number \| string* | `1/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 ### Props
@ -117,6 +134,9 @@ export default {
| lazy-load | Whether to enable thumb lazy loadshould register [Lazyload](#/en-US/lazyload) component | *boolean* | `false` | | lazy-load | Whether to enable thumb lazy loadshould register [Lazyload](#/en-US/lazyload) component | *boolean* | `false` |
| max-zoom | Max zoom | *number \| string* | `3` | | max-zoom | Max zoom | *number \| string* | `3` |
| min-zoom | Min zoom | *number \| string* | `1/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 ### 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 方法关闭图片预览 通过`asyncClose`属性可以开启异步关闭,开启后异步关闭后,只能通过实例上的 close 方法关闭图片预览
@ -112,6 +126,9 @@ export default {
| lazyLoad | 是否开启图片懒加载,须配合 [Lazyload](#/zh-CN/lazyload) 组件使用 | *boolean* | `false` | | lazyLoad | 是否开启图片懒加载,须配合 [Lazyload](#/zh-CN/lazyload) 组件使用 | *boolean* | `false` |
| maxZoom | 手势缩放时,最大缩放比例 | *number \| string* | `3` | | maxZoom | 手势缩放时,最大缩放比例 | *number \| string* | `3` |
| minZoom | 手势缩放时,最小缩放比例 | *number \| string* | `1/3` | | minZoom | 手势缩放时,最小缩放比例 | *number \| string* | `1/3` |
| closeable | 是否显示关闭图标 | *boolean* | `false` |
| closeIcon | 关闭图标名称或图片链接 | *string* | `clear` |
| closeIconPosition | 关闭图标位置,可选值为`top-left`<br>`bottom-left` `bottom-right` | *string* | `top-right` |
### Props ### Props
@ -131,6 +148,10 @@ export default {
| lazy-load | 是否开启图片懒加载,须配合 [Lazyload](#/zh-CN/lazyload) 组件使用 | *boolean* | `false` | | lazy-load | 是否开启图片懒加载,须配合 [Lazyload](#/zh-CN/lazyload) 组件使用 | *boolean* | `false` |
| max-zoom | 手势缩放时,最大缩放比例 | *number \| string* | `3` | | max-zoom | 手势缩放时,最大缩放比例 | *number \| string* | `3` |
| min-zoom | 手势缩放时,最小缩放比例 | *number \| string* | `1/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 ### Events

View File

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

View File

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

View File

@ -59,4 +59,36 @@
&__overlay { &__overlay {
background-color: @image-preview-overlay-background-color; 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> </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`] = ` exports[`index slot 1`] = `
<div class="van-image-preview" name="van-fade"> <div class="van-image-preview" name="van-fade">
<div class="van-swipe van-image-preview__swipe"> <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); 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 () => { test('async close prop', async () => {
const wrapper = mount(ImagePreviewVue, { const wrapper = mount(ImagePreviewVue, {
propsData: { propsData: {

View File

@ -411,6 +411,11 @@
@image-preview-index-font-size: @font-size-md; @image-preview-index-font-size: @font-size-md;
@image-preview-index-text-shadow: 0 1px 1px @gray-8; @image-preview-index-text-shadow: 0 1px 1px @gray-8;
@image-preview-overlay-background-color: rgba(0, 0, 0, 0.9); @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
@list-icon-margin-right: 5px; @list-icon-margin-right: 5px;