如何在Element-UI的el-image-viewer组件预览图片上添加文字?

如何在通过Element-ul的 el-image-viewer组件实现的预览的图片上添加文字,例如下面这种效果
image.png
image.png

尝试在组件上添加div但是没有效果

<el-image-viewer
    v-if="showPreview"
    :urlList="previewImages"
    :on-close="closeViewer"
    :zIndex=9999

<div></div>
</el-image-viewer>

补充问题:
页面上通过this.$openPreview 传递图片数据
image.png
image.png

改写:
页面上
image.png
preview.js
image.png
mypreview.vue
image.png
MyImage.vue
image.png
MyImageViewer.vue
image.png

当前页面:
image.png
1730879971962.jpg
1730879971966.jpg

阅读 985
avatarAI BotBETA
在Element-UI的`el-image-viewer`组件上直接添加文字是不可能的,因为这个组件是专门用于图片预览的,并且它内部有严格的结构和样式管理,不允许外部直接插入DOM元素(如`<div>`)来改变其内容。

要在预览的图片上添加文字,你可以考虑以下几种方法:

1. **预处理图片**:
   在将图片传递给`el-image-viewer`之前,使用图像处理库(如Pillow、Sharp等,取决于你的后端技术栈)在图片上添加文字,然后保存并传递处理后的图片。

2. **使用CSS覆盖**:
   这种方法比较复杂且可能不稳定,因为它依赖于CSS的绝对定位和对`el-image-viewer`内部结构的了解。你可以尝试通过CSS将文字定位到图片上,但这可能会因为组件内部结构的更新而失效。

3. **自定义组件**:
   如果Element-UI的`el-image-viewer`不能满足需求,你可以考虑自己实现一个图片预览组件,这个组件可以支持在图片上添加文字的功能。

4. **使用Canvas**:
   在前端使用Canvas来绘制图片和文字,然后将Canvas转换为图片进行预览。这种方法需要一定的Canvas编程知识。

5. **SVG覆盖**:
   如果图片是SVG格式的,你可以直接在SVG文件中添加文字元素。对于非SVG图片,你可以将图片转换为SVG格式(如果可能的话),或者将SVG作为覆盖层放置在图片上方。

通常,预处理图片或使用自定义组件是实现这一需求的最可靠方法。如果你选择预处理图片,请确保你的后端能够处理这种图像操作,并且你有足够的权限和存储空间来保存这些修改后的图片。
2 个回答

<el-image> 组件没有对应的插槽和 props,只能你自己改写组件,叠加在上层。

一个简单的例子:

<template>
  <div id="app">
    <MyImagePreview
      v-for="img in srcList"
      :key="img.url"
      :src="img.url"
      :preview-src-list="srcList"
      style="width: 100px; height: 100px"
    />
  </div>
</template>

<script>
import MyImagePreview from '@/components/MyImage'

export default {
  name: 'App',
  components: {
    MyImagePreview
  },
  data() {
    return {
      srcList: [
        {
          label: '图片1',
          url: 'https://fuss10.elemecdn.com/8/27/f01c15bb73e1ef3793e64e6b7bbccjpeg.jpeg',
        }, {
          label: '图片2',
          url: 'https://fuss10.elemecdn.com/1/8e/aeffeb4de74e2fde4bd74fc7b4486jpeg.jpeg'
        }
      ]
    }
  }
}
</script>

自定义 <el-image> 组件

<script>
import { Image } from 'element-ui';
import MyImageViewer from "@/components/MyImageViewer";

export default {
  name: "MyImagePreview",
  extends: Image,
  components: { ImageViewer: MyImageViewer },
}
</script>
<script>
import imageViewer from 'element-ui/packages/image/src/image-viewer.vue';

export default {
  name: "MyImageViewer",
  extends: imageViewer,
}
</script>

<!-- 复制的 ele-ui 的模板代码 -->
<template>
  <transition name="viewer-fade">
    <div tabindex="-1" ref="el-image-viewer__wrapper" class="el-image-viewer__wrapper" :style="{ 'z-index': viewerZIndex }">
      <div class="el-image-viewer__mask" @click.self="handleMaskClick"></div>
      <!-- CLOSE -->
      <span class="el-image-viewer__btn el-image-viewer__close" @click="hide">
        <i class="el-icon-close"></i>
      </span>
      <!-- ARROW -->
      <template v-if="!isSingle">
        <span
            class="el-image-viewer__btn el-image-viewer__prev"
            :class="{ 'is-disabled': !infinite && isFirst }"
            @click="prev">
          <i class="el-icon-arrow-left"/>
        </span>
        <span
            class="el-image-viewer__btn el-image-viewer__next"
            :class="{ 'is-disabled': !infinite && isLast }"
            @click="next">
          <i class="el-icon-arrow-right"/>
        </span>
      </template>
      <!-- ACTIONS -->
      <div class="el-image-viewer__btn el-image-viewer__actions">
        <div class="el-image-viewer__actions__inner">
          <i class="el-icon-zoom-out" @click="handleActions('zoomOut')"></i>
          <i class="el-icon-zoom-in" @click="handleActions('zoomIn')"></i>
          <i class="el-image-viewer__actions__divider"></i>
          <i :class="mode.icon" @click="toggleMode"></i>
          <i class="el-image-viewer__actions__divider"></i>
          <i class="el-icon-refresh-left" @click="handleActions('anticlocelise')"></i>
          <i class="el-icon-refresh-right" @click="handleActions('clocelise')"></i>
        </div>
      </div>
      <!-- CANVAS -->
      <div class="el-image-viewer__canvas">
        <!-- 👇 只改写了这部分的业务代码 👇 -->
        <template v-for="(img, i) in urlList">
          <div v-if="i === index" :key="img.url">
            <div class="el-image-viewer__title">{{ img.label }}</div>
            <img
              ref="img"
              class="el-image-viewer__img"
              :src="img.url"
              :style="imgStyle"
              @load="handleImgLoad"
              @error="handleImgError"
              @mousedown="handleMouseDown">
          </div>
        </template>
      </div>
    </div>
  </transition>
</template>

<style>
.el-image-viewer__title {
  position: fixed;
  top: 30px;
  left: 0;
  width: 100%;
  font-size: 20px;
  font-weight: bold;
  color: black;
  text-align: center;
  text-shadow: 1px 1px 0px white;
  z-index: 100;
}
</style>

代码可以再优化一下,但是作为示意Demo已经足够了。

图片.png

可以使用 pnpm patch 修改 https://github.com/ElemeFE/element/blob/dev/packages/image/src/image-viewer.vue#L37 组件,让它支持 slot 。

<div class="el-image-viewer__canvas">
  <img
    v-for="(url, i) in urlList"
    v-if="i === index"
    ref="img"
    class="el-image-viewer__img"
    :key="url"
    :src="currentImg"
    :style="imgStyle"
    @load="handleImgLoad"
    @error="handleImgError"
    @mousedown="handleMouseDown" />
    <slot></slot>
</div>
推荐问题
宣传栏