基于vue+canvas实现图片预览功能

基于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>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值