🚀
头像

六扇有伊人


博学多才的六扇老师

vue 用 input 和 canvas 标签实现前端背景图片的移动 重绘 上传

2022-10-18 11:47:54 253 💗 0 @六扇有伊人

前言:

    闲得无聊写的,嫌麻烦的直接出门左转搜索 vue cropper.js模块 直接用就行

正文:

    首先我们要知道input 是自带file 方法的,直接可以选这文件上传就行,但为了美观都是給上边覆盖了一个button ,我是懒得写了直接用的方法调用

    然后用ref选这就行,id也行但是用的是vue ref更省事

    下边附上div代码:

      <template>
            <div class="personal_img">
                <p>
                    <input type="file" @change="changeFile" ref="fileRef" v-show="false">
                    <el-button @click="personal()" plain v-if="ifimg">
                        上传图片
                        <i class="el-icon-camera-solid"></i>
                    </el-button>
                </p>                
                <div v-if="ifimg">
                    <img :src="list.imag" alt="">  
                </div>
                <div style="height: 200px;width: 100%;" v-if="ifimgs">
                    <canvas ref="myCanvasRef" :width="canvasWidth" :height="canvasHeight" style="height: 200px;opacity: 0.4;-o-object-fit: cover;object-fit: cover;width: 100%;"></canvas>
                    <div style="float: right;">
                        <el-button plain @click="updataimg()"> 上传 </el-button>
                        <el-button plain @click="cancel()"> 取消 </el-button>
                    </div>
                </div>
            </div>
      </template>

  因为用的是vue所以拿到图片之后 之后 v-if 销毁之前的img然后用canvas显示图片就行,这里再插一句 canvas 标签 里的 width和height 是画板的宽高,而style里的才是元素的宽高

   再写js之前,再data声明几个变量之后重绘要用:

    data(){
        return{
            canvasWidth: 1000, // 画布大小
            canvasHeight: 200,
            extraImgList: [  // 图片的大小和图片的x y坐标
                {
                    x: 0,
                    y: 0,
                    width: 2400,
                    height: 1000
                },     
            ],
            myCanvas: null,
            ctx: null,
            imgObject: [], // 全局的img存储
            imgX: 0, // 图片在画布中渲染的起点x y坐标
            imgY: 0,
            imgScale: 0.9, // 图片的缩放大小
            file:null, // file对象
            headportraitfile:null,
            ifimg:true, // 显示与隐藏
            ifimgs:false,
            imgpath:null,
            // 用户数据
            list:{
                name:'六扇有伊人',
                personality:'学到老活到老',
                imag:require('@/../public/123456.jpg'),
                portrait:require('@/../public/portrait.jpg'),
            },
        }
    },

看着很乱,所以出门左拐才是王道,不要闲着没事瞎搞,我看着都乱,自己慢慢看吧,看不懂我也不讲

下面附上 methods 里的 方法 :

    methods: {
        //   拉起方法
        changeFile(e){
            console.log(e.target.files);
            this.file = e.target.files[0];
            this.testCanvas(); // 开启绘图
        },
        //   上传图片到服务器
        dataURLtoFile(dataURI, type) {
            let binary = atob(dataURI.split(',')[1]);
            let array = [];
            for (let i = 0; i < binary.length; i++) {
                array.push(binary.charCodeAt(i));
            }
            return new Blob([new Uint8Array(array)], {type: type});
        },
        canvasToBase64(canvas){
            // 'image/png'可以换成'image/jpeg'
            return canvas.toDataURL('image/jpeg');
        },
        updataimg(){
            let formdata = new FormData();
            var l = this.canvasToBase64(this.ctx.canvas)
            let blob = this.dataURLtoFile(l, 'image/jpeg');
            let fileOfBlob = new File([blob], new Date() + '.jpg',{type:'image/jpeg'});
            console.log(fileOfBlob)
            formdata.append('file',fileOfBlob);
            this.$axios.post('http://192.168.1.72:7001/api/upload?type=article', formdata).then(res => {
                console.log(res.data.url);
                this.list.imag = res.data.url;
                this.cancel()
            }).catch(err => {
                console.log(err)
            })
        },
        // 取消
        cancel(){
            this.ifimg = true
            this.ifimgs = false
        },
        //  点击触发上传
        personal(){
            this.$refs.fileRef.dispatchEvent(new MouseEvent('click'))
            this.ifimg = false
            this.ifimgs = true
        },
        //   绘图
        testCanvas(){
            this.myCanvas = this.$refs.myCanvasRef;
            this.ctx = this.myCanvas.getContext('2d'); // 创建一个2d渲染的画布
            this.loadImg(); // 渲染图片
            this.canvasEventsInit(); // 鼠标移动方法
        },
        loadImg() {
            var _this = this;
            let extraImgList = _this.extraImgList; // 图片的路径 里面有 图片的 xy 宽高
            var imageList = []; 
            //加载背景图片
            var isBgLoaded = false;
            var img = new Image(); // 创建一个Image对象,相当于给浏览器缓存了一张图片
            var bgImg = extraImgList[0]; 
            var reader = new FileReader(); // 创建一个 FileReader 对象编译图片
            reader.readAsDataURL(this.file);//base64
            reader.onload = function () {
                this.imgpath = reader.result
                img.src = this.imgpath; // 图片路径
                img.onload = function () {
                imageList.push({img: img, x: bgImg.x, y: bgImg.y, width: bgImg.width, height: bgImg.height});  
                    _this.imgObject = imageList;
                    _this.drawImage(imageList);
                }      

            }
        },        drawImage(imgList) {
            var _this = this;
            _this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
            for(let i = 0; i < imgList.length; i++) {
            _this.ctx.drawImage(
                imgList[i].img, //规定要使用的图片
                _this.imgX + imgList[i].x * _this.imgScale, _this.imgY+ imgList[i].y * _this.imgScale, //在画布上放置图像的 x 、y坐标位置。
                imgList[i].width*_this.imgScale, imgList[i].height*_this.imgScale  //要使用的图像的宽度、高度
            );
            }
        },
        canvasEventsInit() {
            var _this = this;
            var canvas = _this.myCanvas;
        
            canvas.onmousedown = function (event) {
            var imgx = _this.imgX;
            var imgy = _this.imgY;
            var pos = {x:event.clientX, y:event.clientY};  //坐标转换,将窗口坐标转换成canvas的坐标
            canvas.onmousemove = function (evt) {  //移动
                canvas.style.cursor = 'move';

                var x = (evt.clientX - pos.x) * 2 + imgx;
                var y = (evt.clientY - pos.y) * 2 + imgy;
                
                _this.imgX  = x;
                _this.imgY  = y;
                
                _this.drawImage(_this.imgObject);  //重新绘制图片
            };
            canvas.onmouseup = function () {
                canvas.onmousemove = null;
                canvas.onmouseup = null;
                canvas.style.cursor = 'default';
            };
            };
    
            canvas.onmousewheel = canvas.onwheel = function (event) {    //滚轮放大缩小
            var wheelDelta = event.wheelDelta ? event.wheelDelta : (event.deltalY * (-40));  //获取当前鼠标的滚动情况
            if (wheelDelta > 0) {
                _this.imgScale *= 1.1;
            } else {
                if(_this.imgScale > 0.9) {
                    _this.imgScale *= 0.9;
                }
            }
            _this.drawImage(_this.imgObject);   //重新绘制图片
            event.preventDefault  && event.preventDefault();
            return false;
            };
        },
    }

详细过程:

    首先用按钮拉起input的change方法 target.files[0] 选这文件

        changeFile(e){
            this.file = e.target.files[0];
            this.testCanvas(); // 开启绘图
        },

    然后开启绘图  用ref指定canvas标签,然后创建一个2d渲染的画布 赋值給 this.ctx 同时渲染图片

        testCanvas(){
            this.myCanvas = this.$refs.myCanvasRef;
            this.ctx = this.myCanvas.getContext('2d'); // 创建一个2d渲染的画布
            this.loadImg(); // 渲染图片
            this.canvasEventsInit(); // 鼠标移动方法
        },

    渲染图片 

        loadImg() {
            var _this = this;
            let extraImgList = _this.extraImgList; // 图片的路径 里面有 图片的 xy 宽高
            var imageList = []; 
            //加载背景图片
            var isBgLoaded = false;
            var img = new Image(); // 创建一个Image对象,相当于给浏览器缓存了一张图片
            var bgImg = extraImgList[0]; 
            var reader = new FileReader(); // 创建一个 FileReader 对象编译图片
            reader.readAsDataURL(this.file);//base64
            reader.onload = function () {
                this.imgpath = reader.result
                img.src = this.imgpath; // 图片路径
                img.onload = function () {
                imageList.push({img: img, x: bgImg.x, y: bgImg.y, width: bgImg.width, height: bgImg.height});  
                    _this.imgObject = imageList;
                    _this.drawImage(imageList);
                }      
            }
        },
        drawImage(imgList) {
            var _this = this;
            _this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
            for(let i = 0; i < imgList.length; i++) {
            _this.ctx.drawImage(
                imgList[i].img, //规定要使用的图片
                _this.imgX + imgList[i].x * _this.imgScale, _this.imgY+ imgList[i].y * _this.imgScale, //在画布上放置图像的 xy坐标位置。
                imgList[i].width*_this.imgScale, imgList[i].height*_this.imgScale  //要使用的图像的宽度、高度
            );
            }
        },


懒得写了,更多信息请关注抖音号: 六扇有伊人 

    目录导航