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

This commit is contained in:
uniquker 2022-10-15 20:51:49 +08:00 committed by chenjiahan
parent e1d24caa98
commit 1f77796bad
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

@ -138,6 +138,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
### Methods ### Methods
@ -246,6 +282,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

@ -149,6 +149,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
### 方法 ### 方法
@ -264,6 +300,7 @@ imagePreviewRef.value?.swipeTo(1);
| ----- | ------------------------------ | ------------------------- | | ----- | ------------------------------ | ------------------------- |
| index | 自定义页码内容 | { index: 当前图片的索引 } | | index | 自定义页码内容 | { index: 当前图片的索引 } |
| cover | 自定义覆盖在图片预览上方的内容 | - | | cover | 自定义覆盖在图片预览上方的内容 | - |
| image | 自定义图片插槽 | { src: 当前资源地址 } |
### onClose 回调参数 ### onClose 回调参数

View File

@ -19,6 +19,7 @@ const t = useTranslate({
customConfig: '传入配置项', customConfig: '传入配置项',
startPosition: '指定初始位置', startPosition: '指定初始位置',
useComponent: '使用 ImagePreview 组件', useComponent: '使用 ImagePreview 组件',
componentImage: '组件调用使用image插槽',
index: (index: number) => `${index + 1}`, index: (index: number) => `${index + 1}`,
}, },
'en-US': { 'en-US': {
@ -30,6 +31,7 @@ const t = useTranslate({
customConfig: 'Custom Config', customConfig: 'Custom Config',
startPosition: 'Set Start Position', startPosition: 'Set Start Position',
useComponent: 'Use ImagePreview Component', useComponent: 'Use ImagePreview Component',
componentImage: 'Component Call use image slot',
index: (index: number) => `Page: ${index}`, index: (index: number) => `Page: ${index}`,
}, },
}); });
@ -41,9 +43,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 = () => showToast(t('closed')); const onClose = () => showToast(t('closed'));
const beforeClose = () => const beforeClose = () =>
@ -61,6 +73,14 @@ const showComponentCall = () => {
show.value = true; show.value = true;
}; };
const showComponentCallSlot = () => {
showSlot.value = true;
};
const onChangeSlot = (newIndex: number) => {
indexSlot.value = newIndex;
};
const showFunctionCall = (options: Partial<ImagePreviewOptions> = {}) => { const showFunctionCall = (options: Partial<ImagePreviewOptions> = {}) => {
const instance = showImagePreview({ const instance = showImagePreview({
images, images,
@ -112,4 +132,21 @@ const showFunctionCall = (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

@ -37,7 +37,8 @@
left: 0; left: 0;
} }
&__image { &__image,
&__image-wrap {
width: 100%; width: 100%;
transition-property: transform; transition-property: transform;
@ -46,7 +47,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();
});