前端实现图片或视频预览的三种方法总结

 更新时间:2024年06月27日 10:49:41   作者:chens123123  
在JavaScript中实现前端图片上传即时预览功能是一项常见的需求,特别是在网页交互设计中,这篇文章主要给大家介绍了关于前端实现图片或视频预览的三种方法,需要的朋友可以参考下

一、上传到OSS或者服务器

缺点:

1.大文件上传时间过长

2.如果用户只是预览则会浪费服务端存储

二、使用FileReader对象转换File对象为base64

<input type="file" id="videoInput">
<video src="" alt="预览" id="video" controls="controls">
<script>
  const videoInput = document.getElementById('videoInput');
  videoInput.addEventListener('change', e => {
    previewByReader(e.target.files[0])
  })

function fileToBase64(file: File): Promise<{ url: any, filename: string }> {
  const fileReader = new FileReader()
  fileReader.readAsDataURL(file)
  var filename = file.name;
  return new Promise((resolve, reject) => {
    fileReader.addEventListener("loadend", (e: ProgressEvent<FileReader>) => {
      var url: any = e.target!.result;
      resolve({ url, filename })
    }, false);
  })
}
  async function previewByReader (file) {
   const {url} = await fileToBase64(file)
   video.src = url
  }
</script>

三、通过blob协议实现预览

<input type="file" id="videoInput">
  <video src="" alt="预览" id="video" controls="controls" width="400" height="200">
  <script>
    const videoInput = document.getElementById('videoInput');
    videoInput.addEventListener('change', e => {
      previewByURL(e.target.files[0])
    })
    function previewByURL (file) {
      video.src = URL.createObjectURL(file)
    }
  </script>

附:前端自定义封装图片预览组件(支持多张图片预览 缩放)

封装图片预览组件:

<template>
    <div ref="previewWrapper" class="image-preview">
      <div class="overlay" v-if="showOverlay" @click="closePreview"></div>
      <div class="preview-container" v-wheelScale>
        <img :src="currentImageUrl" alt="Preview Image" @load="imageLoaded" ref="previewImage">
      </div>
      <div class="arrow arrow-left" @click="prevImage" :disabled="currentIndex === 0">&lt;</div>
      <div class="arrow arrow-right" @click="nextImage" :disabled="currentIndex === images.length - 1">&gt;</div>
    </div>
  </template>
  
  <script>
  export default {
    props: {
      images: {
        type: Array,
        required: true,
      },
    },
    data() {
      return {
        showOverlay: false,
        currentIndex: 0,
        currentImageUrl: '',
        scale: 1,
        initialMouseX: 0,
        initialScale: 1,
        isDragging: false,
      };
    },
    methods: {
      openPreview() {
        this.showOverlay = true;
        this.currentImageUrl = this.images[this.currentIndex];
        this.$refs.previewWrapper.style.display = 'flex';
        setTimeout(() => {
          this.$refs.previewWrapper.style.opacity = 1;
        }, 10);
      },
      closePreview() {
        this.showOverlay = false;
        setTimeout(() => {
          this.$refs.previewWrapper.style.opacity = 0;
          setTimeout(() => {
            this.$refs.previewWrapper.style.display = 'none';
          }, 0);
        }, 0);
      },
      nextImage() {
        this.currentIndex = (this.currentIndex + 1) % this.images.length;
        this.currentImageUrl = this.images[this.currentIndex];
      },
      prevImage() {
        this.currentIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
        this.currentImageUrl = this.images[this.currentIndex];
      },
      imageLoaded() {
        // 可以在此处调整图片的居中或其它布局逻辑
      },
    },
    mounted() {
      // 初始化时隐藏预览层
      this.$refs.previewWrapper.style.display = 'none';
    },
  };
  </script>
  
  <style scoped>
  .image-preview {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 999;
    display: none;
    justify-content: center;
    align-items: center;
    opacity: 0;
    transition: opacity 0.7s ease-in-out;
  }
  
  .overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.8);
    cursor: pointer;
  }
  
  .preview-container {
    position: relative;
    text-align: center;
    overflow: hidden;
    max-width: 90%;
    max-height: 90vh;
  }
  
  .arrow {
    width: 50px;
    height: 50px;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(255, 255, 255, 0.8);
    padding: 10px;
    border-radius: 50%;
    cursor: pointer;
    z-index: 1;
    opacity: 0.5;
    transition: opacity 0.3s;
    border: none;
    font-size: 20px;
    line-height: 50px;
  }
  
  .arrow:hover {
    opacity: 1;
  }
  
  .arrow-left {
    left: 10px;
  }
  
  .arrow-right {
    right: 10px;
  }
  </style>

图片放大缩小依靠自定义指令实现:

自定义指定代码:src/utils/scale.js

export const initVWheelScale = (Vue) => {
    Vue.directive("wheelScale", (el, binding) => {
      const {
        maxScale = 5,
        minScale = 0.5,
        initScale = 1,
        cssVarName = "--scale",
      } = binding.arg || {}
      let currentScale = initScale || el.style.getPropertyValue(cssVarName) || 1
      setWheelScale(binding, {
        el,
        cssVarName,
        currentScale,
        minScale,
        maxScale,
      })
      if (el) {
        el.onwheel = (e) => {
          currentScale = el.style.getPropertyValue(cssVarName) || 1
   
          if (e.wheelDelta > 0) {
            currentScale = currentScale * 1 + 0.1
          } else {
            currentScale = currentScale * 1 - 0.1
          }
          setWheelScale(binding, {
            el,
            cssVarName,
            currentScale,
            minScale,
            maxScale,
          })
        }
      }
    })
  }
  // 设置 --scale 变量 缩放比例
  const setVarScale = (el, cssVarName, currentScale, minScale, maxScale) => {
    // 现在缩放范围
    if (currentScale > maxScale) {
      currentScale = maxScale
    } else if (currentScale < minScale) {
      currentScale = minScale
    }
    let cssText = el.style.cssText
    let cssTextList = cssText.split(";")
    let isExist = false
    let isExistIndex = -1
    for (let index = 0; index < cssTextList.length; index++) {
      const element = cssTextList[index]
      if (element.includes(cssVarName + ":")) {
        isExist = true
        isExistIndex = index
        break
      }
    }
    if (isExist) {
      cssTextList[isExistIndex] = `--scale: ${currentScale}`
    } else {
      cssTextList.push(`--scale: ${currentScale}`)
      //   el.setAttribute("style", `--scale: ${currentScale}`)
    }
    cssText = cssTextList.join(";")
    el.style.cssText = cssText
    return currentScale
  }
  // 设置 style.transform
  const setTransformCss = (el, cssVarName) => {
    let transformCssString = el.style.transform
    let regScaleGlobal = /scale\(.*?[ )]*[)]+[ ]*/g //匹配 Scale属性 全局
    if (regScaleGlobal.test(transformCssString)) {
      transformCssString = transformCssString.replace(
        regScaleGlobal,
        ` scale(var(${cssVarName})) `
      )
    } else {
      transformCssString += " " + `scale(var(${cssVarName}))`
    }
    el.style.transform = transformCssString
  }
  export const setWheelScale = (binding = {}, options) => {
    const { el, cssVarName, currentScale, minScale, maxScale } = options
    const nowScale = setVarScale(el, cssVarName, currentScale, minScale, maxScale)
    setTransformCss(el, cssVarName)
    // 缩放改变回调函数
    const wheelScaleHandle = binding.value || null
    if (wheelScaleHandle instanceof Function) {
      wheelScaleHandle({
        el,
        cssVarName,
        maxScale,
        minScale,
        currentScale: nowScale,
        setScale: (_scale) => {
          setWheelScale(binding, { ...options, currentScale: _scale })
        },
        binding,
      })
    }
  }
   

main.js中全局注册自定义指令:

import { initVWheelScale} from "@/utils/scale.js"
initVWheelScale(Vue)

在图片预览组件中使用:

组件的使用:

<template>
  <div>
    <!-- ...其他内容 -->
    <button @click="openPreview">预览图片</button>
    <image-preview :images="imageList" ref="imagePreview"></image-preview>
  </div>
</template>

<script>
import ImagePreview from '@/components/ImagePreview.vue'; // 引入你的图片预览组件

export default {
  components: {
    ImagePreview,
  },
  data() {
    return {
      imageList: [
        'https://img1.baidu.com/it/u=582697934,2565184993&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=539',
        'https://img2.baidu.com/it/u=3519181745,2349627299&fm=253&fmt=auto&app=120&f=JPEG?w=750&h=500',
        // 更多图片路径
      ],
    };
  },
  methods: {
    openPreview() {
      this.$refs.imagePreview.openPreview();
    },
  },
};
</script>

效果:

总结 

到此这篇关于前端实现图片或视频预览的三种方法的文章就介绍到这了,更多相关前端图片或视频预览内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论