diff --git a/src/image-preview/ImagePreview.js b/src/image-preview/ImagePreview.js index 59a22f176..60e030fe4 100644 --- a/src/image-preview/ImagePreview.js +++ b/src/image-preview/ImagePreview.js @@ -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({ ); }, + + genClose() { + if (this.closeable) { + return ( + + ); + } + }, }, render() { @@ -341,6 +368,7 @@ export default createComponent({ return (
+ {this.genClose()} {this.genImages()} {this.genIndex()} {this.genCover()} diff --git a/src/image-preview/README.md b/src/image-preview/README.md index 47ab9ea65..8168a0aeb 100644 --- a/src/image-preview/README.md +++ b/src/image-preview/README.md @@ -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 load,should 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 position,can 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 load,should 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 position,can be set to `top-left` `bottom-left` `bottom-right` | *string* | `top-right` | ### Events diff --git a/src/image-preview/README.zh-CN.md b/src/image-preview/README.zh-CN.md index 20d1b910c..eaa52bc23 100644 --- a/src/image-preview/README.zh-CN.md +++ b/src/image-preview/README.zh-CN.md @@ -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`
`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`
`bottom-left` `bottom-right` | *string* | `top-right` | + ### Events diff --git a/src/image-preview/demo/index.vue b/src/image-preview/demo/index.vue index 7ceadf5ce..f3ef3fa9e 100644 --- a/src/image-preview/demo/index.vue +++ b/src/image-preview/demo/index.vue @@ -12,6 +12,12 @@ + + + {{ $t('button4') }} + + + {{ $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, }); diff --git a/src/image-preview/index.js b/src/image-preview/index.js index da75d722c..ad41607d5 100644 --- a/src/image-preview/index.js +++ b/src/image-preview/index.js @@ -20,6 +20,9 @@ const defaultConfig = { swipeDuration: 500, showIndicators: false, closeOnPopstate: false, + closeable: false, + closeIcon: 'clear', + closeIconPosition: 'top-right', }; const initInstance = () => { diff --git a/src/image-preview/index.less b/src/image-preview/index.less index d66da0cf3..fe73b3610 100644 --- a/src/image-preview/index.less +++ b/src/image-preview/index.less @@ -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; + } + } } diff --git a/src/image-preview/test/__snapshots__/index.spec.js.snap b/src/image-preview/test/__snapshots__/index.spec.js.snap index 9708d5c6f..515c5e9f8 100644 --- a/src/image-preview/test/__snapshots__/index.spec.js.snap +++ b/src/image-preview/test/__snapshots__/index.spec.js.snap @@ -10,6 +10,26 @@ exports[`cover slot 1`] = `
`; +exports[`close-icon prop 1`] = ` +
+ +
+
+
+
1 / 0
+
+`; + +exports[`close-icon-position prop 1`] = ` +
+ +
+
+
+
1 / 0
+
+`; + exports[`index slot 1`] = `
diff --git a/src/image-preview/test/index.spec.js b/src/image-preview/test/index.spec.js index 98001a10a..4c1a4eca2 100644 --- a/src/image-preview/test/index.spec.js +++ b/src/image-preview/test/index.spec.js @@ -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: { diff --git a/src/style/var.less b/src/style/var.less index 3ed3c104a..2b5e92a07 100644 --- a/src/style/var.less +++ b/src/style/var.less @@ -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;