前端實(shí)現(xiàn)圖片或視頻預(yù)覽的三種方法總結(jié)
一、上傳到OSS或者服務(wù)器
缺點(diǎn):
1.大文件上傳時(shí)間過(guò)長(zhǎng)
2.如果用戶(hù)只是預(yù)覽則會(huì)浪費(fèi)服務(wù)端存儲(chǔ)
二、使用FileReader對(duì)象轉(zhuǎn)換File對(duì)象為base64
<input type="file" id="videoInput"> <video src="" alt="預(yù)覽" 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>
三、通過(guò)blob協(xié)議實(shí)現(xiàn)預(yù)覽
<input type="file" id="videoInput"> <video src="" alt="預(yù)覽" 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>
附:前端自定義封裝圖片預(yù)覽組件(支持多張圖片預(yù)覽 縮放)
封裝圖片預(yù)覽組件:
<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"><</div> <div class="arrow arrow-right" @click="nextImage" :disabled="currentIndex === images.length - 1">></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() { // 可以在此處調(diào)整圖片的居中或其它布局邏輯 }, }, mounted() { // 初始化時(shí)隱藏預(yù)覽層 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>
圖片放大縮小依靠自定義指令實(shí)現(xiàn):
自定義指定代碼: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, }) } } }) } // 設(shè)置 --scale 變量 縮放比例 const setVarScale = (el, cssVarName, currentScale, minScale, maxScale) => { // 現(xiàn)在縮放范圍 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 } // 設(shè)置 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) // 縮放改變回調(diào)函數(shù) 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中全局注冊(cè)自定義指令:
import { initVWheelScale} from "@/utils/scale.js" initVWheelScale(Vue)
在圖片預(yù)覽組件中使用:
組件的使用:
<template> <div> <!-- ...其他內(nèi)容 --> <button @click="openPreview">預(yù)覽圖片</button> <image-preview :images="imageList" ref="imagePreview"></image-preview> </div> </template> <script> import ImagePreview from '@/components/ImagePreview.vue'; // 引入你的圖片預(yù)覽組件 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>
效果:
總結(jié)
到此這篇關(guān)于前端實(shí)現(xiàn)圖片或視頻預(yù)覽的三種方法的文章就介紹到這了,更多相關(guān)前端圖片或視頻預(yù)覽內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript中Iterator迭代器接口和循環(huán)
這篇文章主要介紹了JavaScript中Iterator迭代器接口和循環(huán),迭代器是數(shù)據(jù)結(jié)構(gòu)遍歷的一種機(jī)制迭代器主要是提供for...of使用,更多相關(guān)內(nèi)推需要的小伙伴可以參考下面文章內(nèi)容2022-06-06JavaScript高級(jí)程序設(shè)計(jì) 讀書(shū)筆記之九 本地對(duì)象Array
本地對(duì)象Array,數(shù)組等操作函數(shù)2012-02-02ArrayBuffer Uint8Array Blob與文本字符相互轉(zhuǎn)換示例
這篇文章主要為大家介紹了ArrayBuffer Uint8Array Blob與文本字符相互轉(zhuǎn)換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06利用JavaScript實(shí)現(xiàn)網(wǎng)頁(yè)版2048小游戲
這篇文章主要介紹了如何利用HTML+CSS+JS編寫(xiě)一個(gè)網(wǎng)頁(yè)版的2048小游戲,代碼簡(jiǎn)單易懂對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11javascript中延遲加載的7種方法實(shí)現(xiàn)
在web前端開(kāi)發(fā)中,性能優(yōu)化一直是一個(gè)非常重要的話題,JavaScript中延遲加載的方式有很多種,本文就來(lái)介紹了javascript中延遲加載的7種方法實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2025-01-01教學(xué)演示-UBB,剪貼板,textRange及其他
教學(xué)演示-UBB,剪貼板,textRange及其他...2006-07-07Javascript/Jquery——簡(jiǎn)單定時(shí)器的多種實(shí)現(xiàn)方法
本文為大家詳細(xì)介紹下使用Javascript/Jquery實(shí)現(xiàn)簡(jiǎn)單的定時(shí)器,方法有多種,大家可以根據(jù)自己的喜好自由選擇,希望對(duì)大家有所幫助2013-07-07