mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(ImagePreview): add preview image slot (#11133)
This commit is contained in:
parent
e1d24caa98
commit
1f77796bad
@ -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>
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 回调参数
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user