vue-cli项目中,运用element
- 图片上可以加文字/图片,加这些的可以使用鼠标拖拽改变大小或位置
- 支持保存图片
- 支持生成二维码
- 支持手机查看
安装三个插件:
安装生成二维码
npm install qrcodejs2 --save-dev
安装拖拽缩放组件
npm install vue-drag-resize --save-dev
安装html2canvas
npm install html2canvas --save-dev
html2canvas库的工作原理并不是真正的“截图”,而是读取网页上的目标DOM节点的信息来绘制canvas,所以它并不支持所有的css属性
代码:
<template>
<div class="generate_picture">
<el-row class="inner">
<el-main>
<div class="generate_imgBox">
<div class="generate_imgInner">
<div id="dragContainer">
<img :src="imgUrl">
<VueDragResize :aspectRatio="true" :parentLimitation="false" :w="142" :h="142" :minw="100" :minh="100" :x="458" :y="100" v-on:resizing="resize" v-show="showQrCode">
<div id="qrCode" class="qrcode" ref="qrCodeDiv" style="width: 102px;height: 102px;" :style="{ background: qrCodeBgColor }"></div>
</VueDragResize>
<VueDragResize :aspectRatio="true" :parentLimitation="false" :w="142" :h="142" :minw="100" :minh="100" :x="150" :y="100" v-show="showContactImg">
<img class="contact_img" :src="contactImg">
</VueDragResize>
<VueDragResize :aspectRatio="false" :isResizable="true" :parentLimitation="false" :w="100" :h="50" :minh="50" :x="50" :y="50" v-on:resizing="resizePone" v-show="showword">
<pre :style="{ color: wordColor, background: bgColor, fontSize: fontsize + 'px' }">{{ word }}</pre>
</VueDragResize>
</div>
</div>
<p>使用鼠标拖拽可改变二维码大小或位置</p>
</div>
<div class="generate_from">
<div class="generate_from_box">
<el-row class="generate_from_tab">
<ul>
<li v-for="(item,index) in tabs" :class="{ bor_active: tabNum == index}" @click="tabNum = index">{{ item }}</li>
</ul>
</el-row>
<el-row class="generate_from_bot" v-show="tabNum == 0">
<p>二维码颜色</p>
<el-color-picker v-model="qrCodeColor" @active-change="qrCodeColorActive"></el-color-picker>
<p>二维码背景</p>
<el-color-picker v-model="qrCodeBgColor" @active-change="qrCodeBgColorActive"></el-color-picker>
<p>二维码颜色</p>
<el-input
type="textarea"
:rows="2"
placeholder="请输入内容"
v-model="qrCodeLink"
@input="qrCodeLinkInput">
</el-input>
<el-checkbox v-model="showQrCode">二维码预览</el-checkbox>
</el-row>
<el-row class="generate_from_bot" v-show="tabNum == 1">
<p>图片</p>
<el-upload
class="upload-demo"
:action="upUrl"
:data="qn"
:on-success="handleSuccess"
:on-remove="handleRemove">
<el-button size="small" class="btn_bor_primary" round plain>上传图片</el-button>
</el-upload>
</el-row>
<el-row class="generate_from_bot generate_from_three" v-show="tabNum == 2">
<p>文字1</p>
<textarea
placeholder="请输入内容"
cols="30"
rows="10"
v-model="word"
:style="{ color: wordColor, background: bgColor }"></textarea>
<p>颜色</p>
<el-color-picker v-model="wordColor" @active-change="wordColorActive1"></el-color-picker>
<p>背景</p>
<el-color-picker v-model="bgColor" @active-change="bgColorActive1"></el-color-picker>
<el-checkbox v-model="showword" class="fix" style="margin-bottom: 24px;">文字预览</el-checkbox>
</el-row>
</div>
<div class="generate_from_btn">
<el-button class="btn_bor_primary" round plain @click="saveLocalClick">保存本地</el-button>
<el-popover
placement="top"
width="200"
trigger="click">
<div class="popover-content" style="height: 170px">
<div id="qrCode" class="qrcode" ref="imgQrCodeDiv" style="width: 170px;height: 170px;margin: 0 auto"></div>
</div>
<el-button slot="reference" class="btn_bor_primary" round plain @click="mobileViewClick">手机查看</el-button>
</el-popover>
<el-button class="btn_bor_primary" round plain @click="previewClick">预览</el-button>
</div>
</div>
</el-main>
</el-row>
</div>
</template>
<script>
import QRCode from 'qrcodejs2';
import VueDragResize from "vue-drag-resize";
import html2canvas from "html2canvas";
export default {
data() {
return {
imgUrl: require("../../assets/img/d8f9d72a6059252d715289453f9b033b5bb5b92e.jpg"),
tabs: ['二维码', '图片', '文字信息'],
tabNum: 0,
// 二维码
qrCodeColor: "#000",
qrCodeBgColor: "#fff",
qrCodeLink: "https://www.xxx.com/",
showQrCode: false,
canvasWidth: 92,
canvasHeight: 92,
// 上传初始化
qn:{
token: ""
},
upUrl: "",
// 上传成功后展示IMG
showContactImg: false,
contactImg: "",
// 文字
word:"",
wordColor: "red",
bgColor: "",
showword: false,
fontsize: 16,
}
},
methods: {
// 上传初始化获取上传接口地址和token
UpImgData () {
// ...
},
// 初始化
bindQRCode: function () {
new QRCode(this.$refs.qrCodeDiv, {
text: this.qrCodeLink,
width: 92,
height: 92,
colorDark: this.qrCodeColor, //二维码颜色
colorLight: "#ff000000", //二维码背景色
correctLevel: QRCode.CorrectLevel.L//容错率,L/M/H
})
},
// 缩放时事件
resize(newRect) {
document.getElementsByClassName('qrcode')[0].style.width = (newRect.width - 40) + "px";
document.getElementsByClassName('qrcode')[0].style.height = (newRect.height - 40) + "px";
document.getElementsByTagName('canvas')[0].style.width = (newRect.width - 50) + "px";
document.getElementsByTagName('canvas')[0].style.height = (newRect.height - 50) + "px";
this.canvasWidth = (newRect.width - 50);
this.canvasHeight = (newRect.height - 50);
},
resizePone(newRect) {
if(newRect.width < 100){
this.fontsize = 16
}else{
var v = (newRect.width - 100) / 5
this.fontsize = 16 + v
}
},
// 二维码链接输入事件
qrCodeLinkInput () {
this.$refs.qrCodeDiv.innerHTML = '';
new QRCode(this.$refs.qrCodeDiv, {
text: this.qrCodeLink,
width: this.canvasWidth,
height: this.canvasHeight,
colorDark: this.qrCodeColor, //二维码颜色
colorLight: "#ff000000", //二维码背景色
correctLevel: QRCode.CorrectLevel.L//容错率,L/M/H
})
},
// 二维码颜色面板中当前显示的颜色发生改变时触发
qrCodeColorActive (val) {
this.$refs.qrCodeDiv.innerHTML = '';
new QRCode(this.$refs.qrCodeDiv, {
text: this.qrCodeLink,
width: this.canvasWidth,
height: this.canvasHeight,
colorDark: val, //二维码颜色
colorLight: "#ff000000", //二维码背景色
correctLevel: QRCode.CorrectLevel.L//容错率,L/M/H
})
},
// 二维码背景面板中当前显示的颜色发生改变时触发
qrCodeBgColorActive (val) {
this.qrCodeBgColor = val
},
// 文字颜色面板中当前显示的颜色发生改变时触发
wordColorActive1 (val) {
this.wordColor = val
},
bgColorActive1 (val) {
this.bgColor = val
},
// 图片上传成功
handleSuccess(res, file) {
this.showContactImg = true;
this.contactImg = res.file_path
},
// 删除图片
handleRemove() {
this.showUploadBtn = true;
this.contactImg = ""
},
// 抽出公共图片
opts () {
var dragContainer = document.getElementById("dragContainer");
let opts = {
useCORS: true,
height: dragContainer.offsetHeight, // 解决当页面滚动之后生成图片出现白边问题
width: dragContainer.offsetWidth,
scrollX: -8,
dpi: 300, // 处理模糊问题
scale: 1
};
return opts
},
// 保存图片
saveLocalClick(){
var _this = this;
var dragContainer = document.getElementById("dragContainer");
html2canvas(dragContainer,_this.opts).then((canvas) => {
var url = canvas.toDataURL('image/png');
var a = document.createElement("a");
a.href = url;
a.download = "素材";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
},
// 手机查看
mobileViewClick () {
var _this = this;
this.$refs.imgQrCodeDiv.innerHTML = '';
var dragContainer = document.getElementById("dragContainer");
html2canvas(dragContainer,_this.opts).then((canvas) => {
canvas.toBlob(function (blobObj) {
var formData = new FormData();
// _this.qn.token和_this.upUrl是上传初始化接口返回的
formData.append("token", _this.qn.token);
formData.append("file", blobObj);
// 把图片上加文字/二维码生成的新图片传给上传提交的接口,然后获取接口返回的新图片链接,把这个链接生成二维码,才能给手机扫描查看
_this.$http.post(_this.upUrl, formData).then(res => {
new QRCode(_this.$refs.imgQrCodeDiv, {
text: res.data.file_path,
width: 170,
height: 170,
colorDark: "#000", //二维码颜色
colorLight: "#fff", //二维码背景色
correctLevel: QRCode.CorrectLevel.L//容错率,L/M/H
})
}).catch(err => {
})
})
});
},
// 预览
previewClick() {
var _this = this;
var dragContainer = document.getElementById("dragContainer");
html2canvas(dragContainer,_this.opts).then(function(canvas) {
canvas.toBlob(function (blobObj) {
console.log(blobObj)
window.open(URL.createObjectURL(blobObj))
})
});
},
},
mounted () {
this.$nextTick(function () {
this.bindQRCode();
});
},
components:{
VueDragResize
}
}
</script>
<style scoped>
.generate_picture .inner{
width: 1200px;
margin: 25px auto;
}
.generate_picture .el-main {
width: 100%;
min-height: 980px;
background-color: #fff;
border-radius: 10px;
float: right;
}
.generate_imgBox{
border-radius: 4px;
-webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .04);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .04);
border: solid 1px #eeeeee;
height: 600px;
width: 794px;
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
padding: 9px;
/* text-align: center; */
position: relative;
float: left;
}
.generate_imgInner{
position: absolute;
border-radius: 4px;
left: 20px;
top: 20px;
border: solid 1px #eeeeee;
height: 560px;
width: 770px;
overflow: auto;
}
.generate_imgInner::-webkit-scrollbar{
width: 8px;
height: 8px;
}
.generate_imgInner::-webkit-scrollbar{
width: 5px !important;
margin-right: 8px;
}
.generate_imgInner::-webkit-scrollbar-thumb,
.generate_imgInner::-webkit-scrollbar-thumb:horizontal{
border-radius: 2.5px;
background: #a5a9b3;
}
.generate_imgInner::-webkit-scrollbar-track,
.generate_imgInner::-webkit-scrollbar-track-piece{
border-radius: 2.5px;
}
.generate_imgInner::-webkit-scrollbar-track,
.generate_imgInner::-webkit-scrollbar-track-piece{
border-radius: 2.5px;
}
#dragContainer{
width: auto;
display: inline-grid;
position: relative;
}
#dragContainer .qrcode{
padding: 10px;
margin: 10px;
background-color: #fff;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
position: relative;
}
#dragContainer img.contact_img{
width: 100%;
}
#dragContainer pre{
padding: 0 6px;
font-size: 16px;
text-align: center;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
word-break: break-all;
white-space: pre-wrap;
}
.generate_from{
width: 330px;
height: auto;
overflow: hidden;
float: right;
}
.generate_from_box{
border-radius: 4px;
border: solid 1px #eeeeee;
min-height: 342px;
margin: 0;
height: auto;
padding: 0;
-webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .04);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .04);
}
.generate_from_tab{
margin: 0 0 16px;
}
.generate_from_tab ul li{
width: 33.3%;
height: 42px;
float: left;
line-height: 42px;
text-align: center;
font-size: 14px;
border-bottom: 1px #eee solid;
cursor: pointer;
}
.generate_from_tab ul li.bor_active{
border-bottom-width: 2px;
}
.generate_from_bot{
padding: 0px 20px 10px 20px;
}
.generate_from_bot p{
color: #414755;
opacity: 0.6;
font-size: 14px;
padding-bottom: 8px;
}
.generate_from_bot .el-color-picker{
margin-bottom: 10px;
}
.generate_from_bot .el-color-picker__trigger{
width: 290px;
border: 0;
padding: 0;
border: 1px #eee solid;
border-radius: 5px;
}
.generate_from_bot .el-color-picker__icon{
display: none;
}
.generate_from_bot .el-color-picker__color{
border: 0;
border-radius: 5px;
}
.generate_from_bot textarea{
margin-bottom: 10px;
width: 100%;
min-height: 50px;;
height: 100px;
padding: 5px 15px;
display: block;
resize: vertical;
box-sizing: border-box;
font-size: inherit;
color: #606266;
background-color: #FFF;
border: 1px solid #DCDFE6;
border-radius: 4px;
transition: border-color .2s cubic-bezier(.645,.045,.355,1);
outline:none;
}
.generate_from_bot .el-checkbox{
float: right;
margin-right: 0;
}
.generate_from_three{
max-height: 600px;
overflow: auto;
}
.generate_from_three::-webkit-scrollbar {
width: 5px !important;
margin-right: 8px;
}
.generate_from_three::-webkit-scrollbar-thumb,
.generate_from_three::-webkit-scrollbar-thumb:horizontal {
border-radius: 2.5px;
background: #a5a9b3;
}
.generate_from_three::-webkit-scrollbar-track,
.generate_from_three::-webkit-scrollbar-track-piece {
border-radius: 2.5px;
}
.generate_from_three::-webkit-scrollbar-track,
.generate_from_three::-webkit-scrollbar-track-piece {
border-radius: 2.5px;
}
.generate_from_bot .divider-dashed{
background: none;
border: dashed #e8e8e8;
border-width: 1px 0 0;
display: block;
clear: both;
width: 100%;
min-width: 100%;
height: 1px;
margin: 24px 0;
}
.generate_from_btn{
margin-top: 20px;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.generate_from_btn .el-button{
width: 33%;
height: 28px;
line-height: 0.3;
}
.generate_from_btn span{
margin: 0 6px;
}
.generate_from_btn span .el-button{
width: 100%;
}
.generate_imgBox p{
color: rgb(65, 71, 85);
opacity: 0.6;
position: absolute;
bottom: -34px;
}
</style>