mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-03 03:38:41 +08:00
feat(components): [el-image] support append preview to body (#5883)
* feat(components): [el-image] support append preview to body * chore: add deprecated warning * chore: compatible with append-to-body and get zIndex from PopupManager * fix: apply transition on the initial render * fix: PopupManager import * fix: modify default value * chore: rename to teleported * chore: rename to teleported * fix: resolve import issue * fix: resolve import issue * fix: resolve import issue
This commit is contained in:
parent
b6be179a2c
commit
dcb7365365
@ -8,7 +8,6 @@ export const imageViewerProps = buildProps({
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 2000,
|
||||
},
|
||||
initialIndex: {
|
||||
type: Number,
|
||||
@ -22,6 +21,10 @@ export const imageViewerProps = buildProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
teleported: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
} as const)
|
||||
export type ImageViewerProps = ExtractPropTypes<typeof imageViewerProps>
|
||||
|
||||
|
@ -1,81 +1,83 @@
|
||||
<template>
|
||||
<transition name="viewer-fade">
|
||||
<div
|
||||
ref="wrapper"
|
||||
:tabindex="-1"
|
||||
:class="ns.e('wrapper')"
|
||||
:style="{ zIndex }"
|
||||
>
|
||||
<div :class="ns.e('mask')" @click.self="hideOnClickModal && hide()" />
|
||||
<teleport to="body" :disabled="!teleported">
|
||||
<transition name="viewer-fade" appear>
|
||||
<div
|
||||
ref="wrapper"
|
||||
:tabindex="-1"
|
||||
:class="ns.e('wrapper')"
|
||||
:style="{ zIndex: computedZIndex }"
|
||||
>
|
||||
<div :class="ns.e('mask')" @click.self="hideOnClickModal && hide()" />
|
||||
|
||||
<!-- CLOSE -->
|
||||
<span :class="[ns.e('btn'), ns.e('close')]" @click="hide">
|
||||
<el-icon><close /></el-icon>
|
||||
</span>
|
||||
<!-- CLOSE -->
|
||||
<span :class="[ns.e('btn'), ns.e('close')]" @click="hide">
|
||||
<el-icon><close /></el-icon>
|
||||
</span>
|
||||
|
||||
<!-- ARROW -->
|
||||
<template v-if="!isSingle">
|
||||
<span
|
||||
:class="[
|
||||
ns.e('btn'),
|
||||
ns.e('prev'),
|
||||
ns.is('disabled', !infinite && isFirst),
|
||||
]"
|
||||
@click="prev"
|
||||
>
|
||||
<el-icon><arrow-left /></el-icon>
|
||||
</span>
|
||||
<span
|
||||
:class="[
|
||||
ns.e('btn'),
|
||||
ns.e('next'),
|
||||
ns.is('disabled', !infinite && isLast),
|
||||
]"
|
||||
@click="next"
|
||||
>
|
||||
<el-icon><arrow-right /></el-icon>
|
||||
</span>
|
||||
</template>
|
||||
<!-- ACTIONS -->
|
||||
<div :class="[ns.e('btn'), ns.e('actions')]">
|
||||
<div :class="ns.e('actions__inner')">
|
||||
<el-icon @click="handleActions('zoomOut')">
|
||||
<zoom-out />
|
||||
</el-icon>
|
||||
<el-icon @click="handleActions('zoomIn')">
|
||||
<zoom-in />
|
||||
</el-icon>
|
||||
<i :class="ns.e('actions__divider')"></i>
|
||||
<el-icon @click="toggleMode">
|
||||
<component :is="mode.icon" />
|
||||
</el-icon>
|
||||
<i :class="ns.e('actions__divider')"></i>
|
||||
<el-icon @click="handleActions('anticlockwise')">
|
||||
<refresh-left />
|
||||
</el-icon>
|
||||
<el-icon @click="handleActions('clockwise')">
|
||||
<refresh-right />
|
||||
</el-icon>
|
||||
<!-- ARROW -->
|
||||
<template v-if="!isSingle">
|
||||
<span
|
||||
:class="[
|
||||
ns.e('btn'),
|
||||
ns.e('prev'),
|
||||
ns.is('disabled', !infinite && isFirst),
|
||||
]"
|
||||
@click="prev"
|
||||
>
|
||||
<el-icon><arrow-left /></el-icon>
|
||||
</span>
|
||||
<span
|
||||
:class="[
|
||||
ns.e('btn'),
|
||||
ns.e('next'),
|
||||
ns.is('disabled', !infinite && isLast),
|
||||
]"
|
||||
@click="next"
|
||||
>
|
||||
<el-icon><arrow-right /></el-icon>
|
||||
</span>
|
||||
</template>
|
||||
<!-- ACTIONS -->
|
||||
<div :class="[ns.e('btn'), ns.e('actions')]">
|
||||
<div :class="ns.e('actions__inner')">
|
||||
<el-icon @click="handleActions('zoomOut')">
|
||||
<zoom-out />
|
||||
</el-icon>
|
||||
<el-icon @click="handleActions('zoomIn')">
|
||||
<zoom-in />
|
||||
</el-icon>
|
||||
<i :class="ns.e('actions__divider')"></i>
|
||||
<el-icon @click="toggleMode">
|
||||
<component :is="mode.icon" />
|
||||
</el-icon>
|
||||
<i :class="ns.e('actions__divider')"></i>
|
||||
<el-icon @click="handleActions('anticlockwise')">
|
||||
<refresh-left />
|
||||
</el-icon>
|
||||
<el-icon @click="handleActions('clockwise')">
|
||||
<refresh-right />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<!-- CANVAS -->
|
||||
<div :class="ns.e('canvas')">
|
||||
<img
|
||||
v-for="(url, i) in urlList"
|
||||
v-show="i === index"
|
||||
:ref="(el) => (imgRefs[i] = el)"
|
||||
:key="url"
|
||||
:src="url"
|
||||
:style="imgStyle"
|
||||
:class="ns.e('img')"
|
||||
@load="handleImgLoad"
|
||||
@error="handleImgError"
|
||||
@mousedown="handleMouseDown"
|
||||
/>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
<!-- CANVAS -->
|
||||
<div :class="ns.e('canvas')">
|
||||
<img
|
||||
v-for="(url, i) in urlList"
|
||||
v-show="i === index"
|
||||
:ref="(el) => (imgRefs[i] = el)"
|
||||
:key="url"
|
||||
:src="url"
|
||||
:style="imgStyle"
|
||||
:class="ns.e('img')"
|
||||
@load="handleImgLoad"
|
||||
@error="handleImgError"
|
||||
@mousedown="handleMouseDown"
|
||||
/>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
</transition>
|
||||
</transition>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -89,12 +91,12 @@ import {
|
||||
effectScope,
|
||||
markRaw,
|
||||
} from 'vue'
|
||||
import { useEventListener } from '@vueuse/core'
|
||||
import { useEventListener, isNumber } from '@vueuse/core'
|
||||
import { throttle } from 'lodash-unified'
|
||||
import ElIcon from '@element-plus/components/icon'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import { isFirefox } from '@element-plus/utils'
|
||||
import { useLocale, useNamespace, useZIndex } from '@element-plus/hooks'
|
||||
import { EVENT_CODE } from '@element-plus/constants'
|
||||
import { isFirefox } from '@element-plus/utils'
|
||||
import {
|
||||
Close,
|
||||
ArrowLeft,
|
||||
@ -146,6 +148,7 @@ export default defineComponent({
|
||||
setup(props, { emit }) {
|
||||
const { t } = useLocale()
|
||||
const ns = useNamespace('image-viewer')
|
||||
const { nextZIndex } = useZIndex()
|
||||
const wrapper = ref<HTMLDivElement>()
|
||||
const imgRefs = ref<any[]>([])
|
||||
|
||||
@ -209,6 +212,10 @@ export default defineComponent({
|
||||
return style
|
||||
})
|
||||
|
||||
const computedZIndex = computed(() => {
|
||||
return isNumber(props.zIndex) ? props.zIndex : nextZIndex()
|
||||
})
|
||||
|
||||
function hide() {
|
||||
unregisterEventListener()
|
||||
emit('close')
|
||||
@ -404,6 +411,7 @@ export default defineComponent({
|
||||
currentImg,
|
||||
imgStyle,
|
||||
mode,
|
||||
computedZIndex,
|
||||
handleActions,
|
||||
prev,
|
||||
next,
|
||||
|
@ -10,7 +10,7 @@ import type { ExtractPropTypes } from 'vue'
|
||||
export const imageProps = buildProps({
|
||||
appendToBody: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
default: undefined,
|
||||
},
|
||||
hideOnClickModal: {
|
||||
type: Boolean,
|
||||
@ -36,9 +36,12 @@ export const imageProps = buildProps({
|
||||
type: definePropType<string[]>(Array),
|
||||
default: () => mutable([] as const),
|
||||
},
|
||||
previewTeleported: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 2000,
|
||||
},
|
||||
initialIndex: {
|
||||
type: Number,
|
||||
|
@ -14,31 +14,40 @@
|
||||
:class="[ns.e('inner'), preview ? ns.e('preview') : '']"
|
||||
@click="clickHandler"
|
||||
/>
|
||||
<teleport to="body" :disabled="!appendToBody">
|
||||
<template v-if="preview">
|
||||
<image-viewer
|
||||
v-if="showViewer"
|
||||
:z-index="zIndex"
|
||||
:initial-index="imageIndex"
|
||||
:url-list="previewSrcList"
|
||||
:hide-on-click-modal="hideOnClickModal"
|
||||
@close="closeViewer"
|
||||
@switch="switchViewer"
|
||||
>
|
||||
<div v-if="$slots.viewer">
|
||||
<slot name="viewer" />
|
||||
</div>
|
||||
</image-viewer>
|
||||
</template>
|
||||
</teleport>
|
||||
<template v-if="preview">
|
||||
<image-viewer
|
||||
v-if="showViewer"
|
||||
:z-index="zIndex"
|
||||
:initial-index="imageIndex"
|
||||
:url-list="previewSrcList"
|
||||
:hide-on-click-modal="hideOnClickModal"
|
||||
:teleported="teleported"
|
||||
@close="closeViewer"
|
||||
@switch="switchViewer"
|
||||
>
|
||||
<div v-if="$slots.viewer">
|
||||
<slot name="viewer" />
|
||||
</div>
|
||||
</image-viewer>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref, onMounted, watch, nextTick } from 'vue'
|
||||
import { isString } from '@vue/shared'
|
||||
import { useEventListener, useThrottleFn, isClient } from '@vueuse/core'
|
||||
import { useAttrs, useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import {
|
||||
useEventListener,
|
||||
useThrottleFn,
|
||||
isClient,
|
||||
isBoolean,
|
||||
} from '@vueuse/core'
|
||||
import {
|
||||
useAttrs,
|
||||
useLocale,
|
||||
useNamespace,
|
||||
useDeprecated,
|
||||
} from '@element-plus/hooks'
|
||||
import ImageViewer from '@element-plus/components/image-viewer'
|
||||
import { getScrollContainer, isInContainer } from '@element-plus/utils'
|
||||
import { imageEmits, imageProps } from './image'
|
||||
@ -61,6 +70,17 @@ export default defineComponent({
|
||||
emits: imageEmits,
|
||||
|
||||
setup(props, { emit, attrs: rawAttrs }) {
|
||||
useDeprecated(
|
||||
{
|
||||
scope: 'el-image',
|
||||
from: 'append-to-body',
|
||||
replacement: 'preview-teleported',
|
||||
version: '2.2.0',
|
||||
ref: 'https://element-plus.org/en-US/component/image.html#image-attributess',
|
||||
},
|
||||
computed(() => isBoolean(props.appendToBody))
|
||||
)
|
||||
|
||||
const { t } = useLocale()
|
||||
const ns = useNamespace('image')
|
||||
|
||||
@ -91,6 +111,10 @@ export default defineComponent({
|
||||
return Array.isArray(previewSrcList) && previewSrcList.length > 0
|
||||
})
|
||||
|
||||
const teleported = computed(() => {
|
||||
return props.appendToBody || props.previewTeleported
|
||||
})
|
||||
|
||||
const imageIndex = computed(() => {
|
||||
const { previewSrcList, initialIndex } = props
|
||||
let previewIndex = initialIndex
|
||||
@ -259,6 +283,7 @@ export default defineComponent({
|
||||
imageIndex,
|
||||
container,
|
||||
ns,
|
||||
teleported,
|
||||
|
||||
clickHandler,
|
||||
closeViewer,
|
||||
|
Loading…
Reference in New Issue
Block a user