feat(ImagePreview): add preview image slot (#11133)

This commit is contained in:
uniquker 2022-10-15 20:51:49 +08:00 committed by GitHub
parent 685351799e
commit 7d48159e65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 166 additions and 11 deletions

View File

@ -157,6 +157,9 @@ export default defineComponent({
rootHeight={state.rootHeight} rootHeight={state.rootHeight}
onScale={emitScale} onScale={emitScale}
onClose={emitClose} onClose={emitClose}
v-slots={{
image: slots.image,
}}
/> />
))} ))}
</Swipe> </Swipe>

View File

@ -47,7 +47,7 @@ export default defineComponent({
emits: ['scale', 'close'], emits: ['scale', 'close'],
setup(props, { emit }) { setup(props, { emit, slots }) {
const state = reactive({ const state = reactive({
scale: 1, scale: 1,
moveX: 0, moveX: 0,
@ -293,14 +293,20 @@ export default defineComponent({
onTouchend={onTouchEnd} onTouchend={onTouchEnd}
onTouchcancel={onTouchEnd} onTouchcancel={onTouchEnd}
> >
<Image {slots.image ? (
v-slots={imageSlots} <div class={bem('image-wrap')}>
src={props.src} {slots.image({ src: props.src })}
fit="contain" </div>
class={bem('image', { vertical: vertical.value })} ) : (
style={imageStyle.value} <Image
onLoad={onLoad} v-slots={imageSlots}
/> src={props.src}
fit="contain"
class={bem('image', { vertical: vertical.value })}
style={imageStyle.value}
onLoad={onLoad}
/>
)}
</SwipeItem> </SwipeItem>
); );
}; };

View File

@ -118,6 +118,42 @@ export default {
}; };
``` ```
### Component Call use image slot
```html
<van-image-preview v-model:show="show" :images="images" @change="onChange">
<template #image="{src}">
<video style="width: 100%;" controls><source :src="src" /></video>
</template>
</van-image-preview>
```
```js
import { ref } from 'vue';
export default {
setup() {
const show = ref(false);
const index = ref(0);
const images = [
'https://www.w3school.com.cn/i/movie.ogg',
'https://www.w3school.com.cn/i/movie.ogg',
'https://www.w3school.com.cn/i/movie.ogg',
];
const onChange = (newIndex) => {
index.value = newIndex;
};
return {
show,
index,
images,
onChange,
};
},
};
```
## API ## API
### Options ### Options
@ -218,6 +254,7 @@ imagePreviewRef.value?.swipeTo(1);
| --- | --- | --- | | --- | --- | --- |
| index | Custom index | { index: index of current image } | | index | Custom index | { index: index of current image } |
| cover | Custom content that covers the image preview | - | | cover | Custom content that covers the image preview | - |
| image | Custom image slot | { src: current image src } |
### onClose Parameters ### onClose Parameters

View File

@ -172,6 +172,42 @@ export default {
}; };
``` ```
### 组件调用 - 使用 image 插槽
```html
<van-image-preview v-model:show="show" :images="images" @change="onChange">
<template #image="{src}">
<video style="width: 100%;" controls><source :src="src" /></video>
</template>
</van-image-preview>
```
```js
import { ref } from 'vue';
export default {
setup() {
const show = ref(false);
const index = ref(0);
const images = [
'https://www.w3school.com.cn/i/movie.ogg',
'https://www.w3school.com.cn/i/movie.ogg',
'https://www.w3school.com.cn/i/movie.ogg',
];
const onChange = (newIndex) => {
index.value = newIndex;
};
return {
show,
index,
images,
onChange,
};
},
};
```
## API ## API
### Options ### Options
@ -279,6 +315,7 @@ imagePreviewRef.value?.swipeTo(1);
| ----- | ------------------------------ | ------------------------- | | ----- | ------------------------------ | ------------------------- |
| index | 自定义页码内容 | { index: 当前图片的索引 } | | index | 自定义页码内容 | { index: 当前图片的索引 } |
| cover | 自定义覆盖在图片预览上方的内容 | - | | cover | 自定义覆盖在图片预览上方的内容 | - |
| image | 自定义图片插槽 | { src: 当前资源地址 } |
### onClose 回调参数 ### onClose 回调参数

View File

@ -17,6 +17,7 @@ const t = useTranslate({
customConfig: '传入配置项', customConfig: '传入配置项',
startPosition: '指定初始位置', startPosition: '指定初始位置',
componentCall: '组件调用', componentCall: '组件调用',
componentImage: '组件调用使用image插槽',
index: (index: number) => `${index + 1}`, index: (index: number) => `${index + 1}`,
}, },
'en-US': { 'en-US': {
@ -28,6 +29,7 @@ const t = useTranslate({
customConfig: 'Custom Config', customConfig: 'Custom Config',
startPosition: 'Set Start Position', startPosition: 'Set Start Position',
componentCall: 'Component Call', componentCall: 'Component Call',
componentImage: 'Component Call use image slot',
index: (index: number) => `Page: ${index}`, index: (index: number) => `Page: ${index}`,
}, },
}); });
@ -39,9 +41,19 @@ const images = [
cdnURL('apple-4.jpeg'), cdnURL('apple-4.jpeg'),
]; ];
const imagesSlot = [
'https://www.w3school.com.cn/i/movie.ogg',
'https://www.w3school.com.cn/i/movie.ogg',
'https://www.w3school.com.cn/i/movie.ogg',
'https://www.w3school.com.cn/i/movie.ogg',
];
const show = ref(false); const show = ref(false);
const index = ref(0); const index = ref(0);
const showSlot = ref(false);
const indexSlot = ref(0);
const onClose = () => Toast(t('closed')); const onClose = () => Toast(t('closed'));
const beforeClose = () => const beforeClose = () =>
@ -59,6 +71,14 @@ const onChange = (newIndex: number) => {
index.value = newIndex; index.value = newIndex;
}; };
const showComponentCallSlot = () => {
showSlot.value = true;
};
const onChangeSlot = (newIndex: number) => {
indexSlot.value = newIndex;
};
const showImagePreview = (options: Partial<ImagePreviewOptions> = {}) => { const showImagePreview = (options: Partial<ImagePreviewOptions> = {}) => {
const instance = ImagePreview({ const instance = ImagePreview({
images, images,
@ -110,4 +130,21 @@ const showImagePreview = (options: Partial<ImagePreviewOptions> = {}) => {
<template #index>{{ t('index', index) }}</template> <template #index>{{ t('index', index) }}</template>
</van-image-preview> </van-image-preview>
</demo-block> </demo-block>
<demo-block card :title="t('componentImage')">
<van-cell
is-link
:value="t('componentImage')"
@click="showComponentCallSlot"
/>
<van-image-preview
v-model:show="showSlot"
:images="imagesSlot"
@change="onChangeSlot"
>
<template #image="{ src }">
<video style="width: 100%" controls><source :src="src" /></video>
</template>
</van-image-preview>
</demo-block>
</template> </template>

View File

@ -38,7 +38,8 @@
left: 0; left: 0;
} }
&__image { &__image,
&__image-wrap {
width: 100%; width: 100%;
transition-property: transform; transition-property: transform;
@ -47,7 +48,8 @@
height: 100%; height: 100%;
} }
img { img,
video {
// disable desktop browser image drag // disable desktop browser image drag
-webkit-user-drag: none; -webkit-user-drag: none;
} }

View File

@ -254,3 +254,36 @@ test('zoom out', async () => {
restore(); restore();
}); });
test('should render image slot correctly', async () => {
const wrapper = mount(ImagePreviewComponent, {
props: {
show: true,
images,
},
slots: {
image: ({ src }) => `<img class="test-img" src="${src}" />`,
},
});
await later();
expect(wrapper.html().includes('test-img')).toBeTruthy();
});
test('should render image slot correctly 2', async () => {
const wrapper = mount(ImagePreviewComponent, {
props: {
show: true,
images,
},
slots: {
image: ({ src }) =>
`<video style="width: 100%;" controls><source src="${src}" /></video>`,
},
});
await later();
expect(wrapper.html().includes('video')).toBeTruthy();
});