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}
onScale={emitScale}
onClose={emitClose}
v-slots={{
image: slots.image,
}}
/>
))}
</Swipe>

View File

@ -47,7 +47,7 @@ export default defineComponent({
emits: ['scale', 'close'],
setup(props, { emit }) {
setup(props, { emit, slots }) {
const state = reactive({
scale: 1,
moveX: 0,
@ -293,14 +293,20 @@ export default defineComponent({
onTouchend={onTouchEnd}
onTouchcancel={onTouchEnd}
>
<Image
v-slots={imageSlots}
src={props.src}
fit="contain"
class={bem('image', { vertical: vertical.value })}
style={imageStyle.value}
onLoad={onLoad}
/>
{slots.image ? (
<div class={bem('image-wrap')}>
{slots.image({ src: props.src })}
</div>
) : (
<Image
v-slots={imageSlots}
src={props.src}
fit="contain"
class={bem('image', { vertical: vertical.value })}
style={imageStyle.value}
onLoad={onLoad}
/>
)}
</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
### Options
@ -218,6 +254,7 @@ imagePreviewRef.value?.swipeTo(1);
| --- | --- | --- |
| index | Custom index | { index: index of current image } |
| cover | Custom content that covers the image preview | - |
| image | Custom image slot | { src: current image src } |
### 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
### Options
@ -279,6 +315,7 @@ imagePreviewRef.value?.swipeTo(1);
| ----- | ------------------------------ | ------------------------- |
| index | 自定义页码内容 | { index: 当前图片的索引 } |
| cover | 自定义覆盖在图片预览上方的内容 | - |
| image | 自定义图片插槽 | { src: 当前资源地址 } |
### onClose 回调参数

View File

@ -17,6 +17,7 @@ const t = useTranslate({
customConfig: '传入配置项',
startPosition: '指定初始位置',
componentCall: '组件调用',
componentImage: '组件调用使用image插槽',
index: (index: number) => `${index + 1}`,
},
'en-US': {
@ -28,6 +29,7 @@ const t = useTranslate({
customConfig: 'Custom Config',
startPosition: 'Set Start Position',
componentCall: 'Component Call',
componentImage: 'Component Call use image slot',
index: (index: number) => `Page: ${index}`,
},
});
@ -39,9 +41,19 @@ const images = [
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 index = ref(0);
const showSlot = ref(false);
const indexSlot = ref(0);
const onClose = () => Toast(t('closed'));
const beforeClose = () =>
@ -59,6 +71,14 @@ const onChange = (newIndex: number) => {
index.value = newIndex;
};
const showComponentCallSlot = () => {
showSlot.value = true;
};
const onChangeSlot = (newIndex: number) => {
indexSlot.value = newIndex;
};
const showImagePreview = (options: Partial<ImagePreviewOptions> = {}) => {
const instance = ImagePreview({
images,
@ -110,4 +130,21 @@ const showImagePreview = (options: Partial<ImagePreviewOptions> = {}) => {
<template #index>{{ t('index', index) }}</template>
</van-image-preview>
</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>

View File

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

View File

@ -254,3 +254,36 @@ test('zoom out', async () => {
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();
});