基于vue实现图片预览功能。实现图片旋转,下载,放大。缩小功能
基本使用:
父组件
<template>
<el-button @click="open">预览</el-button>
<CompleteCav :url="url3" v-model="show"/>
</template>
<script>
import CompleteCav from './completeCav'
export default {
components:{CompleteCav },
data(){
return{
url: "//宽图片
url2:" "//长图图片
}
},
methods:{
open() {
this.show=true
}
}
}
</script>
接下来是预览核心逻辑:
<template>
<transition name="fade">
<div v-if="value" class="box">
<div class="cont">
<div class="img-ele-wrap" :style="imgStyle">
<img id="thumb" :src="urlValue" alt="" />
</div>
</div>
<div class="actions">
<span class="zoomIn" @click="operate('zoomIn')">+</span>
<span class="zoomOut" @click="operate('zoomOut')">-</span>
<span class="ratateLeft" @click="operate('ratateLeft')"></span>
<span class="ratateRight" @click="operate('ratateRight')"></span>
<span class="download" @click="operate('download')">↓</span>
<span class="close" @click="operate('close')">×</span>
</div>
<div class="mask"></div>
</div>
</transition>
</template>
<script>
export default {
name:"completeCav",
props:{
url:{
type:String,
default:""
},
value:{
type:Boolean,
default:false
}
},
data(){
return{
urlValue:"",
transformStyle:{
ImgHeight:0,
ImgWidth:0,
show:false,
deg:0,
scale:1
}
}
},
computed:{
imgStyle(){
const style={
width:this.transformStyle.ImgWidth+'px',
height:this.transformStyle.ImgHeight+'px',
transform:`rotate(${this.transformStyle.deg}deg) scale(${this.transformStyle.scale})`,
}
return style
}
},
mounted(){
this.drawCanv();
window.addEventListener("resize",this.throttle(this.drawCanv,200));
},
beforeDestroy(){
window.removeEventListener("resize",this.drawCanv);
},
watch:{
value(n){
console.log("n----:",n)
if(!n){
this.reset()
}
}
},
methods:{
reset(){
this.transformStyle.deg=0
},
close(){
console.log("close111'")
this.$emit("input",false)
},
operate(type){
let zoomRate=0.2
switch(type){
case "close":
this.$emit("input",false)
break;
case "download":
let a=document.createElement("a")
a.href=this.url
a.target="_blank"
a.click()
break;
case "ratateLeft":
this.transformStyle.deg-=90;
break;
case "ratateRight":
this.transformStyle.deg+=90;
break;
case "zoomIn":
if(this.transformStyle.scale>=2.4){
return
}
this.transformStyle.scale = parseFloat((this.transformStyle.scale + zoomRate).toFixed(3));
console.log("this.transformStyle.scale:",this.transformStyle.scale)
break;
case "zoomOut":
if(this.transformStyle.scale>0.2){
this.transformStyle.scale = parseFloat((this.transformStyle.scale - zoomRate).toFixed(3));
}
break;
default:
break;
}
},
ratate(type){
type=='rotateLeft'?this.transformStyle.deg-=90:this.deg+=90
},
download(){
let a=document.createElement("a")
a.href=this.url
a.target="_blank"
a.click()
},
drawCanv(){
let _this=this
let canvas=document.createElement("canvas");
let ctx=canvas.getContext("2d");
let w=document.documentElement.clientWidth-300||document.body.clientWidth-300;
let h=document.documentElement.clientHeight
let ImgHeight=0
let ImgWidth=0
canvas.width= w;
canvas.height= h;
let imgObj=new Image()
imgObj.src=_this.url;
imgObj.setAttribute("crossOrigin",'Anonymous')
imgObj.onload=function(e){
//获取原始宽高
let naturalWidth = (e.path)[0].naturalWidth
let naturalHeight = (e.path)[0].naturalHeight
// 图片宽高比
let imageRadio =(naturalWidth / naturalHeight);
if (imageRadio <= 1) { //长图
// 图片的高度
console.log("长途")
ImgHeight =naturalHeight>canvas.height?canvas.height:naturalHeight
// 根据原始宽高,等比例得到图片宽度
ImgWidth = ImgHeight * imageRadio;
canvas.width=ImgWidth
ctx.drawImage(imgObj,0,0,ImgWidth,ImgHeight)
var base64 = canvas.toDataURL("image/png"); //"image/png" 这里注意一下
_this.urlValue=base64
_this.transformStyle.ImgHeight=ImgHeight;
_this.transformStyle.ImgWidth=ImgWidth;
}else{
console.log("宽图")
// 图片的高度
ImgWidth =naturalWidth>canvas.width?canvas.width:naturalWidth
// 根据原始宽高,等比例得到图片宽度
ImgHeight= ImgWidth / imageRadio;
// 重新赋值canvas宽高
ctx.drawImage(imgObj,0,0,ImgWidth,ImgHeight)
var base64 = canvas.toDataURL("image/png"); //"image/png" 这里注意一下
_this.urlValue=base64
_this.transformStyle.ImgHeight=ImgHeight
_this.transformStyle.ImgWidth=ImgWidth
}
}
},
throttle(fn, threshhold) {
var timeout
var start = new Date;
var threshhold = threshhold || 160
return function () {
var context = this, args = arguments, curr = new Date() - 0
clearTimeout(timeout)//总是干掉事件回调
if(curr - start >= threshhold){
console.log("now", curr, curr - start)//注意这里相减的结果,都差不多是160左右
fn.apply(context, args) //只执行一部分方法,这些方法是在某个时间段内执行一次
start = curr
}else{
//让方法在脱离事件后也能执行一次
timeout = setTimeout(function(){
fn.apply(context, args)
}, threshhold);
}
}
}
}
}
</script>
<style scoped>
.box{
width: 100%;
height: 100vh;
position: fixed;
top:0;
left:0;
z-index:100;
}
.mask{
width: 100%;
height: 100vh;
position: fixed;
top:0;
left:0;
z-index:1;
background: rgba(0,0,0,0.5);
}
.cont{
position: fixed;
z-index: 101;
width: 100%;
height: 100vh;
left:0;
top:0;
display: flex;
justify-content: center;
}
.img-ele-wrap{
transition:all 0.2s;
}
.img-ele-wrap img{
object-fit: cover;
}
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
.actions{
position:fixed;
z-index: 101;
color:#fff;
font-size: 16px;
right:20px;
top:20px
}
.ratateLeft,.download,.close,.zoomIn,.zoomOut{
font-size: 16px;
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
border:1px solid #fff;
margin-left:10px
}
</style>