基于vue实现的拖拽,缩放,前背景不动,后背景移动,绘制成分享海报
技术:用到了图片上传,滕叙的组件库alloyfinger,html2canvas绘制海报
概述
客户需求,需要一个用户自己上传图片,功能不大,思路得清楚,前背景不动,后背景(用户上传的图片)可以移动,缩放,最后根据用户缩放图片的把整个页面绘制成海报,上传服务器,用户可以保存。页面不多,没有引入UI库,有用到的可以参考看一下
详细
客户需求,需要一个用户自己上传图片,功能不大,思路得清楚,前背景不动,后背景(用户上传的图片)可以移动,缩放,最后根据用户缩放图片的把整个页面绘制成海报,上传服务器,用户可以保存。页面不多,没有引入UI库,有用到的可以参考看一下。
next文件有线上的代码,把
depro
字短设置false和true,可以切换本地测试,还是线上用户自己上传图片
html2canvas针对线上的图片,本地测试存在跨域问题
全demo一共四个页面
演示图(引导页):
演示图(上传,拖拽,裁剪,生成海报)
部分代码:
index
<template> <div style="width: 100%;height: 100%;background: #eee" ref="imageWrapper"> <div class="xj" v-if="show"> <div class="upload"> <input type="file" accept="image/gif,image/jpeg,image/jpg,image/png" @change="changeImage($event)"> <img src="../../assets/xj.png" alt=""> </div> </div> <div class="name" v-if="!show"> <span style="color: #ec550b">{{option.name}}</span> <span style="color: #ec550b;padding-top: 7px">恭喜您成为第{{num}}位代言人</span> </div> <div class="btn" v-if="show"> <span @click="btn()">生 成 海 报</span> </div> <div> <div class="bg"></div> <div class="box" > <!-- rotate(' + angle + 'deg)'--> <img :src="img" class="pic" id="pic" :style="{'transform': 'translate('+ posX + 'px,' + posY + 'px) translateZ(0px) scale(' + dis + ') '}" /> </div> </div> </div> </template> <script> import axios from 'axios' import AlloyFinger from "../../utils/alloyfinger"; import html2canvas from "html2canvas" var url = "http://hb.8sdy.cn" export default { name: "next", data() { return { depro:true, show:true, option: {}, posX: 0, posY: 0, dis: 1, angle: 0, img: "", images: "", imgUrl:"", num:"" } }, created() { this.option = this.$route.query; }, mounted() { this.getData(); }, methods: { toImage(id) { html2canvas(this.$refs.imageWrapper).then(canvas => { let dataURL = canvas.toDataURL("image/png"); this.imgUrl = dataURL; if (this.imgUrl !== "") { sessionStorage.setItem('img',dataURL); this.$router.push({path: "/poster", query: { id: id, }}) // this.dialogTableVisible = true; } }); }, getData() { let that = this; let element = document.getElementById("pic"); this.af = new AlloyFinger(element, { // rotate: function (evt) { // console.log("实现旋转"); // that.angle += evt.angle; // }, pinch: function (evt) { console.log("实现缩放"); that.dis = evt.zoom; }, pressMove: function (evt) { console.log("实现移动"); that.posX += evt.deltaX; that.posY += evt.deltaY; }, tap: function (evt) { console.log("单击"); //点按触发 }, doubleTap: function (e) { console.log("双击"); //双击屏幕触发 }, longTap: function (e) { console.log("长按"); //长按屏幕750ms触发 }, swipe: function (e) { //e.direction代表滑动的方向 console.log("swipe" + e.direction); }, }); }, changeImage(e) { //假数据 if(this.depro){ this.img = require("../../assets/demo.jpg") return } //正式的 let that = this let file = e.target.files[0] let formdata = new FormData(); let config = { headers: { 'Content-Type': 'multipart/form-data' } }; formdata.append('file', file); axios.post(url + '/index/index/upload', formdata, config ).then(function (response) { if (response.data.code == 1) { that.img = url + response.data.data that.images = response.data.data } else { alert(response.data.msg) } }).catch(function (error) { console.log(error); }); }, btn() { if(this.depro){ this.show = false this.num = 10 setTimeout(()=>{ this.toImage(10); this.show = true },200) return } this.show = false let that = this if (that.images == "") { this.show = true alert("请上传图片") return } axios.post(url + "/index/index/add", { name: that.option.name, worknum: that.option.num, mechanism: that.option.jigou, images: that.images, }) .then(function (response) { console.log(response) that.num = response.data.data.id setTimeout(()=>{ that.toImage(response.data.data.id); that.show = true },200) }) .catch(function (error) { this.show = true console.log(error); }); } } } </script> <style scoped> .bg { background: url("../../assets/bg3.png") no-repeat; background-size: 100% 100%; width: 100%; height: 100%; position: absolute; pointer-events: none; z-index: 9; } .box { width: 100vw; height: 100vh; overflow: hidden; text-align: center; } .pic { width: 30rem; margin: 2rem auto; } .name{ display: flex; flex-flow: column; position: absolute; bottom: 140px; /*left: 15px;*/ z-index: 999; width: 100%; align-items: center; } .name span{ font-size: 17px; } .xj { display: flex; align-items: center; justify-content: center; width: 100%; position: absolute; top: 160px; z-index: 999; } .xj img { width: 50px; height: 50px; } .upload { width: 50px; height: 50px; position: relative; } .upload input { position: absolute; width: 100%; height: 100%; opacity: 0; } .btn { position: fixed; bottom: 10px; display: flex; align-items: center; justify-content: center; width: 100%; z-index: 99; } .btn span { width: 90%; background: #FFFFFF; height: 45px; line-height: 45px; border-radius: 25px; color: #000; text-align: center; font-size: 18px; font-weight: bold; } </style>
form页面
<template> <div class="bg"> <div class="lists"> <div class="list"> <span>工号</span> <input type="text" v-model="num" placeholder="请输入工号"> </div> <div class="list"> <span>姓名</span> <input type="text" v-model="name" placeholder="请输入姓名"> </div> <div class="list"> <span>机构</span> <input type="text" v-model="jigou" placeholder="请输入机构"> </div> <div class="btn"> <span @click="goPage('/next')"> 下 一 步 </span> </div> </div> <div class="toast" v-show="toastShow"> {{toastText}} </div> </div> </template> <script> export default { name: "form", data() { return { toastShow: false, toastText: '', num:"", name:"", jigou:"" } }, methods: { goPage(url) { if (this.num == ""){ this.toast('请输入工号') return } if (this.name == ""){ this.toast('请输入姓名') return } if (this.jigou == ""){ this.toast('请输入机构') return } let that = this this.$router.push({path: url,query: { num: that.num, name:that.name, jigou:that.jigou }}) }, toast (e) { let self = this self.toastText = e self.toastShow = true setTimeout(function(){ self.toastShow = false }, 1500) } } } </script> <style scoped> .bg { background: url("../../assets/bg4.jpeg") no-repeat; background-size: cover; width: 100%; height: 100%; } .lists { width: 100%; display: flex; flex-flow: column; align-items: center; justify-content: center; height: 100%; } .list { display: flex; width: 100%; margin-bottom: 30px; align-items: center; } .list span { text-align: right; padding-right: 5%; color: #FFFFFF; font-size: 15px; padding-left: 8%; } .list input { width: 70%; background: transparent; outline: none; border: 1px solid #EEE; padding: 10px 10px; box-sizing: border-box; color: #FFFFFF; font-size: 15px; border-radius: 4px; } input::-webkit-input-placeholder { color: #FFFFFF; } .btn { display: flex; align-items: center; justify-content: center; width: 100%; } .btn span { width: 85%; background: #FFFFFF; height: 40px; line-height: 40px; border-radius: 20px; color: #000; text-align: center; font-size: 16px; font-weight: bold; } .toast{ position: fixed; z-index: 2000; left: 50%; top:45%; transition:all .5s; -webkit-transform: translateX(-50%) translateY(-50%); -moz-transform: translateX(-50%) translateY(-50%); -ms-transform: translateX(-50%) translateY(-50%); -o-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%); text-align: center; border-radius: 5px; color:#FFF; background: rgba(17, 17, 17, 0.7); height: 45px; line-height: 45px; padding: 0 15px; max-width: 150px; } </style>
程序可以理解成一个活动demo,有需要的可以参考一下
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码