翼度科技»论坛 编程开发 JavaScript 查看内容

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

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
一、上传到OSS或者服务器

缺点:
1.大文件上传时间过长
2.如果用户只是预览则会浪费服务端存储

二、使用FileReader对象转换File对象为base64
  1. <input type="file" id="videoInput">
  2. <video src="" alt="预览" id="video" controls="controls">
  3. <script>
  4.   const videoInput = document.getElementById('videoInput');
  5.   videoInput.addEventListener('change', e => {
  6.     previewByReader(e.target.files[0])
  7.   })

  8. function fileToBase64(file: File): Promise<{ url: any, filename: string }> {
  9.   const fileReader = new FileReader()
  10.   fileReader.readAsDataURL(file)
  11.   var filename = file.name;
  12.   return new Promise((resolve, reject) => {
  13.     fileReader.addEventListener("loadend", (e: ProgressEvent<FileReader>) => {
  14.       var url: any = e.target!.result;
  15.       resolve({ url, filename })
  16.     }, false);
  17.   })
  18. }
  19.   async function previewByReader (file) {
  20.    const {url} = await fileToBase64(file)
  21.    video.src = url
  22.   }
  23. </script>
复制代码
三、通过blob协议实现预览
  1. <input type="file" id="videoInput">
  2.   <video src="" alt="预览" id="video" controls="controls" width="400" height="200">
  3.   <script>
  4.     const videoInput = document.getElementById('videoInput');
  5.     videoInput.addEventListener('change', e => {
  6.       previewByURL(e.target.files[0])
  7.     })
  8.     function previewByURL (file) {
  9.       video.src = URL.createObjectURL(file)
  10.     }
  11.   </script>
复制代码
附:前端自定义封装图片预览组件(支持多张图片预览 缩放)

封装图片预览组件:
  1. <template>
  2.     <div ref="previewWrapper" class="image-preview">
  3.       <div class="overlay" v-if="showOverlay" @click="closePreview"></div>
  4.       <div class="preview-container" v-wheelScale>
  5.         <img :src="currentImageUrl" alt="Preview Image" @load="imageLoaded" ref="previewImage">
  6.       </div>
  7.       <div class="arrow arrow-left" @click="prevImage" :disabled="currentIndex === 0">&lt;</div>
  8.       <div class="arrow arrow-right" @click="nextImage" :disabled="currentIndex === images.length - 1">&gt;</div>
  9.     </div>
  10.   </template>
  11.   
  12.   <script>
  13.   export default {
  14.     props: {
  15.       images: {
  16.         type: Array,
  17.         required: true,
  18.       },
  19.     },
  20.     data() {
  21.       return {
  22.         showOverlay: false,
  23.         currentIndex: 0,
  24.         currentImageUrl: '',
  25.         scale: 1,
  26.         initialMouseX: 0,
  27.         initialScale: 1,
  28.         isDragging: false,
  29.       };
  30.     },
  31.     methods: {
  32.       openPreview() {
  33.         this.showOverlay = true;
  34.         this.currentImageUrl = this.images[this.currentIndex];
  35.         this.$refs.previewWrapper.style.display = 'flex';
  36.         setTimeout(() => {
  37.           this.$refs.previewWrapper.style.opacity = 1;
  38.         }, 10);
  39.       },
  40.       closePreview() {
  41.         this.showOverlay = false;
  42.         setTimeout(() => {
  43.           this.$refs.previewWrapper.style.opacity = 0;
  44.           setTimeout(() => {
  45.             this.$refs.previewWrapper.style.display = 'none';
  46.           }, 0);
  47.         }, 0);
  48.       },
  49.       nextImage() {
  50.         this.currentIndex = (this.currentIndex + 1) % this.images.length;
  51.         this.currentImageUrl = this.images[this.currentIndex];
  52.       },
  53.       prevImage() {
  54.         this.currentIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
  55.         this.currentImageUrl = this.images[this.currentIndex];
  56.       },
  57.       imageLoaded() {
  58.         // 可以在此处调整图片的居中或其它布局逻辑
  59.       },
  60.     },
  61.     mounted() {
  62.       // 初始化时隐藏预览层
  63.       this.$refs.previewWrapper.style.display = 'none';
  64.     },
  65.   };
  66.   </script>
  67.   
  68.   <style scoped>
  69.   .image-preview {
  70.     position: fixed;
  71.     top: 0;
  72.     left: 0;
  73.     right: 0;
  74.     bottom: 0;
  75.     z-index: 999;
  76.     display: none;
  77.     justify-content: center;
  78.     align-items: center;
  79.     opacity: 0;
  80.     transition: opacity 0.7s ease-in-out;
  81.   }
  82.   
  83.   .overlay {
  84.     position: absolute;
  85.     top: 0;
  86.     left: 0;
  87.     width: 100%;
  88.     height: 100%;
  89.     background-color: rgba(0, 0, 0, 0.8);
  90.     cursor: pointer;
  91.   }
  92.   
  93.   .preview-container {
  94.     position: relative;
  95.     text-align: center;
  96.     overflow: hidden;
  97.     max-width: 90%;
  98.     max-height: 90vh;
  99.   }
  100.   
  101.   .arrow {
  102.     width: 50px;
  103.     height: 50px;
  104.     position: absolute;
  105.     top: 50%;
  106.     transform: translateY(-50%);
  107.     background: rgba(255, 255, 255, 0.8);
  108.     padding: 10px;
  109.     border-radius: 50%;
  110.     cursor: pointer;
  111.     z-index: 1;
  112.     opacity: 0.5;
  113.     transition: opacity 0.3s;
  114.     border: none;
  115.     font-size: 20px;
  116.     line-height: 50px;
  117.   }
  118.   
  119.   .arrow:hover {
  120.     opacity: 1;
  121.   }
  122.   
  123.   .arrow-left {
  124.     left: 10px;
  125.   }
  126.   
  127.   .arrow-right {
  128.     right: 10px;
  129.   }
  130.   </style>
复制代码
图片放大缩小依靠自定义指令实现:
自定义指定代码:src/utils/scale.js
  1. export const initVWheelScale = (Vue) => {
  2.     Vue.directive("wheelScale", (el, binding) => {
  3.       const {
  4.         maxScale = 5,
  5.         minScale = 0.5,
  6.         initScale = 1,
  7.         cssVarName = "--scale",
  8.       } = binding.arg || {}
  9.       let currentScale = initScale || el.style.getPropertyValue(cssVarName) || 1
  10.       setWheelScale(binding, {
  11.         el,
  12.         cssVarName,
  13.         currentScale,
  14.         minScale,
  15.         maxScale,
  16.       })
  17.       if (el) {
  18.         el.onwheel = (e) => {
  19.           currentScale = el.style.getPropertyValue(cssVarName) || 1
  20.    
  21.           if (e.wheelDelta > 0) {
  22.             currentScale = currentScale * 1 + 0.1
  23.           } else {
  24.             currentScale = currentScale * 1 - 0.1
  25.           }
  26.           setWheelScale(binding, {
  27.             el,
  28.             cssVarName,
  29.             currentScale,
  30.             minScale,
  31.             maxScale,
  32.           })
  33.         }
  34.       }
  35.     })
  36.   }
  37.   // 设置 --scale 变量 缩放比例
  38.   const setVarScale = (el, cssVarName, currentScale, minScale, maxScale) => {
  39.     // 现在缩放范围
  40.     if (currentScale > maxScale) {
  41.       currentScale = maxScale
  42.     } else if (currentScale < minScale) {
  43.       currentScale = minScale
  44.     }
  45.     let cssText = el.style.cssText
  46.     let cssTextList = cssText.split(";")
  47.     let isExist = false
  48.     let isExistIndex = -1
  49.     for (let index = 0; index < cssTextList.length; index++) {
  50.       const element = cssTextList[index]
  51.       if (element.includes(cssVarName + ":")) {
  52.         isExist = true
  53.         isExistIndex = index
  54.         break
  55.       }
  56.     }
  57.     if (isExist) {
  58.       cssTextList[isExistIndex] = `--scale: ${currentScale}`
  59.     } else {
  60.       cssTextList.push(`--scale: ${currentScale}`)
  61.       //   el.setAttribute("style", `--scale: ${currentScale}`)
  62.     }
  63.     cssText = cssTextList.join(";")
  64.     el.style.cssText = cssText
  65.     return currentScale
  66.   }
  67.   // 设置 style.transform
  68.   const setTransformCss = (el, cssVarName) => {
  69.     let transformCssString = el.style.transform
  70.     let regScaleGlobal = /scale\(.*?[ )]*[)]+[ ]*/g //匹配 Scale属性 全局
  71.     if (regScaleGlobal.test(transformCssString)) {
  72.       transformCssString = transformCssString.replace(
  73.         regScaleGlobal,
  74.         ` scale(var(${cssVarName})) `
  75.       )
  76.     } else {
  77.       transformCssString += " " + `scale(var(${cssVarName}))`
  78.     }
  79.     el.style.transform = transformCssString
  80.   }
  81.   export const setWheelScale = (binding = {}, options) => {
  82.     const { el, cssVarName, currentScale, minScale, maxScale } = options
  83.     const nowScale = setVarScale(el, cssVarName, currentScale, minScale, maxScale)
  84.     setTransformCss(el, cssVarName)
  85.     // 缩放改变回调函数
  86.     const wheelScaleHandle = binding.value || null
  87.     if (wheelScaleHandle instanceof Function) {
  88.       wheelScaleHandle({
  89.         el,
  90.         cssVarName,
  91.         maxScale,
  92.         minScale,
  93.         currentScale: nowScale,
  94.         setScale: (_scale) => {
  95.           setWheelScale(binding, { ...options, currentScale: _scale })
  96.         },
  97.         binding,
  98.       })
  99.     }
  100.   }
  101.    
复制代码
main.js中全局注册自定义指令:
  1. import { initVWheelScale} from "@/utils/scale.js"
  2. initVWheelScale(Vue)
复制代码
在图片预览组件中使用:

组件的使用:
  1. <template>
  2.   <div>
  3.     <!-- ...其他内容 -->
  4.     <button @click="openPreview">预览图片</button>
  5.     <image-preview :images="imageList" ref="imagePreview"></image-preview>
  6.   </div>
  7. </template>

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

  10. export default {
  11.   components: {
  12.     ImagePreview,
  13.   },
  14.   data() {
  15.     return {
  16.       imageList: [
  17.         'https://img1.baidu.com/it/u=582697934,2565184993&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=539',
  18.         'https://img2.baidu.com/it/u=3519181745,2349627299&fm=253&fmt=auto&app=120&f=JPEG?w=750&h=500',
  19.         // 更多图片路径
  20.       ],
  21.     };
  22.   },
  23.   methods: {
  24.     openPreview() {
  25.       this.$refs.imagePreview.openPreview();
  26.     },
  27.   },
  28. };
  29. </script>
复制代码
效果:


总结

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

来源:https://www.jb51.net/javascript/323380w1s.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具