自定义指令 vue中 怎么把element中的 el-image组件封装成可预览大图的指令?

el-image已封装成了组件,但是觉得指令更简单些,但在做的过程中有问题了

把element中的el-image组件封装成可预览大图的指令,

index.html中用 <img v-preview-image/>调用,

index.js中写全局指令

previewImage.vue中用<el-image></el-image>布局

点击index.html中的图片,直接显示大图预览

index.html

<template>
<a v-for="(pic, index) in comment.pic_info" :key="index" class="imgWrap">
  <img alt="图片" v-img-preview="{src: pic.url, imgList:imgList}" :src="pic.url" class="xnw_weibo_img wei"/>
</a>
</template>
<script>
export default {
        data() {
            return {
                imgList: [
                    'https://fuss10.elemecdn.com/8/27/f01c15bb73e1ef3793e64e6b7bbccjpeg.jpeg',
                    'https://fuss10.elemecdn.com/1/8e/aeffeb4de74e2fde4bd74fc7b4486jpeg.jpeg'
                ]
            }
        }
</script>

index.js

import imgPreview from './imgPreview'
Vue.directive('img-preview', {
    bind(el, binding, vnode) {
        const {src, imgList} = (binding.value && binding.value) || []
        el.addEventListener('click', () => {
            const $preview = new (Vue.extend(imgPreview))({
                propsData: {
                    el: el,
                    src: src,
                    imgList: imgList,
                    initialIndex: 0
                }
            }).$mount()

            document.body.appendChild($preview.$el)
        })
    }
})

imgPreview.vue

<template>
    <div class="preview-container">
        <el-image
            style="width: 100px; height: 100px"
            :src="src"
            @click="showImgPreview"
            :preview-src-list="imgList">
        </el-image>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                // imgurl: '',
                // imgList: []
            }
        },
        props: {
            src: {
                type: String,
                required: true
            },
            imgList: {
                type: Array,
                default: () => []
            },
            el: {
                default: {}
            }
        },
        created() {
            // this.$emit('close') // 首次创建实例时触发关闭事件,避免显示预览图
        },
        mounted() {
            // this.imgurl = this.src
            this.$el.addEventListener('click', this.close) // 监听预览图点击事件,用于关闭预览图
        },
        beforeDestroy() {
            this.$el.removeEventListener('click', this.close) // 移除预览图点击事件监听器
        },
        methods: {
            showImgPreview(){
                this.$nextTick(() => {
                    console.log('dom')
                })
            },
            close() {
                // this.$emit('close') // 关闭预览图
            }
        },
        watch: {
            src(newSrc) {
                // this.$emit('close') // 当预览图的src属性变化时触发关闭事件,避免显示预览图
            }
        }
    }
</script>

<style scoped>
    .preview-container {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 9999;
        background-color: rgba(0, 0, 0, 0.8);
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .preview-image {
        max-width: 90%;
        max-height: 90%;
    }
</style>

这样的效果是点击图片时,直接弹出了图1
图一
image.png
点中间的小图出现图2
图二
image.png

但是我要的效果是点击时出现如下效果

image.png

寻大神看下我代码怎么改比较好,也可以另起炉灶,只要实现效果就行

阅读 2.5k
2 个回答
新手上路,请多包涵
<a v-for="(pic, index) in comment.pic_info" :key="index" class="imgWrap">
  <img alt="图片" v-img-preview="{src: pic.url, imgList:imgList}" :src="pic.url" class="xnw_weibo_img wei"/>
</a>

怎么就比

<a v-for="(pic, index) in comment.pic_info" :key="index" class="imgWrap">
  <el-image alt="图片" :src="pic.url" class="xnw_weibo_img wei"/>
</a>

简单了?

所以直接用 el-imagepreview-src-list 属性不就好了吗?只不过需要你自己封装一下 el-iamge 组件,不一定需要指令,可以通过只传入一个 src 属性这种的方式,我大概简单实现一个:

<template>
  <div class="preview-container">
    <el-image
      v-for="(_, index) in imgLimit"
      :key="srcList[index]+index"
      class="preview-img"
      fit="cover"
      :src="srcList[index]"
      :style="`width:${imgWidth};height:${imgHeight};`"
      :preview-src-list="srcList"
    >
      <div slot="error" class="image-slot">
        <i class="el-icon-picture-outline" />
      </div>
    </el-image>
  </div>
</template>

<script>
export default {
  name: 'ImagePreview',
  props: {
    src: {
      type: [String, Array],
      default: () => ''
    },
    width: {
      type: [Number, String],
      default: 100
    },
    height: {
      type: [Number, String],
      default: 100
    },
    max: {
      type: Number,
      default: 0
    }
  },
  computed: {
    // 处理传入src属性
    srcList() {
      const { src = '' } = this
      // 如果传入的是数组直接返回
      if (Array.isArray(src)) return src
      // 如果不是数组则转换为数组,同时过滤掉空链接
      const tempList = src.split(',').filter(Boolean)
      return tempList
    },
    // 展示图片数量限制
    imgLimit() {
      // 如果图片限制为0,则展示全部图片
      if (this.max === 0) return this.srcList.length
      // 如果图片数量大于限制则展示限制数量,否则展示图片数量
      return this.srcList.length > this.max ? this.max : this.srcList.length
    },
    // 转换图片高度
    imgWidth() {
      return String(this.width).includes('px') ? this.width : `${this.width}px`
    },
    // 转换图片高度
    imgHeight() {
      return String(this.height).includes('px') ? this.height : `${this.height}px`
    }
  }
}
</script>

这样在你使用的时候就可以直接 <img-preview :src="imgList" /> 来展示就好了,默认展示全部,如果有限制则传入限制最大数量的 max。通过指令的方式没必要,属于杀鸡用牛刀了。

本文参与了SegmentFault 思否面试闯关挑战赛,欢迎正在阅读的你也加入。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题