• element-plus中图片预览插件源码改动


    最近有一个需求,要求对图片进行预览的同时,可以对图片进行放大、缩小、旋转、查看原图(放大或者缩小之后)等功能点,说白了这就是一个图片编辑器。既然提了这个需求,就要想办法去实现它。
    先说一下项目背景:pc端项目,项目构成是vue3.2+vite+pinia+element-plus

    既然要实现图片预览,就要从ui组件库element-plus入手,看了一下官方文档中的组件image图片这一部分,发现是有图片预览功能的,而且可以放大、缩小、旋转、查看原图等,完美地符合了需求。所以就准备用这个插件来实现了。

    虽然image图片组件满足了需求,但是它有个前提条件就是点击图片本身时才会触发预览功能。

    代码如下:

    <template>
      <div class="demo-image__preview">
        <el-image
          style="width: 100px; height: 100px"
          :src="url"
          :zoom-rate="1.2"
          :max-scale="7"
          :min-scale="0.2"
          :preview-src-list="srcList"
          :initial-index="4"
          fit="cover"
        />
      </div>
    </template>
    
    <script lang="ts" setup>
    const url =
      'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'
    const srcList = [
      'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
      'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
      'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
      'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
      'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
      'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
      'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg',
    ]
    </script>
    
    <style scoped>
    .demo-image__error .image-slot {
      font-size: 30px;
    }
    .demo-image__error .image-slot .el-icon {
      font-size: 30px;
    }
    .demo-image__error .el-image {
      width: 100%;
      height: 200px;
    }
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    其中的preview-src-list是开启预览功能的,还有一些配套的参数设置:zoom-rate等,

    但是我们项目的需求是点击按钮进入一个预览页面,直接展示预览图片,并且左边有文件名列表,点击列表中的文件名,展示这个文件名下上传的所有图片,然后进行轮播预览,同时在大图预览下面有对应的缩略图轮播,大图预览轮播和缩略图轮播形成联动效果,大图轮播,下面缩略图也跟着轮播。缩略图轮播也是一样的。

    所以需要根据需求点来进行对应的改造
    1、首先要实现点击按钮来进行图片预览的效果(利用element-plus中的el-image-viewer这个组件);
    2、其次实现缩略图的轮播展示(使用swiper插件实现);
    3、实现图片预览轮播和缩略图轮播的联动效果;

    我们一步一步来实现:
    1.1、因为el-image这个组件只能在点击图片的时候才能展示图片轮播,所以只能改其他的方案,经过探索之后,发现了el-image-viewer这个组件,这个组件就是名副其实的预览组件,非常切合开发需求。

    <el-image-viewer
      ref="allImageViewerList"
      v-if="isShow"
      :url-list="imageList"
      @switch="($event) => onSwitch($event, 'imageView')"
      :hideOnClickModal="true"
      @imageClick="imageClick"
    />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    直接传入图片列表url-list,然后展示对应的轮播预览图效果,这样就实现了点击按钮展示预览轮播图的效果了。
    虽然效果展示出来了,但是有些方面还是不能满足我们的需求,比如,预览图在一个固定的区域内,但是因为有鼠标滚轮事件,可以滚动的时候实现预览图的放大缩小,所以导致在左边的列表区域上下滚动的时候,预览图也跟着放大和缩小。所以要解决的问题,就是禁止掉滚轮事件。怎么禁止呢,api文档中没有提到。需要翻看源码。
    我先看了一下node_modules中安装的element-plus中的源码,
    发现在onMounted中触发了registerEventListener方法,

    vue.onMounted(() => {
          var _a, _b;
          registerEventListener();
          (_b = (_a = wrapper.value) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
        });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    registerEventListener方法代码如下,在registerEventListener中发现了core.useEventListener(document, “wheel”, mousewheelHandler),滚轮监听事件,还有就是键盘监听事件;

    const scopeEventListener = vue.effectScope();
    function registerEventListener() {
          const keydownHandler = lodashUnified.throttle((e) => {
            switch (e.code) {
              case aria.EVENT_CODE.esc:
                props.closeOnPressEscape && hide();
                break;
              case aria.EVENT_CODE.space:
                toggleMode();
                break;
              case aria.EVENT_CODE.left:
                prev();
                break;
              case aria.EVENT_CODE.up:
                handleActions("zoomIn");
                break;
              case aria.EVENT_CODE.right:
                next();
                break;
              case aria.EVENT_CODE.down:
                handleActions("zoomOut");
                break;
            }
          });
          const mousewheelHandler = lodashUnified.throttle((e) => {
            const delta = e.deltaY || e.deltaX;
            handleActions(delta < 0 ? "zoomIn" : "zoomOut", {
              zoomRate: props.zoomRate,
              enableTransition: false
            });
          });
          scopeEventListener.run(() => {
            core.useEventListener(document, "keydown", keydownHandler);
            core.useEventListener(document, "wheel", mousewheelHandler);
          });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    怎么取消这些监听事件呢?(可以先查一下effectScope的用法)
    发现了unregisterEventListener这样一个方法

    function unregisterEventListener() {
       scopeEventListener.stop();
    }
    
    • 1
    • 2
    • 3

    通过unregisterEventListener就可以接触对wheel、keydown的监听。

    但是unregisterEventListener这个事件我们组件外面拿不到,因为这个组件没有暴露这个unregisterEventListener方法。
    所以需要修改源码,把这个事件暴露出来;
    修改的代码如下:

    expose({
      setActiveItem,
      unregisterEventListener
    });
    
    • 1
    • 2
    • 3
    • 4

    这样在引用el-image-viewer组件的页面中就可以使用unregisterEventListener这个方法,去掉滚轮和键盘的监听事件

    1.2 修改源码解决了这个问题之后,又有一个新问题,就是要实现点击图片实现跳转或者下载的效果。(这里为什么说是跳转或者下载呢,因为如果文件是pdf、excel,预览图展示的是一个固定的图,点击就会跳转到对应的文件预览页面,如果是zip等文件,点击固定的图片就会直接下载)。
    因为el-image-viewer组件渲染的图片列表,没有点击事件,所以就又要修改源码,增加图片点击事件;
    el-image-viewer组件原来是有close、switch事件,增加一个和它们并列的imageClick就可以了,然后把imageClick事件emit出去就可以了。

    function imgClick(url) {
       if (["jpg", "jpeg", "png", "gif", "bmp", "svg", "tif", "pcx", "tga", "exif", "fpx", "psd", "cdr", "pcd", "dxf", "ufo", "eps", "ai", "raw", "wmv", "webp", "avif", "apng", "heic", "heif"].includes(url == null ? void 0 : url.fileName.substring((url == null ? void 0 : url.fileName.lastIndexOf(".")) + 1).toLowerCase())) {
            return;
          }
       emit("imageClick", url);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在源码中加入这个参数,首先数据类型为图片格式的,点击没有反应,非图片格式的才有返回值,返回之后会进行下载或者预览(引用el-image-viewer组件的页面中做的处理)

    1.3
    好了,改完源码,满足需求了。我说说改源码的流程以及源码打包后怎么放入项目中。
    我用的element-plus版本是目前最新的,2.4.1
    步骤如下

    1. 下载element-plus源码

    2. 在下载的源码项目中的packages中的component中修改对应的组件源码;

    3. 修改完成之后,npm run build进行打包,打包之后的文件是dist;

    4. 拿着dist下面的element-plus文件夹,替换自己项目中node_modules的element-plus(注意,源码项目中打包的dist下面的element-plus可能缺少global.d.ts、package.json、README.md等这几个文件,所以别忘了先拷贝进去(把原来的element-plus中的这几个文件拷贝到现在的element-plus中),然后再进行替换原来的element-plus);

    5. 做完这些之后,启动项目发现没有变化,这个时候我们要清除一下缓存,怎么清除缓存呢?首先把node_modules中的.vite文件删除掉,然后在package.json中的scripts中的dev上加上–force,如下:
      ”scripts": {
      “dev”: “vite --force”,
      “build”: “vite build”,
      “preview”: “vite preview”
      },

    6. 做完这些之后,重新启动项目,发现修改源码的地方已经生效了。

    7. 注意点:现在element-plus的源码项目已经使用pnpm了,所以clone源码后安装依赖的时候,注意一下;

    做完这一切就完成了使用element-plus中的el-image-viewer组件实现图片预览的效果(轮播、放大、缩小、旋转、查看原图等)

    下面的缩略图轮播我会再写一篇文章,希望本篇文章对大家有所帮助。

  • 相关阅读:
    Android一个简单带动画的展开收起功能
    基于GA遗传优化的PID控制器控制参数整定matlab仿真
    电脑黑屏按什么键恢复?只需要3个键就可以解决黑屏
    C#中的delegate和event,及他们的区别
    51单片机基础(C语言):定时器时钟
    七、函数-存储过程-触发器
    linux查看各个目录占用磁盘的大小&清理nohup.out日志
    R语言深度学习-4-识别异常数据(无监督学习/自动编码器)
    upload-labs靶场第17关设计PHP函数解析
    三维度:专业、展现与连接
  • 原文地址:https://blog.csdn.net/xiaolinlife/article/details/134435052