基于vue实现的拖拽,缩放,前背景不动,后背景移动,绘制成分享海报

发布时间:2021-04-27
技术:用到了图片上传,滕叙的组件库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,有需要的可以参考一下

本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码