首页 > 其他分享 >vue 用 input 和 canvas 标签实现前端背景图片的移动 重绘 上传

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

时间:2022-10-21 20:16:23浏览次数:131  
标签:canvas vue img imgList imgScale var input 图片

前言:

    闲得无聊写的,嫌麻烦的直接出门左转搜索 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, //在画布上放置图像的 x 、y坐标位置。
                imgList[i].width*_this.imgScale, imgList[i].height*_this.imgScale  //要使用的图像的宽度、高度
            );
            }
        },

 

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

标签:canvas,vue,img,imgList,imgScale,var,input,图片
From: https://www.cnblogs.com/LiuSan/p/16814632.html

相关文章

  • vue引用MarkDown(mavonEditor)编辑器,文档
    mavonEditorInstallmavon-editor(安装)npminstallmavon-editor--save如何引入:全局引用://全局注册importVuefrom'vue'importmavonEditorf......
  • [HTML]改变input框中placeholder颜色的方法
    textarea同理,把以下的input改成textarea即可。input::-webkit-input-placeholder{/*WebKitbrowsers适配谷歌*/color:#BDCADA;}input:-moz-placeholder{/......
  • vue题库
    1、用index作为key可能会引发的问题1、若对数据进行:逆序添加/逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新,界面效果虽然没有问题,但是数据过多的话,会效率过低;......
  • vue2.0中svg图片的引用
    1、基础工作都是引用了svg-sprite-loader这个插件  npmisvg-sprite-loader--save2、写一个Svglcon的组件(components/Svglcon),在components目录下新建一个SvgIcon文......
  • HTML标签_表单标签_表单项input1和表单项input2
    *表单项标签: *input:可以通过type属性值,改变元素展示的样式 *type属性: *text:文本输入框,默认值 *placeholder:指定......
  • 为什么vue3要选用proxy,好处是什么?
    提问Object.defineProperty()和proxy的区别?为什么vue3要选用proxy,好处是什么?proxyProxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋......
  • 588_HTML标签_表单标签_概述and589 _HTML标签_表单标签_表单项input1
    HTML标签_表单标签_概述表单标签表单: form:用于定于表单的。可以定一个范围,范围代表采集用户数据的范围       属性:           action:指定提......
  • vue官方文档解读
    参考:https://cn.vuejs.org/guide/introduction.htmlhttps://blog.csdn.net/weixin_42371679/article/details/112408800vue是一个js库,它基于标准html、css和js,并提供了......
  • vue-code-diff 实现版本对比,带内容覆盖(仅组件,待完善内容解析)
    <template><divclass="version-diff-content"><divclass="version-diff-top"><div><el-selectv-model="versionDiffSelected.selectOne.versi......
  • Chrome 浏览器安装Vue插件方法
    谷歌浏览器扩展程序 首先去github下载vue.zip文件插件 下载地址:https://github.com/vuejs/vue-devtools不要去下载默认分支的 下载后解压验证npm是否安装成......